Skip to main content

async_tiff/metadata/
reader.rs

1use std::collections::HashMap;
2use std::io::Read;
3
4use bytes::Bytes;
5
6use crate::error::{AsyncTiffError, AsyncTiffResult, TiffError, TiffFormatError};
7use crate::metadata::fetch::MetadataCursor;
8use crate::metadata::MetadataFetch;
9use crate::reader::Endianness;
10use crate::tag_value::TagValue;
11use crate::tags::{Tag, Type};
12use crate::{ImageFileDirectory, TIFF};
13
14/// Entry point to reading TIFF metadata.
15///
16/// This is a stateful reader because we don't know how many IFDs will be encountered.
17///
18/// ```notest
19/// // fetch implements MetadataFetch
20/// let mut metadata_reader = TiffMetadataReader::try_open(&fetch).await?;
21/// let ifds = metadata_reader.read_all_ifds(&fetch).await?;
22/// ```
23pub struct TiffMetadataReader {
24    endianness: Endianness,
25    bigtiff: bool,
26    next_ifd_offset: Option<u64>,
27}
28
29impl TiffMetadataReader {
30    /// Open a new TIFF file, validating the magic bytes, reading the endianness, and checking for
31    /// the bigtiff flag.
32    ///
33    /// This does not read any IFD metadata.
34    pub async fn try_open<F: MetadataFetch>(fetch: &F) -> AsyncTiffResult<Self> {
35        let magic_bytes = fetch.fetch(0..2).await?;
36
37        // Should be b"II" for little endian or b"MM" for big endian
38        let endianness = if magic_bytes == Bytes::from_static(b"II") {
39            Endianness::LittleEndian
40        } else if magic_bytes == Bytes::from_static(b"MM") {
41            Endianness::BigEndian
42        } else {
43            return Err(AsyncTiffError::General(format!(
44                "unexpected magic bytes {magic_bytes:?}"
45            )));
46        };
47
48        // Set offset to 2 since we've already read magic bytes.
49        let mut cursor = MetadataCursor::new(fetch, endianness).with_offset(2);
50
51        let version = cursor.read_u16().await?;
52        let bigtiff = match version {
53            42 => false,
54            43 => {
55                // Read bytesize of offsets (in bigtiff it's alway 8 but provide a way to move to 16 some day)
56                if cursor.read_u16().await? != 8 {
57                    return Err(
58                        TiffError::FormatError(TiffFormatError::TiffSignatureNotFound).into(),
59                    );
60                }
61                // This constant should always be 0
62                if cursor.read_u16().await? != 0 {
63                    return Err(
64                        TiffError::FormatError(TiffFormatError::TiffSignatureNotFound).into(),
65                    );
66                }
67                true
68            }
69            _ => return Err(TiffError::FormatError(TiffFormatError::TiffSignatureInvalid).into()),
70        };
71
72        let first_ifd_location = if bigtiff {
73            cursor.read_u64().await?
74        } else {
75            cursor.read_u32().await?.into()
76        };
77
78        Ok(Self {
79            endianness,
80            bigtiff,
81            next_ifd_offset: Some(first_ifd_location),
82        })
83    }
84
85    /// Returns the endianness of the file.
86    pub fn endianness(&self) -> Endianness {
87        self.endianness
88    }
89
90    /// Returns `true` if this is a bigtiff file.
91    pub fn bigtiff(&self) -> bool {
92        self.bigtiff
93    }
94
95    /// Returns `true` if there are more IFDs to read.
96    pub fn has_next_ifd(&self) -> bool {
97        self.next_ifd_offset.is_some()
98    }
99
100    /// The byte offset of the start of the next IFD.
101    ///
102    /// This will be `None` if all IFDs have already been read.
103    pub fn next_ifd_offset(&self) -> Option<u64> {
104        self.next_ifd_offset
105    }
106
107    /// Read the next IFD from the file.
108    ///
109    /// If there are no more IFDs, returns `None`.
110    pub async fn read_next_ifd<F: MetadataFetch>(
111        &mut self,
112        fetch: &F,
113    ) -> AsyncTiffResult<Option<ImageFileDirectory>> {
114        if let Some(ifd_start) = self.next_ifd_offset {
115            let ifd_reader =
116                ImageFileDirectoryReader::open(fetch, ifd_start, self.bigtiff, self.endianness)
117                    .await?;
118            let ifd = ifd_reader.read(fetch).await?;
119            let next_ifd_offset = ifd_reader.finish(fetch).await?;
120            self.next_ifd_offset = next_ifd_offset;
121            Ok(Some(ifd))
122        } else {
123            Ok(None)
124        }
125    }
126
127    /// Read all IFDs from the file.
128    pub async fn read_all_ifds<F: MetadataFetch>(
129        &mut self,
130        fetch: &F,
131    ) -> AsyncTiffResult<Vec<ImageFileDirectory>> {
132        let mut ifds = vec![];
133        while let Some(ifd) = self.read_next_ifd(fetch).await? {
134            ifds.push(ifd);
135        }
136        Ok(ifds)
137    }
138
139    /// Read all IFDs from the file and return a complete TIFF structure.
140    pub async fn read<F: MetadataFetch>(&mut self, fetch: &F) -> AsyncTiffResult<TIFF> {
141        let ifds = self.read_all_ifds(fetch).await?;
142        Ok(TIFF::new(ifds, self.endianness))
143    }
144}
145
146/// Reads the [`ImageFileDirectory`] metadata.
147///
148/// TIFF metadata is not necessarily contiguous in the files: IFDs are normally all stored
149/// contiguously in the header, but the spec allows them to be non-contiguous or spread out through
150/// the file.
151///
152/// Note that you must call [`finish`][ImageFileDirectoryReader::finish] to read the offset of the
153/// following IFD.
154pub struct ImageFileDirectoryReader {
155    endianness: Endianness,
156    bigtiff: bool,
157    /// The byte offset of the beginning of this IFD
158    ifd_start_offset: u64,
159    /// The number of tags in this IFD
160    tag_count: u64,
161    /// The number of bytes that each IFD entry takes up.
162    /// This is 12 bytes for normal TIFF and 20 bytes for BigTIFF.
163    ifd_entry_byte_size: u64,
164    /// The number of bytes that the value for the number of tags takes up.
165    tag_count_byte_size: u64,
166}
167
168impl ImageFileDirectoryReader {
169    /// Read and parse the IFD starting at the given file offset
170    pub async fn open<F: MetadataFetch>(
171        fetch: &F,
172        ifd_start_offset: u64,
173        bigtiff: bool,
174        endianness: Endianness,
175    ) -> AsyncTiffResult<Self> {
176        let mut cursor = MetadataCursor::new_with_offset(fetch, endianness, ifd_start_offset);
177
178        // Tag   2 bytes
179        // Type  2 bytes
180        // Count:
181        //  - bigtiff: 8 bytes
182        //  - else: 4 bytes
183        // TagValue:
184        //  - bigtiff: 8 bytes either a pointer the value itself
185        //  - else: 4 bytes either a pointer the value itself
186        let ifd_entry_byte_size = if bigtiff { 20 } else { 12 };
187        // The size of `tag_count` that we read above
188        let tag_count_byte_size = if bigtiff { 8 } else { 2 };
189
190        let tag_count = if bigtiff {
191            cursor.read_u64().await?
192        } else {
193            cursor.read_u16().await?.into()
194        };
195
196        Ok(Self {
197            endianness,
198            bigtiff,
199            ifd_entry_byte_size,
200            tag_count,
201            tag_count_byte_size,
202            ifd_start_offset,
203        })
204    }
205
206    /// Manually read the tag with the specified index.
207    ///
208    /// Panics if the tag index is out of range of the tag count.
209    ///
210    /// This can be useful if you need to access tags at a low level. You'll need to call
211    /// [`ImageFileDirectory::from_tags`] on the resulting collection of tags.
212    pub async fn read_tag<F: MetadataFetch>(
213        &self,
214        fetch: &F,
215        tag_idx: u64,
216    ) -> AsyncTiffResult<(Tag, TagValue)> {
217        assert!(tag_idx < self.tag_count);
218        let tag_offset =
219            self.ifd_start_offset + self.tag_count_byte_size + (self.ifd_entry_byte_size * tag_idx);
220        let (tag_name, tag_value) =
221            read_tag(fetch, tag_offset, self.endianness, self.bigtiff).await?;
222        Ok((tag_name, tag_value))
223    }
224
225    /// Read all tags out of this IFD.
226    ///
227    /// Keep in mind that you'll still need to call [`finish`][Self::finish] to get the byte offset
228    /// of the next IFD.
229    pub async fn read<F: MetadataFetch>(&self, fetch: &F) -> AsyncTiffResult<ImageFileDirectory> {
230        let mut tags = HashMap::with_capacity(self.tag_count as usize);
231        for tag_idx in 0..self.tag_count {
232            let (tag, value) = self.read_tag(fetch, tag_idx).await?;
233            tags.insert(tag, value);
234        }
235        ImageFileDirectory::from_tags(tags, self.endianness)
236    }
237
238    /// Finish this reader, reading the byte offset of the next IFD
239    pub async fn finish<F: MetadataFetch>(self, fetch: &F) -> AsyncTiffResult<Option<u64>> {
240        // The byte offset for reading the next ifd
241        let next_ifd_byte_offset = self.ifd_start_offset
242            + self.tag_count_byte_size
243            + (self.ifd_entry_byte_size * self.tag_count);
244        let mut cursor =
245            MetadataCursor::new_with_offset(fetch, self.endianness, next_ifd_byte_offset);
246
247        let next_ifd_offset = if self.bigtiff {
248            cursor.read_u64().await?
249        } else {
250            cursor.read_u32().await?.into()
251        };
252
253        // If the ifd_offset is 0, no more IFDs
254        if next_ifd_offset == 0 {
255            Ok(None)
256        } else {
257            Ok(Some(next_ifd_offset))
258        }
259    }
260}
261
262/// Read a single tag from the cursor
263async fn read_tag<F: MetadataFetch>(
264    fetch: &F,
265    tag_offset: u64,
266    endianness: Endianness,
267    bigtiff: bool,
268) -> AsyncTiffResult<(Tag, TagValue)> {
269    let mut cursor = MetadataCursor::new_with_offset(fetch, endianness, tag_offset);
270
271    let tag_name = Tag::from_u16_exhaustive(cursor.read_u16().await?);
272
273    let tag_type_code = cursor.read_u16().await?;
274    let tag_type = Type::from_u16(tag_type_code).expect(
275        "Unknown tag type {tag_type_code}. TODO: we should skip entries with unknown tag types.",
276    );
277    let count = if bigtiff {
278        cursor.read_u64().await?
279    } else {
280        cursor.read_u32().await?.into()
281    };
282
283    let tag_value = read_tag_value(&mut cursor, tag_type, count, bigtiff).await?;
284
285    Ok((tag_name, tag_value))
286}
287
288/// Read a tag's value from the cursor
289///
290/// NOTE: this does not maintain cursor state
291// This is derived from the upstream tiff crate:
292// https://github.com/image-rs/image-tiff/blob/6dc7a266d30291db1e706c8133357931f9e2a053/src/decoder/ifd.rs#L369-L639
293async fn read_tag_value<F: MetadataFetch>(
294    cursor: &mut MetadataCursor<'_, F>,
295    tag_type: Type,
296    count: u64,
297    bigtiff: bool,
298) -> AsyncTiffResult<TagValue> {
299    // Case 1: there are no values so we can return immediately.
300    if count == 0 {
301        return Ok(TagValue::List(vec![]));
302    }
303
304    let tag_size = match tag_type {
305        Type::BYTE | Type::SBYTE | Type::ASCII | Type::UNDEFINED => 1,
306        Type::SHORT | Type::SSHORT => 2,
307        Type::LONG | Type::SLONG | Type::FLOAT | Type::IFD => 4,
308        Type::LONG8
309        | Type::SLONG8
310        | Type::DOUBLE
311        | Type::RATIONAL
312        | Type::SRATIONAL
313        | Type::IFD8 => 8,
314    };
315
316    let value_byte_length = count.checked_mul(tag_size).unwrap();
317
318    // Case 2: there is one value.
319    if count == 1 {
320        // 2a: the value is 5-8 bytes and we're in BigTiff mode.
321        if bigtiff && value_byte_length > 4 && value_byte_length <= 8 {
322            let mut data = cursor.read(value_byte_length).await?;
323
324            return Ok(match tag_type {
325                Type::LONG8 => TagValue::UnsignedBig(data.read_u64()?),
326                Type::SLONG8 => TagValue::SignedBig(data.read_i64()?),
327                Type::DOUBLE => TagValue::Double(data.read_f64()?),
328                Type::RATIONAL => TagValue::Rational(data.read_u32()?, data.read_u32()?),
329                Type::SRATIONAL => TagValue::SRational(data.read_i32()?, data.read_i32()?),
330                Type::IFD8 => TagValue::IfdBig(data.read_u64()?),
331                Type::BYTE
332                | Type::SBYTE
333                | Type::ASCII
334                | Type::UNDEFINED
335                | Type::SHORT
336                | Type::SSHORT
337                | Type::LONG
338                | Type::SLONG
339                | Type::FLOAT
340                | Type::IFD => unreachable!(),
341            });
342        }
343
344        // NOTE: we should only be reading value_byte_length when it's 4 bytes or fewer. Right now
345        // we're reading even if it's 8 bytes, but then only using the first 4 bytes of this
346        // buffer.
347        let mut data = cursor.read(value_byte_length).await?;
348
349        // 2b: the value is at most 4 bytes or doesn't fit in the offset field.
350        return Ok(match tag_type {
351            Type::BYTE | Type::UNDEFINED => TagValue::Byte(data.read_u8()?),
352            Type::SBYTE => TagValue::SignedByte(data.read_i8()?),
353            Type::SHORT => TagValue::Short(data.read_u16()?),
354            Type::SSHORT => TagValue::SignedShort(data.read_i16()?),
355            Type::LONG => TagValue::Unsigned(data.read_u32()?),
356            Type::SLONG => TagValue::Signed(data.read_i32()?),
357            Type::FLOAT => TagValue::Float(data.read_f32()?),
358            Type::ASCII => {
359                if data.as_ref()[0] == 0 {
360                    TagValue::Ascii("".to_string())
361                } else {
362                    panic!("Invalid tag");
363                    // return Err(TiffError::FormatError(TiffFormatError::InvalidTag));
364                }
365            }
366            Type::LONG8 => {
367                let offset = data.read_u32()?;
368                cursor.seek(offset as _);
369                TagValue::UnsignedBig(cursor.read_u64().await?)
370            }
371            Type::SLONG8 => {
372                let offset = data.read_u32()?;
373                cursor.seek(offset as _);
374                TagValue::SignedBig(cursor.read_i64().await?)
375            }
376            Type::DOUBLE => {
377                let offset = data.read_u32()?;
378                cursor.seek(offset as _);
379                TagValue::Double(cursor.read_f64().await?)
380            }
381            Type::RATIONAL => {
382                let offset = data.read_u32()?;
383                cursor.seek(offset as _);
384                let numerator = cursor.read_u32().await?;
385                let denominator = cursor.read_u32().await?;
386                TagValue::Rational(numerator, denominator)
387            }
388            Type::SRATIONAL => {
389                let offset = data.read_u32()?;
390                cursor.seek(offset as _);
391                let numerator = cursor.read_i32().await?;
392                let denominator = cursor.read_i32().await?;
393                TagValue::SRational(numerator, denominator)
394            }
395            Type::IFD => TagValue::Ifd(data.read_u32()?),
396            Type::IFD8 => {
397                let offset = data.read_u32()?;
398                cursor.seek(offset as _);
399                TagValue::IfdBig(cursor.read_u64().await?)
400            }
401        });
402    }
403
404    // Case 3: There is more than one value, but it fits in the offset field.
405    if value_byte_length <= 4 || bigtiff && value_byte_length <= 8 {
406        let mut data = cursor.read(value_byte_length).await?;
407        if bigtiff {
408            cursor.advance(8 - value_byte_length);
409        } else {
410            cursor.advance(4 - value_byte_length);
411        }
412
413        match tag_type {
414            Type::BYTE | Type::UNDEFINED => {
415                return {
416                    Ok(TagValue::List(
417                        (0..count)
418                            .map(|_| TagValue::Byte(data.read_u8().unwrap()))
419                            .collect(),
420                    ))
421                };
422            }
423            Type::SBYTE => {
424                return {
425                    Ok(TagValue::List(
426                        (0..count)
427                            .map(|_| TagValue::SignedByte(data.read_i8().unwrap()))
428                            .collect(),
429                    ))
430                }
431            }
432            Type::ASCII => {
433                let mut buf = vec![0; count as usize];
434                data.read_exact(&mut buf)?;
435                if buf.is_ascii() && buf.ends_with(&[0]) {
436                    let v = std::str::from_utf8(&buf)
437                        .map_err(|err| AsyncTiffError::General(err.to_string()))?;
438                    let v = v.trim_matches(char::from(0));
439                    return Ok(TagValue::Ascii(v.into()));
440                } else {
441                    panic!("Invalid tag");
442                    // return Err(TiffError::FormatError(TiffFormatError::InvalidTag));
443                }
444            }
445            Type::SHORT => {
446                let mut v = Vec::new();
447                for _ in 0..count {
448                    v.push(TagValue::Short(data.read_u16()?));
449                }
450                return Ok(TagValue::List(v));
451            }
452            Type::SSHORT => {
453                let mut v = Vec::new();
454                for _ in 0..count {
455                    v.push(TagValue::SignedShort(data.read_i16()?));
456                }
457                return Ok(TagValue::List(v));
458            }
459            Type::LONG => {
460                let mut v = Vec::new();
461                for _ in 0..count {
462                    v.push(TagValue::Unsigned(data.read_u32()?));
463                }
464                return Ok(TagValue::List(v));
465            }
466            Type::SLONG => {
467                let mut v = Vec::new();
468                for _ in 0..count {
469                    v.push(TagValue::Signed(data.read_i32()?));
470                }
471                return Ok(TagValue::List(v));
472            }
473            Type::FLOAT => {
474                let mut v = Vec::new();
475                for _ in 0..count {
476                    v.push(TagValue::Float(data.read_f32()?));
477                }
478                return Ok(TagValue::List(v));
479            }
480            Type::IFD => {
481                let mut v = Vec::new();
482                for _ in 0..count {
483                    v.push(TagValue::Ifd(data.read_u32()?));
484                }
485                return Ok(TagValue::List(v));
486            }
487            Type::LONG8
488            | Type::SLONG8
489            | Type::RATIONAL
490            | Type::SRATIONAL
491            | Type::DOUBLE
492            | Type::IFD8 => {
493                unreachable!()
494            }
495        }
496    }
497
498    // Seek cursor
499    let offset = if bigtiff {
500        cursor.read_u64().await?
501    } else {
502        cursor.read_u32().await?.into()
503    };
504    cursor.seek(offset);
505
506    // Case 4: there is more than one value, and it doesn't fit in the offset field.
507    match tag_type {
508        // TODO check if this could give wrong results
509        // at a different endianess of file/computer.
510        Type::BYTE | Type::UNDEFINED => {
511            let mut v = Vec::with_capacity(count as _);
512            for _ in 0..count {
513                v.push(TagValue::Byte(cursor.read_u8().await?))
514            }
515            Ok(TagValue::List(v))
516        }
517        Type::SBYTE => {
518            let mut v = Vec::with_capacity(count as _);
519            for _ in 0..count {
520                v.push(TagValue::SignedByte(cursor.read_i8().await?))
521            }
522            Ok(TagValue::List(v))
523        }
524        Type::SHORT => {
525            let mut v = Vec::with_capacity(count as _);
526            for _ in 0..count {
527                v.push(TagValue::Short(cursor.read_u16().await?))
528            }
529            Ok(TagValue::List(v))
530        }
531        Type::SSHORT => {
532            let mut v = Vec::with_capacity(count as _);
533            for _ in 0..count {
534                v.push(TagValue::SignedShort(cursor.read_i16().await?))
535            }
536            Ok(TagValue::List(v))
537        }
538        Type::LONG => {
539            let mut v = Vec::with_capacity(count as _);
540            for _ in 0..count {
541                v.push(TagValue::Unsigned(cursor.read_u32().await?))
542            }
543            Ok(TagValue::List(v))
544        }
545        Type::SLONG => {
546            let mut v = Vec::with_capacity(count as _);
547            for _ in 0..count {
548                v.push(TagValue::Signed(cursor.read_i32().await?))
549            }
550            Ok(TagValue::List(v))
551        }
552        Type::FLOAT => {
553            let mut v = Vec::with_capacity(count as _);
554            for _ in 0..count {
555                v.push(TagValue::Float(cursor.read_f32().await?))
556            }
557            Ok(TagValue::List(v))
558        }
559        Type::DOUBLE => {
560            let mut v = Vec::with_capacity(count as _);
561            for _ in 0..count {
562                v.push(TagValue::Double(cursor.read_f64().await?))
563            }
564            Ok(TagValue::List(v))
565        }
566        Type::RATIONAL => {
567            let mut v = Vec::with_capacity(count as _);
568            for _ in 0..count {
569                v.push(TagValue::Rational(
570                    cursor.read_u32().await?,
571                    cursor.read_u32().await?,
572                ))
573            }
574            Ok(TagValue::List(v))
575        }
576        Type::SRATIONAL => {
577            let mut v = Vec::with_capacity(count as _);
578            for _ in 0..count {
579                v.push(TagValue::SRational(
580                    cursor.read_i32().await?,
581                    cursor.read_i32().await?,
582                ))
583            }
584            Ok(TagValue::List(v))
585        }
586        Type::LONG8 => {
587            let mut v = Vec::with_capacity(count as _);
588            for _ in 0..count {
589                v.push(TagValue::UnsignedBig(cursor.read_u64().await?))
590            }
591            Ok(TagValue::List(v))
592        }
593        Type::SLONG8 => {
594            let mut v = Vec::with_capacity(count as _);
595            for _ in 0..count {
596                v.push(TagValue::SignedBig(cursor.read_i64().await?))
597            }
598            Ok(TagValue::List(v))
599        }
600        Type::IFD => {
601            let mut v = Vec::with_capacity(count as _);
602            for _ in 0..count {
603                v.push(TagValue::Ifd(cursor.read_u32().await?))
604            }
605            Ok(TagValue::List(v))
606        }
607        Type::IFD8 => {
608            let mut v = Vec::with_capacity(count as _);
609            for _ in 0..count {
610                v.push(TagValue::IfdBig(cursor.read_u64().await?))
611            }
612            Ok(TagValue::List(v))
613        }
614        Type::ASCII => {
615            let mut out = vec![0; count as _];
616            let mut buf = cursor.read(count).await?;
617            buf.read_exact(&mut out)?;
618
619            // Strings may be null-terminated, so we trim anything downstream of the null byte
620            if let Some(first) = out.iter().position(|&b| b == 0) {
621                out.truncate(first);
622            }
623            Ok(TagValue::Ascii(String::from_utf8_lossy(&out).into_owned()))
624        }
625    }
626}
627
628#[cfg(test)]
629mod test {
630    use async_trait::async_trait;
631
632    use super::*;
633
634    #[async_trait]
635    impl MetadataFetch for Bytes {
636        async fn fetch(&self, range: std::ops::Range<u64>) -> crate::error::AsyncTiffResult<Bytes> {
637            let usize_range = range.start as usize..range.end as usize;
638            Ok(self.slice(usize_range))
639        }
640    }
641
642    #[tokio::test]
643    #[rustfmt::skip]
644    async fn test_single_fits_notbig() {
645        // personal sanity checks
646        assert_eq!(u16::from_le_bytes([42,0]),42);
647        assert_eq!(u16::from_be_bytes([0,42]),42);
648        assert_eq!(f32::from_le_bytes([0x42,0,0,0]),f32::from_bits(0x00_00_00_42));
649        assert_eq!(f32::from_be_bytes([0,0,0,0x42]),f32::from_bits(0x00_00_00_42));
650        let cases= [
651        // tag type   count      offset
652        // /\  / \   /     \   /       \
653        ([1,1, 1, 0, 1,0,0,0, 42, 0, 0, 0], Endianness::LittleEndian, TagValue::Byte      (42                )),
654        ([1,1, 0, 1, 0,0,0,1, 42, 0, 0, 0], Endianness::BigEndian,    TagValue::Byte      (42                )),
655        ([1,1, 6, 0, 1,0,0,0, 42, 0, 0, 0], Endianness::LittleEndian, TagValue::SignedByte(42                )),
656        ([1,1, 0, 6, 0,0,0,1, 42, 0, 0, 0], Endianness::BigEndian,    TagValue::SignedByte(42                )),
657        ([1,1, 7, 0, 1,0,0,0, 42, 0, 0, 0], Endianness::LittleEndian, TagValue::Byte      (42                )), // undefined
658        ([1,1, 0, 7, 0,0,0,1, 42, 0, 0, 0], Endianness::BigEndian,    TagValue::Byte      (42                )), // undefined
659        ([1,1, 2, 0, 1,0,0,0,  0, 0, 0, 0], Endianness::LittleEndian, TagValue::Ascii     ("".into()         )),
660        ([1,1, 0, 2, 0,0,0,1,  0, 0, 0, 0], Endianness::BigEndian,    TagValue::Ascii     ("".into()         )),
661        ([1,1, 3, 0, 1,0,0,0, 42, 0, 0, 0], Endianness::LittleEndian, TagValue::Short       (42              )),
662        ([1,1, 0, 3, 0,0,0,1,  0,42, 0, 0], Endianness::BigEndian,    TagValue::Short       (42              )),
663        ([1,1, 8, 0, 1,0,0,0, 42, 0, 0, 0], Endianness::LittleEndian, TagValue::SignedShort (42              )),
664        ([1,1, 0, 8, 0,0,0,1,  0,42, 0, 0], Endianness::BigEndian,    TagValue::SignedShort (42              )),
665        ([1,1, 4, 0, 1,0,0,0, 42, 0, 0, 0], Endianness::LittleEndian, TagValue::Unsigned  (42                )),
666        ([1,1, 0, 4, 0,0,0,1,  0, 0, 0,42], Endianness::BigEndian,    TagValue::Unsigned  (42                )),
667        ([1,1, 9, 0, 1,0,0,0, 42, 0, 0, 0], Endianness::LittleEndian, TagValue::Signed    (42                )),
668        ([1,1, 0, 9, 0,0,0,1,  0, 0, 0,42], Endianness::BigEndian,    TagValue::Signed    (42                )),
669        ([1,1,13, 0, 1,0,0,0, 42, 0, 0, 0], Endianness::LittleEndian, TagValue::Ifd       (42                )),
670        ([1,1, 0,13, 0,0,0,1,  0, 0, 0,42], Endianness::BigEndian,    TagValue::Ifd       (42                )),
671        ([1,1,11, 0, 1,0,0,0, 42, 0, 0, 0], Endianness::LittleEndian, TagValue::Float     (f32::from_bits(42))),
672        ([1,1, 0,11, 0,0,0,1,  0, 0, 0,42], Endianness::BigEndian,    TagValue::Float     (f32::from_bits(42))),
673        // Double doesn't fit, neither 8-types and we special-case IFD
674        ];
675        for (buf, byte_order, res) in cases {
676                let fetch = Bytes::copy_from_slice(&buf);
677            assert_eq!(
678                read_tag(&fetch, 0, byte_order, false).await.unwrap(),
679                (Tag::from_u16_exhaustive(0x01_01),res)
680            );
681        }
682    }
683
684    #[tokio::test]
685    #[rustfmt::skip]
686    async fn test_single_fits_big() {
687        // personal sanity checks
688        assert_eq!(u16::from_le_bytes([42,0]),42);
689        assert_eq!(u16::from_be_bytes([0,42]),42);
690
691        assert_eq!(f32::from_le_bytes([0x42,0,0,0]),f32::from_bits(0x00_00_00_42));
692        assert_eq!(f32::from_be_bytes([0,0,0,0x42]),f32::from_bits(0x00_00_00_42));
693        let cases = [
694        //      type       count            offset
695        //       / \  1 2 3 4 5 6 7 8   1  2  3  4  5  6  7  8
696        ([1,1,  1, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::Byte       (42)                ),
697        ([1,1,  0, 1, 0,0,0,0,0,0,0,1, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::Byte       (42)                ),
698        ([1,1,  6, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::SignedByte (42)                ),
699        ([1,1,  0, 6, 0,0,0,0,0,0,0,1, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::SignedByte (42)                ),
700        ([1,1,  7, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::Byte       (42)                ), // undefined
701        ([1,1,  0, 7, 0,0,0,0,0,0,0,1, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::Byte       (42)                ), // undefined
702        ([1,1,  2, 0, 1,0,0,0,0,0,0,0,  0, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::Ascii      ("".into())         ),
703        ([1,1,  0, 2, 0,0,0,0,0,0,0,1,  0, 0, 0, 0, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::Ascii      ("".into())         ),
704        ([1,1,  3, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::Short      (42)                ),
705        ([1,1,  0, 3, 0,0,0,0,0,0,0,1,  0,42, 0, 0, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::Short      (42)                ),
706        ([1,1,  8, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::SignedShort(42)                ),
707        ([1,1,  0, 8, 0,0,0,0,0,0,0,1,  0,42, 0, 0, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::SignedShort(42)                ),
708        ([1,1,  4, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::Unsigned   (42)                ),
709        ([1,1,  0, 4, 0,0,0,0,0,0,0,1,  0, 0, 0,42, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::Unsigned   (42)                ),
710        ([1,1,  9, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::Signed     (42)                ),
711        ([1,1,  0, 9, 0,0,0,0,0,0,0,1,  0, 0, 0,42, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::Signed     (42)                ),
712        ([1,1, 13, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::Ifd        (42)                ),
713        ([1,1,  0,13, 0,0,0,0,0,0,0,1,  0, 0, 0,42, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::Ifd        (42)                ),
714        ([1,1, 16, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::UnsignedBig(42)                ),
715        ([1,1,  0,16, 0,0,0,0,0,0,0,1,  0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian,    TagValue::UnsignedBig(42)                ),
716        ([1,1, 17, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::SignedBig  (42)                ),
717        ([1,1,  0,17, 0,0,0,0,0,0,0,1,  0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian,    TagValue::SignedBig  (42)                ),
718        ([1,1, 18, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::IfdBig     (42)                ),
719        ([1,1,  0,18, 0,0,0,0,0,0,0,1,  0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian,    TagValue::IfdBig     (42)                ),
720        ([1,1, 11, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::Float      (f32::from_bits(42))),
721        ([1,1,  0,11, 0,0,0,0,0,0,0,1,  0, 0, 0,42, 0, 0, 0, 0], Endianness::BigEndian,    TagValue::Float      (f32::from_bits(42))),
722        ([1,1, 12, 0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::Double     (f64::from_bits(42))),
723        ([1,1,  0,12, 0,0,0,0,0,0,0,1,  0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian,    TagValue::Double     (f64::from_bits(42))),
724        ([1,1,  5, 0, 1,0,0,0,0,0,0,0,  42,0, 0, 0,43, 0, 0, 0], Endianness::LittleEndian, TagValue::Rational   (42, 43)            ),
725        ([1,1,  0, 5, 0,0,0,0,0,0,0,1,  0, 0, 0,42, 0, 0, 0,43], Endianness::BigEndian,    TagValue::Rational   (42, 43)            ),
726        ([1,1,  10,0, 1,0,0,0,0,0,0,0, 42, 0, 0, 0,43, 0, 0, 0], Endianness::LittleEndian, TagValue::SRational  (42, 43)            ),
727        ([1,1,  0,10, 0,0,0,0,0,0,0,1,  0, 0, 0,42, 0, 0, 0,43], Endianness::BigEndian,    TagValue::SRational  (42, 43)            ),
728        // we special-case IFD
729        ];
730        for (buf, byte_order, res) in cases {
731            let fetch = Bytes::copy_from_slice(&buf);
732            assert_eq!(
733                read_tag(&fetch, 0, byte_order, true).await.unwrap(),
734                (Tag::from_u16_exhaustive(0x0101), res)
735            )
736        }
737    }
738
739    #[tokio::test]
740    #[rustfmt::skip]
741    async fn test_fits_multi_notbig() {
742        // personal sanity checks
743        assert_eq!(u16::from_le_bytes([42,0]),42);
744        assert_eq!(u16::from_be_bytes([0,42]),42);
745
746        assert_eq!(f32::from_le_bytes([0x42,0,0,0]),f32::from_bits(0x00_00_00_42));
747        assert_eq!(f32::from_be_bytes([0,0,0,0x42]),f32::from_bits(0x00_00_00_42));
748        let cases = [
749        //  tag type  count    offset
750        //  // /  \  /     \   /     \
751        ([1,1, 1, 0, 4,0,0,0, 42,42,42,42], Endianness::LittleEndian, TagValue::List(vec![TagValue::Byte       (42); 4]) ),
752        ([1,1, 0, 1, 0,0,0,4, 42,42,42,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Byte       (42); 4]) ),
753        ([1,1, 6, 0, 4,0,0,0, 42,42,42,42], Endianness::LittleEndian, TagValue::List(vec![TagValue::SignedByte (42); 4]) ),
754        ([1,1, 0, 6, 0,0,0,4, 42,42,42,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::SignedByte (42); 4]) ),
755        ([1,1, 7, 0, 4,0,0,0, 42,42,42,42], Endianness::LittleEndian, TagValue::List(vec![TagValue::Byte     (42); 4]) ), // undefined
756        ([1,1, 0, 7, 0,0,0,4, 42,42,42,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Byte     (42); 4]) ), // undefined
757        ([1,1, 2, 0, 4,0,0,0, 42,42,42, 0], Endianness::LittleEndian, TagValue::Ascii("***".into())),
758        ([1,1, 0, 2, 0,0,0,4, 42,42,42, 0], Endianness::BigEndian,    TagValue::Ascii("***".into())),
759        ([1,1, 3, 0, 2,0,0,0, 42, 0,42, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Short       (42); 2]) ),
760        ([1,1, 0, 3, 0,0,0,2,  0,42, 0,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Short       (42); 2]) ),
761        ([1,1, 8, 0, 2,0,0,0, 42, 0,42, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::SignedShort (42); 2]) ),
762        ([1,1, 0, 8, 0,0,0,2,  0,42, 0,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::SignedShort (42); 2]) ),
763        ([1,1, 0, 2, 0,0,0,4, b'A',b'B',b'C',0], Endianness::BigEndian, TagValue::Ascii("ABC".into())),
764        // others don't fit, neither 8-types and we special-case IFD
765        ];
766        for (buf, byte_order, res) in cases {
767            println!("testing {buf:?} to be {res:?}");
768            let fetch = Bytes::copy_from_slice(&buf);
769            assert_eq!(
770                read_tag(&fetch, 0, byte_order, false).await.unwrap(),
771                (Tag::from_u16_exhaustive(0x0101), res)
772            )
773        }
774    }
775
776    #[tokio::test]
777    #[rustfmt::skip]
778    async fn test_fits_multi_big() {
779        // personal sanity checks
780        assert_eq!(u16::from_le_bytes([42,0]),42);
781        assert_eq!(u16::from_be_bytes([0,42]),42);
782
783        assert_eq!(f32::from_le_bytes([0x42,0,0,0]),f32::from_bits(0x00_00_00_42));
784        assert_eq!(f32::from_be_bytes([0,0,0,0x42]),f32::from_bits(0x00_00_00_42));
785        let cases = [
786        //     type       count            offset
787        //     / \  1 2 3 4 5 6 7 8   1  2  3  4  5  6  7  8
788        ([1,1, 1, 0, 8,0,0,0,0,0,0,0, 42,42,42,42,42,42,42,42], Endianness::LittleEndian, TagValue::List(vec![TagValue::Byte      (42)                ; 8])),
789        ([1,1, 0, 1, 0,0,0,0,0,0,0,8, 42,42,42,42,42,42,42,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Byte      (42)                ; 8])),
790        ([1,1, 6, 0, 8,0,0,0,0,0,0,0, 42,42,42,42,42,42,42,42], Endianness::LittleEndian, TagValue::List(vec![TagValue::SignedByte(42)                ; 8])),
791        ([1,1, 0, 6, 0,0,0,0,0,0,0,8, 42,42,42,42,42,42,42,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::SignedByte(42)                ; 8])),
792        ([1,1, 7, 0, 8,0,0,0,0,0,0,0, 42,42,42,42,42,42,42,42], Endianness::LittleEndian, TagValue::List(vec![TagValue::Byte      (42)                ; 8])), //undefined u8
793        ([1,1, 0, 7, 0,0,0,0,0,0,0,8, 42,42,42,42,42,42,42,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Byte      (42)                ; 8])), //undefined u8
794        ([1,1, 2, 0, 8,0,0,0,0,0,0,0, 42,42,42,42,42,42,42, 0], Endianness::LittleEndian, TagValue::Ascii                      ("*******".into()       )),
795        ([1,1, 0, 2, 0,0,0,0,0,0,0,8, 42,42,42,42,42,42,42, 0], Endianness::BigEndian,    TagValue::Ascii                      ("*******".into()       )),
796        ([1,1, 3, 0, 4,0,0,0,0,0,0,0, 42, 0,42, 0,42, 0,42, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Short       (42)              ; 4])),
797        ([1,1, 0, 3, 0,0,0,0,0,0,0,4,  0,42, 0,42, 0,42, 0,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Short       (42)              ; 4])),
798        ([1,1, 8, 0, 4,0,0,0,0,0,0,0, 42, 0,42, 0,42, 0,42, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::SignedShort (42)              ; 4])),
799        ([1,1, 0, 8, 0,0,0,0,0,0,0,4,  0,42, 0,42, 0,42, 0,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::SignedShort (42)              ; 4])),
800        ([1,1, 4, 0, 2,0,0,0,0,0,0,0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Unsigned  (42)                ; 2])),
801        ([1,1, 0, 4, 0,0,0,0,0,0,0,2,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Unsigned  (42)                ; 2])),
802        ([1,1, 9, 0, 2,0,0,0,0,0,0,0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Signed    (42)                ; 2])),
803        ([1,1, 0, 9, 0,0,0,0,0,0,0,2,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Signed    (42)                ; 2])),
804        ([1,1,13, 0, 2,0,0,0,0,0,0,0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Ifd       (42)                ; 2])),
805        ([1,1, 0,13, 0,0,0,0,0,0,0,2,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Ifd       (42)                ; 2])),
806        ([1,1,11, 0, 2,0,0,0,0,0,0,0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Float     (f32::from_bits(42)); 2])),
807        ([1,1, 0,11, 0,0,0,0,0,0,0,2,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian,    TagValue::List(vec![TagValue::Float     (f32::from_bits(42)); 2])),
808        // we special-case IFD
809        ];
810        for (buf, byte_order, res) in cases {
811            let fetch = Bytes::copy_from_slice(&buf);
812            assert_eq!(
813                read_tag(&fetch, 0, byte_order, true).await.unwrap(),
814                (Tag::from_u16_exhaustive(0x0101), res)
815            )
816        }
817    }
818
819    #[tokio::test]
820    #[rustfmt::skip]
821    async fn test_notfits_notbig() {
822        // personal sanity checks
823        assert_eq!(u16::from_le_bytes([42,0]),42);
824        assert_eq!(u16::from_be_bytes([0,42]),42);
825
826        assert_eq!(f32::from_le_bytes([0x42,0,0,0]),f32::from_bits(0x00_00_00_42));
827        assert_eq!(f32::from_be_bytes([0,0,0,0x42]),f32::from_bits(0x00_00_00_42));
828        let cases = [
829        //          type  count    offset 12
830        //          /\   /     \   /     \
831        (vec![1,1, 1, 0, 5,0,0,0, 12, 0, 0, 0, 42,42,42,42,42],          Endianness::LittleEndian, TagValue::List(vec![TagValue::Byte       (42                 );5])),
832        (vec![1,1, 0, 1, 0,0,0,5,  0, 0, 0,12, 42,42,42,42,42],          Endianness::BigEndian   , TagValue::List(vec![TagValue::Byte       (42                 );5])),
833        (vec![1,1, 6, 0, 5,0,0,0, 12, 0, 0, 0, 42,42,42,42,42],          Endianness::LittleEndian, TagValue::List(vec![TagValue::SignedByte (42                 );5])),
834        (vec![1,1, 0, 6, 0,0,0,5,  0, 0, 0,12, 42,42,42,42,42],          Endianness::BigEndian   , TagValue::List(vec![TagValue::SignedByte (42                 );5])),
835        (vec![1,1, 7, 0, 5,0,0,0, 12, 0, 0, 0, 42,42,42,42,42],          Endianness::LittleEndian, TagValue::List(vec![TagValue::Byte       (42                 );5])), // Type::UNDEFINED ),
836        (vec![1,1, 0, 7, 0,0,0,5,  0, 0, 0,12, 42,42,42,42,42],          Endianness::BigEndian   , TagValue::List(vec![TagValue::Byte       (42                 );5])), // Type::UNDEFINED ),
837        (vec![1,1, 2, 0, 5,0,0,0, 12, 0, 0, 0, 42,42,42,42, 0],          Endianness::LittleEndian,                  TagValue::Ascii      ("****".into()      )    ),
838        (vec![1,1, 0, 2, 0,0,0,5,  0, 0, 0,12, 42,42,42,42, 0],          Endianness::BigEndian   ,                  TagValue::Ascii      ("****".into()      )    ),
839        (vec![1,1, 3, 0, 3,0,0,0, 12, 0, 0, 0, 42, 0,42, 0,42, 0],       Endianness::LittleEndian, TagValue::List(vec![TagValue::Short      (42                 );3])),
840        (vec![1,1, 0, 3, 0,0,0,3,  0, 0, 0,12,  0,42, 0,42, 0,42],       Endianness::BigEndian   , TagValue::List(vec![TagValue::Short      (42                 );3])),
841        (vec![1,1, 8, 0, 3,0,0,0, 12, 0, 0, 0, 42, 0,42, 0,42, 0],       Endianness::LittleEndian, TagValue::List(vec![TagValue::SignedShort(42                 );3])),
842        (vec![1,1, 0, 8, 0,0,0,3,  0, 0, 0,12,  0,42, 0,42, 0,42],       Endianness::BigEndian   , TagValue::List(vec![TagValue::SignedShort(42                 );3])),
843        (vec![1,1, 4, 0, 2,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Unsigned   (42                 );2])),
844        (vec![1,1, 0, 4, 0,0,0,2,  0, 0, 0,12,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::Unsigned   (42                 );2])),
845        (vec![1,1, 9, 0, 2,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Signed     (42                 );2])),
846        (vec![1,1, 0, 9, 0,0,0,2,  0, 0, 0,12,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::Signed     (42                 );2])),
847        (vec![1,1,13, 0, 2,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Ifd        (42                 );2])),
848        (vec![1,1, 0,13, 0,0,0,2,  0, 0, 0,12,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::Ifd        (42                 );2])),
849        (vec![1,1, 16,0, 1,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian,                  TagValue::UnsignedBig(42                 )    ),
850        (vec![1,1, 0,16, 0,0,0,1,  0, 0, 0,12,  0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian   ,                  TagValue::UnsignedBig(42                 )    ),
851        (vec![1,1, 17,0, 1,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian,                  TagValue::SignedBig  (42                 )    ),
852        (vec![1,1, 0,17, 0,0,0,1,  0, 0, 0,12,  0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian   ,                  TagValue::SignedBig  (42                 )    ),
853        (vec![1,1, 18,0, 1,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian,                  TagValue::IfdBig     (42                 )    ),
854        (vec![1,1, 0,18, 0,0,0,1,  0, 0, 0,12,  0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian   ,                  TagValue::IfdBig     (42                 )    ),
855        (vec![1,1, 11,0, 2,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Float      (f32::from_bits(42) );2])),
856        (vec![1,1, 0,11, 0,0,0,2,  0, 0, 0,12,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::Float      (f32::from_bits(42) );2])),
857        (vec![1,1, 12,0, 1,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian,                  TagValue::Double     (f64::from_bits(42))     ),
858        (vec![1,1, 0,12, 0,0,0,1,  0, 0, 0,12,  0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian   ,                  TagValue::Double     (f64::from_bits(42))     ),
859        (vec![1,1, 5, 0, 1,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian,                  TagValue::Rational   (42, 42             )    ),
860        (vec![1,1, 0, 5, 0,0,0,1,  0, 0, 0,12,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian   ,                  TagValue::Rational   (42, 42             )    ),
861        (vec![1,1, 10,0, 1,0,0,0, 12, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian,                  TagValue::SRational  (42, 42             )    ),
862        (vec![1,1, 0,10, 0,0,0,1,  0, 0, 0,12,  0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian   ,                  TagValue::SRational  (42, 42             )    ),
863        ];
864        for (buf, byte_order, res) in cases {
865            println!("reading {buf:?} to be {res:?}");
866            let fetch = Bytes::from_owner(buf);
867            assert_eq!(
868                read_tag(&fetch, 0, byte_order, false).await.unwrap(),
869                (Tag::from_u16_exhaustive(0x0101), res)
870            )
871        }
872    }
873
874    #[tokio::test]
875    #[rustfmt::skip]
876    async fn test_notfits_big() {
877        // personal sanity checks
878        assert_eq!(u16::from_le_bytes([42,0]),42);
879        assert_eq!(u16::from_be_bytes([0,42]),42);
880        assert_eq!(f32::from_le_bytes([0x42,0,0,0]),f32::from_bits(0x00_00_00_42));
881        assert_eq!(f32::from_be_bytes([0,0,0,0x42]),f32::from_bits(0x00_00_00_42));
882        let cases = [
883        //           type       count            offset
884        //           / \  1 2 3 4 5 6 7 8   1  2  3  4  5  6  7  8
885        (vec![1,1,  1, 0, 9,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42,42,42,42,42,42,42,42,42],                      Endianness::LittleEndian, TagValue::List(vec![TagValue::Byte       (42                );9])),
886        (vec![1,1,  0, 1, 0,0,0,0,0,0,0,9,  0, 0, 0, 0, 0, 0, 0,20, 42,42,42,42,42,42,42,42,42],                      Endianness::BigEndian   , TagValue::List(vec![TagValue::Byte       (42                );9])),
887        (vec![1,1,  6, 0, 9,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42,42,42,42,42,42,42,42,42],                      Endianness::LittleEndian, TagValue::List(vec![TagValue::SignedByte (42                );9])),
888        (vec![1,1,  0, 6, 0,0,0,0,0,0,0,9,  0, 0, 0, 0, 0, 0, 0,20, 42,42,42,42,42,42,42,42,42],                      Endianness::BigEndian   , TagValue::List(vec![TagValue::SignedByte (42                );9])),
889        (vec![1,1,  7, 0, 9,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42,42,42,42,42,42,42,42,42],                      Endianness::LittleEndian, TagValue::List(vec![TagValue::Byte       (42                );9])), //TagType::UNDEFINED ),
890        (vec![1,1,  0, 7, 0,0,0,0,0,0,0,9,  0, 0, 0, 0, 0, 0, 0,20, 42,42,42,42,42,42,42,42,42],                      Endianness::BigEndian   , TagValue::List(vec![TagValue::Byte       (42                );9])), //TagType::UNDEFINED ),
891        (vec![1,1,  2, 0, 9,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42,42,42,42,42,42,42,42, 0],                      Endianness::LittleEndian,                  TagValue::Ascii      ("********".into() )    ),
892        (vec![1,1,  0, 2, 0,0,0,0,0,0,0,9,  0, 0, 0, 0, 0, 0, 0,20, 42,42,42,42,42,42,42,42, 0],                      Endianness::BigEndian   ,                  TagValue::Ascii      ("********".into() )    ),
893        (vec![1,1,  3, 0, 5,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0,42, 0,42, 0,42, 0,42, 0],                   Endianness::LittleEndian, TagValue::List(vec![TagValue::Short      (42                );5])),
894        (vec![1,1,  0, 3, 0,0,0,0,0,0,0,5,  0, 0, 0, 0, 0, 0, 0,20,  0,42, 0,42, 0,42, 0,42, 0,42],                   Endianness::BigEndian   , TagValue::List(vec![TagValue::Short      (42                );5])),
895        (vec![1,1,  8, 0, 5,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0,42, 0,42, 0,42, 0,42, 0],                   Endianness::LittleEndian, TagValue::List(vec![TagValue::SignedShort(42                );5])),
896        (vec![1,1,  0, 8, 0,0,0,0,0,0,0,5,  0, 0, 0, 0, 0, 0, 0,20,  0,42, 0,42, 0,42, 0,42, 0,42],                   Endianness::BigEndian   , TagValue::List(vec![TagValue::SignedShort(42                );5])),
897        (vec![1,1,  4, 0, 3,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0],             Endianness::LittleEndian, TagValue::List(vec![TagValue::Unsigned   (42                );3])),
898        (vec![1,1,  0, 4, 0,0,0,0,0,0,0,3,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42],             Endianness::BigEndian   , TagValue::List(vec![TagValue::Unsigned   (42                );3])),
899        (vec![1,1,  9, 0, 3,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0],             Endianness::LittleEndian, TagValue::List(vec![TagValue::Signed     (42                );3])),
900        (vec![1,1,  0, 9, 0,0,0,0,0,0,0,3,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42],             Endianness::BigEndian   , TagValue::List(vec![TagValue::Signed     (42                );3])),
901        (vec![1,1, 13, 0, 3,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0],             Endianness::LittleEndian, TagValue::List(vec![TagValue::Ifd        (42                );3])),
902        (vec![1,1,  0,13, 0,0,0,0,0,0,0,3,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42],             Endianness::BigEndian   , TagValue::List(vec![TagValue::Ifd        (42                );3])),
903        (vec![1,1, 16, 0, 2,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0,42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::UnsignedBig(42                );2])),
904        (vec![1,1,  0,16, 0,0,0,0,0,0,0,2,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0, 0, 0, 0, 0,42, 0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::UnsignedBig(42                );2])),
905        (vec![1,1, 17, 0, 2,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0,42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::SignedBig  (42                );2])),
906        (vec![1,1,  0,17, 0,0,0,0,0,0,0,2,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0, 0, 0, 0, 0,42, 0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::SignedBig  (42                );2])),
907        (vec![1,1, 18, 0, 2,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0,42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::IfdBig     (42                );2])),
908        (vec![1,1,  0,18, 0,0,0,0,0,0,0,2,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0, 0, 0, 0, 0,42, 0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::IfdBig     (42                );2])),
909        (vec![1,1, 11, 0, 3,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,],            Endianness::LittleEndian, TagValue::List(vec![TagValue::Float      (f32::from_bits(42));3])),
910        (vec![1,1,  0,11, 0,0,0,0,0,0,0,3,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42,],            Endianness::BigEndian   , TagValue::List(vec![TagValue::Float      (f32::from_bits(42));3])),
911        (vec![1,1, 12, 0, 2,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0, 0, 0, 0, 0,42, 0, 0, 0, 0, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Double     (f64::from_bits(42));2])),
912        (vec![1,1,  0,12, 0,0,0,0,0,0,0,2,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0, 0, 0, 0, 0,42, 0, 0, 0, 0, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::Double     (f64::from_bits(42));2])),
913        (vec![1,1,  5, 0, 2,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::Rational   (42, 42            );2])),
914        (vec![1,1,  0, 5, 0,0,0,0,0,0,0,2,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::Rational   (42, 42            );2])),
915        (vec![1,1, 10, 0, 2,0,0,0,0,0,0,0, 20, 0, 0, 0, 0, 0, 0, 0, 42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0], Endianness::LittleEndian, TagValue::List(vec![TagValue::SRational  (42, 42            );2])),
916        (vec![1,1,  0,10, 0,0,0,0,0,0,0,2,  0, 0, 0, 0, 0, 0, 0,20,  0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42, 0, 0, 0,42], Endianness::BigEndian   , TagValue::List(vec![TagValue::SRational  (42, 42            );2])),
917        ];
918        for (buf, byte_order, res) in cases {
919            println!("reading {buf:?} to be {res:?}");
920            let fetch = Bytes::from_owner(buf);
921            assert_eq!(read_tag(&fetch, 0, byte_order, true).await.unwrap(), (Tag::from_u16_exhaustive(0x0101), res))
922        }
923    }
924}