dicom_parser/dataset/
read.rs

1//! This module contains a mid-level abstraction for reading DICOM content
2//! sequentially.
3//!
4//! The rest of the crate is used to obtain DICOM element headers and values.
5//! At this level, headers and values are treated as tokens which can be used
6//! to form a syntax tree of a full data set.
7use crate::stateful::decode::{DynStatefulDecoder, Error as DecoderError, StatefulDecode};
8use dicom_core::header::{DataElementHeader, Header, Length, SequenceItemHeader};
9use dicom_core::{PrimitiveValue, Tag, VR};
10use dicom_encoding::text::SpecificCharacterSet;
11use dicom_encoding::transfer_syntax::TransferSyntax;
12use snafu::{Backtrace, ResultExt, Snafu};
13use std::cmp::Ordering;
14use std::io::Read;
15
16use super::{DataToken, SeqTokenType};
17
18fn is_stateful_decode<T>(_: &T)
19where
20    T: StatefulDecode,
21{
22}
23
24#[derive(Debug, Snafu)]
25#[non_exhaustive]
26pub enum Error {
27    #[snafu(display("Could not create decoder"))]
28    CreateDecoder {
29        #[snafu(backtrace)]
30        source: DecoderError,
31    },
32    #[snafu(display("Could not read item header"))]
33    ReadItemHeader {
34        #[snafu(backtrace)]
35        source: DecoderError,
36    },
37    #[snafu(display("Could not read element header"))]
38    ReadHeader {
39        #[snafu(backtrace)]
40        source: DecoderError,
41    },
42    #[snafu(display("Could not read {} value bytes for element tagged {}", len, tag))]
43    ReadValue {
44        len: u32,
45        tag: Tag,
46        #[snafu(backtrace)]
47        source: DecoderError,
48    },
49    #[snafu(display("Could not read {} bytes for item value", len))]
50    ReadItemValue {
51        len: u32,
52        #[snafu(backtrace)]
53        source: DecoderError,
54    },
55    #[snafu(display(
56        "Inconsistent sequence end: expected end at {} bytes but read {}",
57        end_of_sequence,
58        bytes_read
59    ))]
60    InconsistentSequenceEnd {
61        end_of_sequence: u64,
62        bytes_read: u64,
63        backtrace: Backtrace,
64    },
65    #[snafu(display("Unexpected item tag {} while reading element header", tag))]
66    UnexpectedItemTag { tag: Tag, backtrace: Backtrace },
67    #[snafu(display(
68        "Unexpected item header outside a dataset sequence at {} bytes",
69        bytes_read
70    ))]
71    UnexpectedItemHeader {
72        bytes_read: u64,
73        backtrace: Backtrace,
74    },
75    /// Undefined pixel item length
76    UndefinedItemLength,
77}
78
79pub type Result<T> = std::result::Result<T, Error>;
80
81/// A reader-specific token representing a sequence or item start.
82#[derive(Debug, Copy, Clone, PartialEq)]
83struct SeqToken {
84    /// Whether it is the start of a sequence or the start of an item.
85    typ: SeqTokenType,
86    /// The length of the value, as indicated by the starting element,
87    /// can be unknown.
88    len: Length,
89    /// Whether this sequence token is part of an encapsulated pixel data.
90    pixel_data: bool,
91    /// The number of bytes the parser has read until it reached the
92    /// beginning of the sequence or item value data.
93    base_offset: u64,
94}
95
96/// The value reading strategy for the data set reader.
97///
98/// It defines how the `PrimitiveValue`s in value tokens are constructed.
99#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
100pub enum ValueReadStrategy {
101    /// Textual values will be decoded according to their value representation.
102    ///
103    /// Word-sized binary values are read according to
104    /// the expected byte order.
105    /// Dates, times, and date-times (DA, DT, TM) are parsed
106    /// into their more specific variants,
107    /// leading to parser failure if they are not valid DICOM.
108    /// String numbers (IS, FD) are also converted into binary representations.
109    /// For the case of floats, this may introduce precision errors.
110    Interpreted,
111    /// Values will be stored without decoding dates or textual numbers.
112    ///
113    /// Word-sized binary values are read according to
114    /// the expected byte order.
115    /// Date-time values and numbers are kept in their original string
116    /// representation as string objects.
117    /// All text is still decoded into Rust string values,
118    /// in accordance to the standard,
119    /// unless its value representation is unknown to the decoder.
120    ///
121    /// This is the default strategy.
122    #[default]
123    Preserved,
124    /// All primitive values are fetched as raw byte buffers,
125    /// without any form of decoding or interpretation.
126    /// Not even byte order conversions are made.
127    ///
128    /// This strategy is not recommended,
129    /// as it makes the retrieval of important textual data more difficult.
130    Raw,
131}
132
133/// The set of options for the data set reader.
134#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
135#[non_exhaustive]
136pub struct DataSetReaderOptions {
137    /// the value reading strategy
138    pub value_read: ValueReadStrategy,
139    /// the position of the reader as received at building time
140    pub base_offset: u64,
141}
142
143impl DataSetReaderOptions {
144    /// Replace the value reading strategy of the options.
145    pub fn value_read(mut self, value_read: ValueReadStrategy) -> Self {
146        self.value_read = value_read;
147        self
148    }
149    /// Replace the base reader offset of the options.
150    pub fn base_offset(mut self, base_offset: u64) -> Self {
151        self.base_offset = base_offset;
152        self
153    }
154}
155
156/// A higher-level reader for retrieving structure in a DICOM data set from an
157/// arbitrary data source.
158#[derive(Debug)]
159pub struct DataSetReader<S> {
160    /// the stateful decoder
161    parser: S,
162    /// the options of this reader
163    options: DataSetReaderOptions,
164    /// whether the reader is expecting an item header next (or a sequence delimiter)
165    in_sequence: bool,
166    /// whether the reader is expecting the first item value of a pixel sequence next
167    /// (offset table)
168    offset_table_next: bool,
169    /// whether a check for a sequence or item delimitation is pending
170    delimiter_check_pending: bool,
171    /// a stack of delimiters
172    seq_delimiters: Vec<SeqToken>,
173    /// fuse the iteration process if true
174    hard_break: bool,
175    /// last decoded header
176    last_header: Option<DataElementHeader>,
177    /// if a peek was taken, this holds the token peeked
178    peek: Option<DataToken>,
179}
180
181impl<R> DataSetReader<DynStatefulDecoder<R>> {
182    /// Create a new data set token reader with the given byte source,
183    /// while considering the given transfer syntax specifier.
184    #[inline]
185    pub fn new_with_ts(source: R, ts: &TransferSyntax) -> Result<Self>
186    where
187        R: Read,
188    {
189        Self::new_with_ts_cs_options(source, ts, Default::default(), Default::default())
190    }
191
192    /// Create a new data set token reader with the given byte source,
193    /// while considering the given transfer syntax specifier
194    /// and the specific character set to assume by default.
195    ///
196    /// Note that the data set being read
197    /// can override the character set with the presence of a
198    /// _Specific Character Set_ data element.
199    #[inline]
200    pub fn new_with_ts_cs(source: R, ts: &TransferSyntax, cs: SpecificCharacterSet) -> Result<Self>
201    where
202        R: Read,
203    {
204        Self::new_with_ts_cs_options(source, ts, cs, Default::default())
205    }
206
207    /// Create a new iterator with the given stateful decoder and options.
208    pub fn new_with_ts_cs_options(
209        source: R,
210        ts: &TransferSyntax,
211        cs: SpecificCharacterSet,
212        options: DataSetReaderOptions,
213    ) -> Result<Self>
214    where
215        R: Read,
216    {
217        let parser = DynStatefulDecoder::new_with(source, ts, cs, 0).context(CreateDecoderSnafu)?;
218
219        is_stateful_decode(&parser);
220
221        Ok(DataSetReader {
222            parser,
223            options,
224            seq_delimiters: Vec::new(),
225            delimiter_check_pending: false,
226            offset_table_next: false,
227            in_sequence: false,
228            hard_break: false,
229            last_header: None,
230            peek: None,
231        })
232    }
233}
234
235impl<S> DataSetReader<S> {
236    /// Create a new iterator with the given stateful decoder and options.
237    pub fn new(decoder: S, options: DataSetReaderOptions) -> Self {
238        DataSetReader {
239            parser: decoder,
240            options,
241            seq_delimiters: Vec::new(),
242            delimiter_check_pending: false,
243            offset_table_next: false,
244            in_sequence: false,
245            hard_break: false,
246            last_header: None,
247            peek: None,
248        }
249    }
250}
251
252impl<S> Iterator for DataSetReader<S>
253where
254    S: StatefulDecode,
255{
256    type Item = Result<DataToken>;
257
258    fn next(&mut self) -> Option<Self::Item> {
259        if self.hard_break {
260            return None;
261        }
262        // if there was a peek, consume peeked token
263        if let Some(token) = self.peek.take() {
264            return Some(Ok(token));
265        }
266
267        // item or sequence delimitation logic for explicit lengths
268        if self.delimiter_check_pending {
269            match self.update_seq_delimiters() {
270                Err(e) => {
271                    self.hard_break = true;
272                    return Some(Err(e));
273                }
274                Ok(Some(token)) => return Some(Ok(token)),
275                Ok(None) => { /* no-op */ }
276            }
277        }
278
279        if self.in_sequence {
280            // at sequence level, expecting item header
281
282            match self.parser.decode_item_header() {
283                Ok(header) => {
284                    match header {
285                        SequenceItemHeader::Item { len } => {
286                            // entered a new item
287                            self.in_sequence = false;
288
289                            let last_delimiter = match self.seq_delimiters.last() {
290                                Some(d) => d,
291                                None => {
292                                    return Some(
293                                        UnexpectedItemHeaderSnafu {
294                                            bytes_read: self.parser.position(),
295                                        }
296                                        .fail(),
297                                    )
298                                }
299                            };
300                            self.push_sequence_token(
301                                SeqTokenType::Item,
302                                len,
303                                last_delimiter.pixel_data,
304                            );
305                            // items can be empty
306                            if len == Length(0) {
307                                self.delimiter_check_pending = true;
308                            }
309                            Some(Ok(DataToken::ItemStart { len }))
310                        }
311                        SequenceItemHeader::ItemDelimiter => {
312                            // closed an item
313                            self.seq_delimiters.pop();
314                            self.in_sequence = true;
315                            // sequences can end after an item delimiter
316                            self.delimiter_check_pending = true;
317                            Some(Ok(DataToken::ItemEnd))
318                        }
319                        SequenceItemHeader::SequenceDelimiter => {
320                            // closed a sequence
321                            self.seq_delimiters.pop();
322                            self.in_sequence = false;
323                            // items can end after a nested sequence ends
324                            self.delimiter_check_pending = true;
325                            Some(Ok(DataToken::SequenceEnd))
326                        }
327                    }
328                }
329                Err(e) => {
330                    self.hard_break = true;
331                    Some(Err(e).context(ReadItemHeaderSnafu))
332                }
333            }
334        } else if let Some(SeqToken {
335            typ: SeqTokenType::Item,
336            pixel_data: true,
337            len,
338            ..
339        }) = self.seq_delimiters.last()
340        {
341            let len = match len.get() {
342                Some(len) => len as usize,
343                None => return Some(UndefinedItemLengthSnafu.fail()),
344            };
345
346            if self.offset_table_next {
347                // offset table
348                let mut offset_table = Vec::with_capacity(len);
349
350                self.offset_table_next = false;
351
352                // need to pop item delimiter on the next iteration
353                self.delimiter_check_pending = true;
354
355                Some(
356                    match self.parser.read_u32_to_vec(len as u32, &mut offset_table) {
357                        Ok(()) => Ok(DataToken::OffsetTable(offset_table)),
358                        Err(e) => Err(e).context(ReadItemValueSnafu { len: len as u32 }),
359                    },
360                )
361            } else {
362                // item value
363                let mut value = Vec::with_capacity(len);
364
365                // need to pop item delimiter on the next iteration
366                self.delimiter_check_pending = true;
367                Some(
368                    self.parser
369                        .read_to_vec(len as u32, &mut value)
370                        .map(|_| Ok(DataToken::ItemValue(value)))
371                        .unwrap_or_else(|e| Err(e).context(ReadItemValueSnafu { len: len as u32 })),
372                )
373            }
374        } else if let Some(header) = self.last_header {
375            if header.is_encapsulated_pixeldata() {
376                self.push_sequence_token(SeqTokenType::Sequence, Length::UNDEFINED, true);
377                self.last_header = None;
378
379                // encapsulated pixel data, expecting offset table
380                match self.parser.decode_item_header() {
381                    Ok(header) => match header {
382                        SequenceItemHeader::Item { len } => {
383                            // entered a new item
384                            self.in_sequence = false;
385                            self.push_sequence_token(SeqTokenType::Item, len, true);
386                            // items can be empty
387                            if len == Length(0) {
388                                self.delimiter_check_pending = true;
389                            } else {
390                                self.offset_table_next = true;
391                            }
392                            Some(Ok(DataToken::ItemStart { len }))
393                        }
394                        SequenceItemHeader::SequenceDelimiter => {
395                            // empty pixel data
396                            self.seq_delimiters.pop();
397                            self.in_sequence = false;
398                            Some(Ok(DataToken::SequenceEnd))
399                        }
400                        item => {
401                            self.hard_break = true;
402                            Some(UnexpectedItemTagSnafu { tag: item.tag() }.fail())
403                        }
404                    },
405                    Err(e) => {
406                        self.hard_break = true;
407                        Some(Err(e).context(ReadItemHeaderSnafu))
408                    }
409                }
410            } else {
411                // a plain element header was read, so a value is expected
412                let value = match self.read_value(&header) {
413                    Ok(v) => v,
414                    Err(e) => {
415                        self.hard_break = true;
416                        self.last_header = None;
417                        return Some(Err(e));
418                    }
419                };
420
421                self.last_header = None;
422
423                // sequences can end after this token
424                self.delimiter_check_pending = true;
425
426                Some(Ok(DataToken::PrimitiveValue(value)))
427            }
428        } else {
429            // a data element header or item delimiter is expected
430            match self.parser.decode_header() {
431                Ok(DataElementHeader {
432                    tag,
433                    vr: VR::SQ,
434                    len,
435                }) => {
436                    self.in_sequence = true;
437                    self.push_sequence_token(SeqTokenType::Sequence, len, false);
438
439                    // sequences can end right after they start
440                    if len == Length(0) {
441                        self.delimiter_check_pending = true;
442                    }
443
444                    Some(Ok(DataToken::SequenceStart { tag, len }))
445                }
446                Ok(DataElementHeader {
447                    tag: Tag(0xFFFE, 0xE00D),
448                    ..
449                }) if self.seq_delimiters.is_empty() => {
450                    // ignore delimiter, we are not in a sequence
451                    tracing::warn!(
452                        "Item delimitation item outside of a sequence in position {}",
453                        self.parser.position()
454                    );
455                    // return a new token by calling the method again
456                    self.next()
457                }
458                Ok(DataElementHeader {
459                    tag: Tag(0xFFFE, 0xE00D),
460                    ..
461                }) => {
462                    self.in_sequence = true;
463                    // pop item delimiter
464                    self.seq_delimiters.pop();
465                    // sequences can end after this token
466                    self.delimiter_check_pending = true;
467                    Some(Ok(DataToken::ItemEnd))
468                }
469                Ok(header) if header.is_encapsulated_pixeldata() => {
470                    // encapsulated pixel data conditions:
471                    // expect a sequence of pixel data fragments
472
473                    // save it for the next step
474                    self.last_header = Some(header);
475                    Some(Ok(DataToken::PixelSequenceStart))
476                }
477                Ok(header) if header.len.is_undefined() => {
478                    // treat other undefined length elements
479                    // as data set sequences,
480                    // discarding the VR in the process
481                    self.in_sequence = true;
482
483                    let DataElementHeader { tag, len, .. } = header;
484                    self.push_sequence_token(SeqTokenType::Sequence, len, false);
485
486                    Some(Ok(DataToken::SequenceStart { tag, len }))
487                }
488                Ok(header) => {
489                    // save it for the next step
490                    self.last_header = Some(header);
491                    Some(Ok(DataToken::ElementHeader(header)))
492                }
493                Err(DecoderError::DecodeElementHeader {
494                    source: dicom_encoding::decode::Error::ReadHeaderTag { source, .. },
495                    ..
496                }) if source.kind() == std::io::ErrorKind::UnexpectedEof => {
497                    // Note: if `UnexpectedEof` was reached while trying to read
498                    // an element tag, then we assume that
499                    // the end of a DICOM object was reached gracefully.
500                    // This approach is unlikely to consume trailing bytes,
501                    // but may ignore the current depth of the data set tree.
502                    self.hard_break = true;
503                    None
504                }
505                Err(e) => {
506                    self.hard_break = true;
507                    Some(Err(e).context(ReadHeaderSnafu))
508                }
509            }
510        }
511    }
512}
513
514impl<S> DataSetReader<S>
515where
516    S: StatefulDecode,
517{
518    /// Peek the next token from the source by
519    /// reading a new token in the first call.
520    /// Subsequent calls to `peek` will return the same token
521    /// until another consumer method (such as `Iterator::next`)
522    /// is called.
523    pub fn peek(&mut self) -> Result<Option<&DataToken>> {
524        if self.peek.is_none() {
525            // try to read the next token
526            match self.next() {
527                None => return Ok(None),
528                Some(Err(e)) => return Err(e),
529                Some(Ok(token)) => {
530                    self.peek = Some(token);
531                }
532            }
533        }
534        Ok(self.peek.as_ref())
535    }
536
537    fn update_seq_delimiters(&mut self) -> Result<Option<DataToken>> {
538        if let Some(sd) = self.seq_delimiters.last() {
539            if let Some(len) = sd.len.get() {
540                let end_of_sequence = sd.base_offset + len as u64;
541                let bytes_read = self.parser.position();
542                match end_of_sequence.cmp(&bytes_read) {
543                    Ordering::Equal => {
544                        // end of delimiter, as indicated by the element's length
545                        let token;
546                        match sd.typ {
547                            SeqTokenType::Sequence => {
548                                self.in_sequence = false;
549                                token = DataToken::SequenceEnd;
550                            }
551                            SeqTokenType::Item => {
552                                self.in_sequence = true;
553                                token = DataToken::ItemEnd;
554                            }
555                        }
556                        self.seq_delimiters.pop();
557                        return Ok(Some(token));
558                    }
559                    Ordering::Less => {
560                        return InconsistentSequenceEndSnafu {
561                            end_of_sequence,
562                            bytes_read,
563                        }
564                        .fail();
565                    }
566                    Ordering::Greater => {} // continue normally
567                }
568            }
569        }
570        self.delimiter_check_pending = false;
571        Ok(None)
572    }
573
574    #[inline]
575    fn push_sequence_token(&mut self, typ: SeqTokenType, len: Length, pixel_data: bool) {
576        self.seq_delimiters.push(SeqToken {
577            typ,
578            pixel_data,
579            len,
580            base_offset: self.parser.position(),
581        })
582    }
583
584    fn read_value(&mut self, header: &DataElementHeader) -> Result<PrimitiveValue> {
585        match self.options.value_read {
586            ValueReadStrategy::Interpreted => self.parser.read_value(header),
587            ValueReadStrategy::Preserved => self.parser.read_value_preserved(header),
588            ValueReadStrategy::Raw => self.parser.read_value_bytes(header),
589        }
590        .context(ReadValueSnafu {
591            len: header.len.0,
592            tag: header.tag,
593        })
594    }
595}
596
597#[cfg(test)]
598mod tests {
599    use super::{DataSetReader, DataToken, StatefulDecode};
600    use crate::stateful::decode::StatefulDecoder;
601    use dicom_core::header::{DataElementHeader, Length};
602    use dicom_core::value::PrimitiveValue;
603    use dicom_core::{Tag, VR};
604    use dicom_encoding::decode::basic::LittleEndianBasicDecoder;
605    use dicom_encoding::decode::{
606        explicit_le::ExplicitVRLittleEndianDecoder, implicit_le::ImplicitVRLittleEndianDecoder,
607    };
608    use dicom_encoding::text::SpecificCharacterSet;
609
610    fn validate_dataset_reader_implicit_vr<I>(data: &[u8], ground_truth: I)
611    where
612        I: IntoIterator<Item = DataToken>,
613    {
614        let mut cursor = data;
615        let parser = StatefulDecoder::new(
616            &mut cursor,
617            ImplicitVRLittleEndianDecoder::default(),
618            LittleEndianBasicDecoder::default(),
619            SpecificCharacterSet::default(),
620        );
621
622        validate_dataset_reader(data, parser, ground_truth)
623    }
624
625    fn validate_dataset_reader_explicit_vr<I>(data: &[u8], ground_truth: I)
626    where
627        I: IntoIterator<Item = DataToken>,
628    {
629        let mut cursor = data;
630        let parser = StatefulDecoder::new(
631            &mut cursor,
632            ExplicitVRLittleEndianDecoder::default(),
633            LittleEndianBasicDecoder::default(),
634            SpecificCharacterSet::default(),
635        );
636
637        validate_dataset_reader(&data, parser, ground_truth)
638    }
639
640    fn validate_dataset_reader<I, D>(data: &[u8], parser: D, ground_truth: I)
641    where
642        I: IntoIterator<Item = DataToken>,
643        D: StatefulDecode,
644    {
645        let mut dset_reader = DataSetReader::new(parser, Default::default());
646
647        let iter = (&mut dset_reader).into_iter();
648        let mut ground_truth = ground_truth.into_iter();
649
650        while let Some(gt_token) = ground_truth.next() {
651            let token = iter
652                .next()
653                .expect("expecting more tokens from reader")
654                .expect("should fetch the next token without an error");
655            eprintln!("Next token: {:2?} ; Expected: {:2?}", token, gt_token);
656            assert_eq!(
657                token, gt_token,
658                "Got token {:2?} ; but expected {:2?}",
659                token, gt_token
660            );
661        }
662
663        let extra: Vec<_> = iter.collect();
664        assert_eq!(
665            extra.len(), // we have already read all of them
666            0,
667            "extraneous tokens remaining: {:?}",
668            extra,
669        );
670        assert_eq!(
671            dset_reader.parser.position(),
672            data.len() as u64,
673            "Decoder position did not match end of data",
674        );
675    }
676
677    #[test]
678    fn read_sequence_explicit() {
679        #[rustfmt::skip]
680        static DATA: &[u8] = &[
681            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
682            b'S', b'Q', // VR
683            0x00, 0x00, // reserved
684            0x2e, 0x00, 0x00, 0x00, // length: 28 + 18 = 46 (#= 2)
685            // -- 12 --
686            0xfe, 0xff, 0x00, 0xe0, // item start tag
687            0x14, 0x00, 0x00, 0x00, // item length: 20 (#= 2)
688            // -- 20 --
689            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
690            // -- 30 --
691            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
692            // -- 40 --
693            0xfe, 0xff, 0x00, 0xe0, // item start tag
694            0x0a, 0x00, 0x00, 0x00, // item length: 10 (#= 1)
695            // -- 48 --
696            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
697            // -- 58 --
698            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
699            b'T', b'E', b'S', b'T', // value = "TEST"
700        ];
701
702        let ground_truth = vec![
703            DataToken::SequenceStart {
704                tag: Tag(0x0018, 0x6011),
705                len: Length(46),
706            },
707            DataToken::ItemStart { len: Length(20) },
708            DataToken::ElementHeader(DataElementHeader {
709                tag: Tag(0x0018, 0x6012),
710                vr: VR::US,
711                len: Length(2),
712            }),
713            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
714            DataToken::ElementHeader(DataElementHeader {
715                tag: Tag(0x0018, 0x6014),
716                vr: VR::US,
717                len: Length(2),
718            }),
719            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
720            DataToken::ItemEnd,
721            DataToken::ItemStart { len: Length(10) },
722            DataToken::ElementHeader(DataElementHeader {
723                tag: Tag(0x0018, 0x6012),
724                vr: VR::US,
725                len: Length(2),
726            }),
727            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
728            DataToken::ItemEnd,
729            DataToken::SequenceEnd,
730            DataToken::ElementHeader(DataElementHeader {
731                tag: Tag(0x0020, 0x4000),
732                vr: VR::LT,
733                len: Length(4),
734            }),
735            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
736        ];
737
738        validate_dataset_reader_explicit_vr(DATA, ground_truth);
739    }
740
741    #[test]
742    fn read_sequence_explicit_2() {
743        static DATA: &[u8] = &[
744            // SequenceStart: (0008,2218) ; len = 54 (#=3)
745            0x08, 0x00, 0x18, 0x22, b'S', b'Q', 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
746            // -- 12, --
747            // ItemStart: len = 46
748            0xfe, 0xff, 0x00, 0xe0, 0x2e, 0x00, 0x00, 0x00,
749            // -- 20, --
750            // ElementHeader: (0008,0100) CodeValue; len = 8
751            0x08, 0x00, 0x00, 0x01, b'S', b'H', 0x08, 0x00, // PrimitiveValue
752            0x54, 0x2d, 0x44, 0x31, 0x32, 0x31, 0x33, b' ',
753            // -- 36, --
754            // ElementHeader: (0008,0102) CodingSchemeDesignator; len = 4
755            0x08, 0x00, 0x02, 0x01, b'S', b'H', 0x04, 0x00, // PrimitiveValue
756            0x53, 0x52, 0x54, b' ',
757            // -- 48, --
758            // (0008,0104) CodeMeaning; len = 10
759            0x08, 0x00, 0x04, 0x01, b'L', b'O', 0x0a, 0x00, // PrimitiveValue
760            0x4a, 0x61, 0x77, b' ', 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e,
761            // -- 66 --
762            // SequenceStart: (0040,0555) AcquisitionContextSequence; len = 0
763            0x40, 0x00, 0x55, 0x05, b'S', b'Q', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
764            // ElementHeader: (2050,0020) PresentationLUTShape; len = 8
765            0x50, 0x20, 0x20, 0x00, b'C', b'S', 0x08, 0x00, // PrimitiveValue
766            b'I', b'D', b'E', b'N', b'T', b'I', b'T', b'Y',
767        ];
768
769        let ground_truth = vec![
770            DataToken::SequenceStart {
771                tag: Tag(0x0008, 0x2218),
772                len: Length(54),
773            },
774            DataToken::ItemStart { len: Length(46) },
775            DataToken::ElementHeader(DataElementHeader {
776                tag: Tag(0x0008, 0x0100),
777                vr: VR::SH,
778                len: Length(8),
779            }),
780            DataToken::PrimitiveValue(PrimitiveValue::Strs(
781                ["T-D1213 ".to_owned()].as_ref().into(),
782            )),
783            DataToken::ElementHeader(DataElementHeader {
784                tag: Tag(0x0008, 0x0102),
785                vr: VR::SH,
786                len: Length(4),
787            }),
788            DataToken::PrimitiveValue(PrimitiveValue::Strs(["SRT ".to_owned()].as_ref().into())),
789            DataToken::ElementHeader(DataElementHeader {
790                tag: Tag(0x0008, 0x0104),
791                vr: VR::LO,
792                len: Length(10),
793            }),
794            DataToken::PrimitiveValue(PrimitiveValue::Strs(
795                ["Jaw region".to_owned()].as_ref().into(),
796            )),
797            DataToken::ItemEnd,
798            DataToken::SequenceEnd,
799            DataToken::SequenceStart {
800                tag: Tag(0x0040, 0x0555),
801                len: Length(0),
802            },
803            DataToken::SequenceEnd,
804            DataToken::ElementHeader(DataElementHeader {
805                tag: Tag(0x2050, 0x0020),
806                vr: VR::CS,
807                len: Length(8),
808            }),
809            DataToken::PrimitiveValue(PrimitiveValue::Strs(
810                ["IDENTITY".to_owned()].as_ref().into(),
811            )),
812        ];
813
814        validate_dataset_reader_explicit_vr(DATA, ground_truth);
815    }
816
817    #[test]
818    fn read_empty_sequence_explicit() {
819        static DATA: &[u8] = &[
820            // SequenceStart: (0008,1032) ProcedureCodeSequence ; len = 0
821            0x08, 0x00, 0x18, 0x22, // VR: SQ
822            b'S', b'Q', // Reserved
823            0x00, 0x00, // Length: 0
824            0x00, 0x00, 0x00, 0x00,
825        ];
826
827        let ground_truth = vec![
828            DataToken::SequenceStart {
829                tag: Tag(0x0008, 0x2218),
830                len: Length(0),
831            },
832            DataToken::SequenceEnd,
833        ];
834
835        validate_dataset_reader_explicit_vr(DATA, ground_truth);
836    }
837
838    /// Gracefully ignore a stray item end tag in the data set.
839    #[test]
840    fn ignore_trailing_item_delimitation_item() {
841        static DATA: &[u8] = &[
842            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04,
843            0x00, // (0020,4000) ImageComments, len = 4
844            b'T', b'E', b'S', b'T', // value = "TEST"
845            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
846        ];
847
848        let ground_truth = vec![
849            DataToken::ElementHeader(DataElementHeader {
850                tag: Tag(0x0020, 0x4000),
851                vr: VR::LT,
852                len: Length(4),
853            }),
854            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
855            // no item end
856        ];
857
858        validate_dataset_reader_explicit_vr(DATA, ground_truth);
859    }
860
861    #[test]
862    fn read_sequence_implicit() {
863        #[rustfmt::skip]
864        static DATA: &[u8] = &[
865            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
866            b'S', b'Q', // VR
867            0x00, 0x00, // reserved
868            0xff, 0xff, 0xff, 0xff, // length: undefined
869            // -- 12 --
870            0xfe, 0xff, 0x00, 0xe0, // item start tag
871            0xff, 0xff, 0xff, 0xff, // item length: undefined
872            // -- 20 --
873            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
874            // -- 30 --
875            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
876            // -- 40 --
877            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
878            // -- 48 --
879            0xfe, 0xff, 0x00, 0xe0, // item start tag
880            0xff, 0xff, 0xff, 0xff, // item length: undefined
881            // -- 56 --
882            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
883            // -- 66 --
884            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
885            // -- 74 --
886            0xfe, 0xff, 0xdd, 0xe0, 0x00, 0x00, 0x00, 0x00, // sequence end
887            // -- 82 --
888            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
889            b'T', b'E', b'S', b'T', // value = "TEST"
890        ];
891
892        let ground_truth = vec![
893            DataToken::SequenceStart {
894                tag: Tag(0x0018, 0x6011),
895                len: Length::UNDEFINED,
896            },
897            DataToken::ItemStart {
898                len: Length::UNDEFINED,
899            },
900            DataToken::ElementHeader(DataElementHeader {
901                tag: Tag(0x0018, 0x6012),
902                vr: VR::US,
903                len: Length(2),
904            }),
905            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
906            DataToken::ElementHeader(DataElementHeader {
907                tag: Tag(0x0018, 0x6014),
908                vr: VR::US,
909                len: Length(2),
910            }),
911            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
912            DataToken::ItemEnd,
913            DataToken::ItemStart {
914                len: Length::UNDEFINED,
915            },
916            DataToken::ElementHeader(DataElementHeader {
917                tag: Tag(0x0018, 0x6012),
918                vr: VR::US,
919                len: Length(2),
920            }),
921            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
922            DataToken::ItemEnd,
923            DataToken::SequenceEnd,
924            DataToken::ElementHeader(DataElementHeader {
925                tag: Tag(0x0020, 0x4000),
926                vr: VR::LT,
927                len: Length(4),
928            }),
929            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
930        ];
931
932        validate_dataset_reader_explicit_vr(DATA, ground_truth);
933    }
934
935    #[test]
936    fn read_implicit_len_sequence_implicit_vr_unknown() {
937        #[rustfmt::skip]
938        static DATA: &[u8] = &[
939            0x33, 0x55, 0x33, 0x55, // sequence tag: (5533,5533) «private, unknown attribute»
940            0xff, 0xff, 0xff, 0xff, // length: undefined
941            // -- 8 --
942            0xfe, 0xff, 0x00, 0xe0, // item begin
943            0xff, 0xff, 0xff, 0xff, // length: undefined
944            // -- 16 --
945            0xfe, 0xff, 0x0d, 0xe0, // item end
946            0x00, 0x00, 0x00, 0x00, // length is always zero
947            // -- 24 --
948            0xfe, 0xff, 0xdd, 0xe0,
949            0x00, 0x00, 0x00, 0x00, // sequence end
950            // -- 32 --
951        ];
952
953        let ground_truth = vec![
954            DataToken::SequenceStart {
955                tag: Tag(0x5533, 0x5533),
956                len: Length::UNDEFINED,
957            },
958            DataToken::ItemStart {
959                len: Length::UNDEFINED,
960            },
961            DataToken::ItemEnd,
962            DataToken::SequenceEnd,
963        ];
964
965        validate_dataset_reader_implicit_vr(DATA, ground_truth);
966    }
967
968    #[test]
969    fn read_encapsulated_pixeldata() {
970        #[rustfmt::skip]
971        static DATA: &[u8] = &[
972            0xe0, 0x7f, 0x10, 0x00, // (7FE0, 0010) PixelData
973            b'O', b'B', // VR 
974            0x00, 0x00, // reserved
975            0xff, 0xff, 0xff, 0xff, // length: undefined
976            // -- 12 -- Basic offset table
977            0xfe, 0xff, 0x00, 0xe0, // item start tag
978            0x00, 0x00, 0x00, 0x00, // item length: 0
979            // -- 20 -- First fragment of pixel data
980            0xfe, 0xff, 0x00, 0xe0, // item start tag
981            0x20, 0x00, 0x00, 0x00, // item length: 32
982            // -- 28 -- Compressed Fragment
983            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
984            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
985            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
986            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
987            // -- 60 -- End of pixel data
988            0xfe, 0xff, 0xdd, 0xe0, // sequence end tag
989            0x00, 0x00, 0x00, 0x00,
990            // -- 68 -- padding
991            0xfc, 0xff, 0xfc, 0xff, // (fffc,fffc) DataSetTrailingPadding
992            b'O', b'B', // VR
993            0x00, 0x00, // reserved
994            0x08, 0x00, 0x00, 0x00, // length: 8
995            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
996        ];
997
998        let ground_truth = vec![
999            DataToken::PixelSequenceStart,
1000            DataToken::ItemStart { len: Length(0) },
1001            DataToken::ItemEnd,
1002            DataToken::ItemStart { len: Length(32) },
1003            DataToken::ItemValue(vec![0x99; 32]),
1004            DataToken::ItemEnd,
1005            DataToken::SequenceEnd,
1006            DataToken::ElementHeader(DataElementHeader::new(
1007                Tag(0xfffc, 0xfffc),
1008                VR::OB,
1009                Length(8),
1010            )),
1011            DataToken::PrimitiveValue(PrimitiveValue::U8([0x00; 8].as_ref().into())),
1012        ];
1013
1014        validate_dataset_reader_explicit_vr(DATA, ground_truth);
1015    }
1016
1017    #[test]
1018    fn read_encapsulated_pixeldata_with_offset_table() {
1019        #[rustfmt::skip]
1020        static DATA: &[u8] = &[
1021            0xe0, 0x7f, 0x10, 0x00, // (7FE0, 0010) PixelData
1022            b'O', b'B', // VR 
1023            0x00, 0x00, // reserved
1024            0xff, 0xff, 0xff, 0xff, // length: undefined
1025            // -- 12 -- Basic offset table
1026            0xfe, 0xff, 0x00, 0xe0, // item start tag
1027            0x04, 0x00, 0x00, 0x00, // item length: 4
1028            // -- 20 -- item value
1029            0x10, 0x00, 0x00, 0x00, // 16
1030            // -- 24 -- First fragment of pixel data
1031            0xfe, 0xff, 0x00, 0xe0, // item start tag
1032            0x20, 0x00, 0x00, 0x00, // item length: 32
1033            // -- 32 -- Compressed Fragment
1034            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1035            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1036            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1037            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1038            // -- 60 -- End of pixel data
1039            0xfe, 0xff, 0xdd, 0xe0, // sequence end tag
1040            0x00, 0x00, 0x00, 0x00,
1041            // -- 68 -- padding
1042            0xfc, 0xff, 0xfc, 0xff, // (fffc,fffc) DataSetTrailingPadding
1043            b'O', b'B', // VR
1044            0x00, 0x00, // reserved
1045            0x08, 0x00, 0x00, 0x00, // length: 8
1046            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1047        ];
1048
1049        let ground_truth = vec![
1050            DataToken::PixelSequenceStart,
1051            DataToken::ItemStart { len: Length(4) },
1052            DataToken::OffsetTable(vec![16]),
1053            DataToken::ItemEnd,
1054            DataToken::ItemStart { len: Length(32) },
1055            DataToken::ItemValue(vec![0x99; 32]),
1056            DataToken::ItemEnd,
1057            DataToken::SequenceEnd,
1058            DataToken::ElementHeader(DataElementHeader::new(
1059                Tag(0xfffc, 0xfffc),
1060                VR::OB,
1061                Length(8),
1062            )),
1063            DataToken::PrimitiveValue(PrimitiveValue::U8([0x00; 8].as_ref().into())),
1064        ];
1065
1066        validate_dataset_reader_explicit_vr(DATA, ground_truth);
1067    }
1068
1069    #[test]
1070    fn read_dataset_in_dataset() {
1071        #[rustfmt::skip]
1072        const DATA: &'static [u8; 138] = &[
1073            // 0: (2001, 9000) private sequence
1074            0x01, 0x20, 0x00, 0x90, //
1075            // length: undefined
1076            0xFF, 0xFF, 0xFF, 0xFF, //
1077            // 8: Item start
1078            0xFE, 0xFF, 0x00, 0xE0, //
1079            // Item length explicit (114 bytes)
1080            0x72, 0x00, 0x00, 0x00, //
1081            // 16: (0008,1115) ReferencedSeriesSequence
1082            0x08, 0x00, 0x15, 0x11, //
1083            // length: undefined
1084            0xFF, 0xFF, 0xFF, 0xFF, //
1085            // 24: Item start
1086            0xFE, 0xFF, 0x00, 0xE0, //
1087            // Item length undefined
1088            0xFF, 0xFF, 0xFF, 0xFF, //
1089            // 32: (0008,1140) ReferencedImageSequence
1090            0x08, 0x00, 0x40, 0x11, //
1091            // length: undefined
1092            0xFF, 0xFF, 0xFF, 0xFF, //
1093            // 40: Item start
1094            0xFE, 0xFF, 0x00, 0xE0, //
1095            // Item length undefined
1096            0xFF, 0xFF, 0xFF, 0xFF, //
1097            // 48: (0008,1150) ReferencedSOPClassUID
1098            0x08, 0x00, 0x50, 0x11, //
1099            // length: 26
1100            0x1a, 0x00, 0x00, 0x00, //
1101            // Value: "1.2.840.10008.5.1.4.1.1.7\0" (SecondaryCaptureImageStorage)
1102            b'1', b'.', b'2', b'.', b'8', b'4', b'0', b'.', b'1', b'0', b'0', b'0', b'8', b'.',
1103            b'5', b'.', b'1', b'.', b'4', b'.', b'1', b'.', b'1', b'.', b'7', b'\0',
1104            // 82: Item End (ReferencedImageSequence)
1105            0xFE, 0xFF, 0x0D, 0xE0, //
1106            0x00, 0x00, 0x00, 0x00, //
1107            // 90: Sequence End (ReferencedImageSequence)
1108            0xFE, 0xFF, 0xDD, 0xE0, //
1109            0x00, 0x00, 0x00, 0x00, //
1110            // 98: Item End (ReferencedSeriesSequence)
1111            0xFE, 0xFF, 0x0D, 0xE0, //
1112            0x00, 0x00, 0x00, 0x00, //
1113            // 106: Sequence End (ReferencedSeriesSequence)
1114            0xFE, 0xFF, 0xDD, 0xE0, //
1115            0x00, 0x00, 0x00, 0x00, //
1116            // 114: (2050,0020) PresentationLUTShape (CS)
1117            0x50, 0x20, 0x20, 0x00, //
1118            // length: 8
1119            0x08, 0x00, 0x00, 0x00, //
1120            b'I', b'D', b'E', b'N', b'T', b'I', b'T', b'Y', //
1121            // 130: Sequence end
1122            0xFE, 0xFF, 0xDD, 0xE0, //
1123            0x00, 0x00, 0x00, 0x00, //
1124        ];
1125
1126        let ground_truth = vec![
1127            DataToken::SequenceStart {
1128                tag: Tag(0x2001, 0x9000),
1129                len: Length::UNDEFINED,
1130            },
1131            DataToken::ItemStart { len: Length(114) },
1132            DataToken::SequenceStart {
1133                tag: Tag(0x0008, 0x1115),
1134                len: Length::UNDEFINED,
1135            },
1136            DataToken::ItemStart {
1137                len: Length::UNDEFINED,
1138            },
1139            DataToken::SequenceStart {
1140                tag: Tag(0x0008, 0x1140),
1141                len: Length::UNDEFINED,
1142            },
1143            DataToken::ItemStart {
1144                len: Length::UNDEFINED,
1145            },
1146            DataToken::ElementHeader(DataElementHeader {
1147                tag: Tag(0x0008, 0x1150),
1148                vr: VR::UI,
1149                len: Length(26),
1150            }),
1151            DataToken::PrimitiveValue(PrimitiveValue::from("1.2.840.10008.5.1.4.1.1.7\0")),
1152            DataToken::ItemEnd,
1153            DataToken::SequenceEnd,
1154            DataToken::ItemEnd,
1155            DataToken::SequenceEnd,
1156            DataToken::ElementHeader(DataElementHeader {
1157                tag: Tag(0x2050, 0x0020),
1158                vr: VR::CS,
1159                len: Length(8),
1160            }),
1161            DataToken::PrimitiveValue(PrimitiveValue::from("IDENTITY")),
1162            DataToken::ItemEnd, // inserted automatically
1163            DataToken::SequenceEnd,
1164        ];
1165
1166        validate_dataset_reader_implicit_vr(DATA, ground_truth);
1167    }
1168
1169    #[test]
1170    fn peek_data_elements_implicit() {
1171        #[rustfmt::skip]
1172        static DATA: &[u8] = &[
1173            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
1174            b'S', b'Q', // VR
1175            0x00, 0x00, // reserved
1176            0xff, 0xff, 0xff, 0xff, // length: undefined
1177            // -- 12 --
1178            0xfe, 0xff, 0xdd, 0xe0, 0x00, 0x00, 0x00, 0x00, // sequence end
1179            // -- 82 --
1180            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
1181            b'T', b'E', b'S', b'T', // value = "TEST"
1182        ];
1183
1184        let ground_truth = vec![
1185            DataToken::SequenceStart {
1186                tag: Tag(0x0018, 0x6011),
1187                len: Length::UNDEFINED,
1188            },
1189            DataToken::SequenceEnd,
1190            DataToken::ElementHeader(DataElementHeader {
1191                tag: Tag(0x0020, 0x4000),
1192                vr: VR::LT,
1193                len: Length(4),
1194            }),
1195            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
1196        ];
1197
1198        let mut cursor = DATA;
1199        let parser = StatefulDecoder::new(
1200            &mut cursor,
1201            ExplicitVRLittleEndianDecoder::default(),
1202            LittleEndianBasicDecoder::default(),
1203            SpecificCharacterSet::default(),
1204        );
1205        let mut dset_reader = DataSetReader::new(parser, Default::default());
1206
1207        let iter = (&mut dset_reader).into_iter();
1208
1209        // peek at first token
1210        let token = iter.peek().expect("should peek first token OK");
1211        assert_eq!(token, Some(&ground_truth[0]));
1212
1213        // peeking multiple times gives the same result
1214        let token = iter.peek().expect("should peek first token again OK");
1215        assert_eq!(token, Some(&ground_truth[0]));
1216
1217        // Using `next` give us the same token
1218        let token = iter
1219            .next()
1220            .expect("expected token")
1221            .expect("should read token peeked OK");
1222        assert_eq!(&token, &ground_truth[0]);
1223
1224        // read some more tokens
1225
1226        // sequence end
1227        let token = iter.next().unwrap().unwrap();
1228        assert_eq!(&token, &ground_truth[1]);
1229        // data element header
1230        let token = iter.next().unwrap().unwrap();
1231        assert_eq!(&token, &ground_truth[2]);
1232
1233        // peek string value
1234        let token = iter.peek().unwrap();
1235        assert_eq!(token, Some(&ground_truth[3]));
1236        // peek it again
1237        let token = iter.peek().unwrap();
1238        assert_eq!(token, Some(&ground_truth[3]));
1239        // then read it
1240        let token = iter.next().unwrap().unwrap();
1241        assert_eq!(&token, &ground_truth[3]);
1242
1243        // finished reading, peek should return None
1244        assert!(iter.peek().unwrap().is_none());
1245    }
1246
1247    #[test]
1248    fn read_pixel_sequence_bad_item_end() {
1249        #[rustfmt::skip]
1250        static DATA: &[u8] = &[
1251            0xe0, 0x7f, 0x10, 0x00, // (7FE0, 0010) PixelData
1252            b'O', b'B', // VR 
1253            0x00, 0x00, // reserved
1254            0xff, 0xff, 0xff, 0xff, // length: undefined
1255            // -- 12 --
1256            0xfe, 0xff, 0x00, 0xe0, // item start tag
1257            0x00, 0x00, 0x00, 0x00, // item length: 0
1258            // -- 20 --
1259            0xfe, 0xff, 0x0d, 0xe0, // item end
1260            0x00, 0x00, 0x00, 0x00, // length is always zero
1261            // -- 28 --
1262            0xfe, 0xff, 0x0d, 0xe0, // another item end (bad)
1263            0x00, 0x00, 0x00, 0x00, //
1264            // -- 36 --
1265            0xfe, 0xff, 0x00, 0xe0, // another item start
1266            0x00, 0x00, 0x00, 0x00, // item length: 0
1267        ];
1268
1269        let mut cursor = DATA;
1270        let parser = StatefulDecoder::new(
1271            &mut cursor,
1272            ExplicitVRLittleEndianDecoder::default(),
1273            LittleEndianBasicDecoder::default(),
1274            SpecificCharacterSet::default(),
1275        );
1276        let mut dset_reader = DataSetReader::new(parser, Default::default());
1277
1278        let token_res = (&mut dset_reader)
1279            .into_iter()
1280            .collect::<Result<Vec<_>, _>>();
1281        dbg!(&token_res);
1282        assert!(token_res.is_err());
1283    }
1284}