Skip to main content

dicom_parser/dataset/
lazy_read.rs

1//! This module contains a mid-level abstraction for reading DICOM content
2//! sequentially and in a lazy fashion.
3//! That is, unlike the reader in the [`read`](super::read) module,
4//! DICOM values can be skipped and most allocations can be avoided.
5//!
6//! At this level, headers and values are treated as tokens which can be used
7//! to form a syntax tree of a full data set.
8//! Whenever an element value or pixel sequence item is encountered,
9//! the given token does not consume the value from the reader,
10//! thus letting users decide whether to:
11//! - fully read the value and turn it into an in-memory representation;
12//! - skip the value altogether, by reading into a sink;
13//! - copying the bytes of the value into another writer,
14//!   such as a previously allocated buffer.
15use crate::dataset::read::OddLengthStrategy;
16use crate::stateful::decode::{
17    CharacterSetOverride, DynStatefulDecoder, Error as DecoderError, StatefulDecode,
18};
19use crate::util::ReadSeek;
20use dicom_core::header::{DataElementHeader, Header, Length, SequenceItemHeader};
21use dicom_core::{Tag, VR};
22use dicom_encoding::text::SpecificCharacterSet;
23use dicom_encoding::transfer_syntax::TransferSyntax;
24use snafu::{Backtrace, OptionExt, ResultExt, Snafu};
25use std::cmp::Ordering;
26
27use super::{DataToken, LazyDataToken, SeqTokenType};
28
29#[derive(Debug, Snafu)]
30#[non_exhaustive]
31pub enum Error {
32    #[snafu(display("Could not create decoder"))]
33    CreateDecoder {
34        #[snafu(backtrace)]
35        source: DecoderError,
36    },
37    #[snafu(display("Could not read item header at {} bytes", bytes_read))]
38    ReadItemHeader {
39        bytes_read: u64,
40        #[snafu(backtrace)]
41        source: DecoderError,
42    },
43    #[snafu(display("Could not read element header at {} bytes", bytes_read))]
44    ReadHeader {
45        bytes_read: u64,
46        #[snafu(backtrace)]
47        source: DecoderError,
48    },
49    #[snafu(display("Could not read value"))]
50    ReadValue {
51        #[snafu(backtrace)]
52        source: DecoderError,
53    },
54    #[snafu(display("Failed to get reader position"))]
55    GetPosition {
56        source: std::io::Error,
57        backtrace: Backtrace,
58    },
59    #[snafu(display(
60        "Inconsistent sequence end: expected end at {} bytes but read {}",
61        end_of_sequence,
62        bytes_read
63    ))]
64    InconsistentSequenceEnd {
65        end_of_sequence: u64,
66        bytes_read: u64,
67        backtrace: Backtrace,
68    },
69    #[snafu(display("Unexpected item delimiter at {} bytes", bytes_read))]
70    UnexpectedItemDelimiter {
71        bytes_read: u64,
72        backtrace: Backtrace,
73    },
74    #[snafu(display("Unexpected undefined value length at {} bytes", bytes_read))]
75    UndefinedLength {
76        bytes_read: u64,
77        backtrace: Backtrace,
78    },
79
80    /// Invalid data element length {len:04X} of {tag} at {bytes_read:#x}
81    InvalidElementLength {
82        tag: Tag,
83        len: u32,
84        bytes_read: u64,
85        backtrace: Backtrace,
86    },
87
88    /// Invalid sequence item length {len:04X} at {bytes_read:#x}
89    InvalidItemLength {
90        len: u32,
91        bytes_read: u64,
92        backtrace: Backtrace,
93    },
94
95    #[snafu(display("Attempted to inspect a header at {} bytes", bytes_read))]
96    Peek {
97        bytes_read: u64,
98        backtrace: Backtrace,
99    },
100}
101
102pub type Result<T, E = Error> = std::result::Result<T, E>;
103
104/// A reader-specific token representing a sequence or item start.
105#[derive(Debug, Copy, Clone, PartialEq)]
106struct SeqToken {
107    /// Whether it is the start of a sequence or the start of an item.
108    typ: SeqTokenType,
109    /// The length of the value, as indicated by the starting element,
110    /// can be unknown.
111    len: Length,
112    /// Whether this sequence token is part of an encapsulated pixel data.
113    pixel_data: bool,
114    /// The number of bytes the parser has read until it reached the
115    /// beginning of the sequence or item value data.
116    base_offset: u64,
117}
118
119/// An attached iterator for retrieving DICOM object element markers
120/// from a random access data source.
121///
122/// This iterator produces data tokens without eagerly reading the bytes
123/// of a value.
124#[derive(Debug)]
125pub struct LazyDataSetReader<S> {
126    /// the stateful decoder
127    parser: S,
128    /// data set reading options
129    options: LazyDataSetReaderOptions,
130    /// whether the reader is expecting an item next (or a sequence delimiter)
131    in_sequence: bool,
132    /// whether a check for a sequence or item delimitation is pending
133    delimiter_check_pending: bool,
134    /// a stack of delimiters
135    seq_delimiters: Vec<SeqToken>,
136    /// fuse the iteration process if true
137    hard_break: bool,
138    /// last decoded header
139    last_header: Option<DataElementHeader>,
140    /// if a peek was taken, this holds the token peeked
141    peek: Option<DataToken>,
142}
143
144/// The set of options for the lazy data set reader.
145#[derive(Debug, Default, Copy, Clone, Eq, Hash, PartialEq)]
146#[non_exhaustive]
147pub struct LazyDataSetReaderOptions {
148    /// The strategy for handling odd length data elements
149    pub odd_length: OddLengthStrategy,
150
151    /// Override for how text is decoded
152    pub charset_override: CharacterSetOverride,
153}
154
155impl<R> LazyDataSetReader<DynStatefulDecoder<R>> {
156    /// Create a new lazy data set reader
157    /// expecting the given transfer syntax
158    /// that reads from the given random access source.
159    #[inline]
160    pub fn new_with_ts(source: R, ts: &TransferSyntax) -> Result<Self>
161    where
162        R: ReadSeek,
163    {
164        Self::new_with_ts_cs(source, ts, SpecificCharacterSet::default())
165    }
166
167    /// Create a new lazy data set reader
168    /// with the given random access source and element dictionary,
169    /// while considering the given transfer syntax and specific character set.
170    #[inline]
171    pub fn new_with_ts_cs(source: R, ts: &TransferSyntax, cs: SpecificCharacterSet) -> Result<Self>
172    where
173        R: ReadSeek,
174    {
175        Self::new_with_ts_cs_options(source, ts, cs, Default::default())
176    }
177
178    /// Create a new lazy data set reader
179    /// expecting the given transfer syntax
180    /// that reads from the given random access source,
181    /// with extra parsing options.
182    #[inline]
183    pub fn new_with_ts_options(
184        source: R,
185        ts: &TransferSyntax,
186        options: LazyDataSetReaderOptions,
187    ) -> Result<Self>
188    where
189        R: ReadSeek,
190    {
191        Self::new_with_ts_cs_options(source, ts, SpecificCharacterSet::default(), options)
192    }
193
194    /// Create a new lazy data set reader
195    /// with the given random access source and element dictionary,
196    /// while considering the given transfer syntax and specific character set.
197    pub fn new_with_ts_cs_options(
198        mut source: R,
199        ts: &TransferSyntax,
200        cs: SpecificCharacterSet,
201        options: LazyDataSetReaderOptions,
202    ) -> Result<Self>
203    where
204        R: ReadSeek,
205    {
206        let position = source.stream_position().context(GetPositionSnafu)?;
207        let parser = DynStatefulDecoder::new_with_override(
208            source,
209            ts,
210            cs,
211            options.charset_override,
212            position,
213        )
214        .context(CreateDecoderSnafu)?;
215
216        Ok(LazyDataSetReader {
217            parser,
218            options,
219            seq_delimiters: Vec::new(),
220            delimiter_check_pending: false,
221            in_sequence: false,
222            hard_break: false,
223            last_header: None,
224            peek: None,
225        })
226    }
227}
228
229impl<S> LazyDataSetReader<S>
230where
231    S: StatefulDecode,
232{
233    /// Create a new iterator with the given stateful decoder.
234    #[inline]
235    pub fn new(parser: S) -> Self {
236        LazyDataSetReader::new_with_options(parser, Default::default())
237    }
238
239    /// Create a new lazy data set reader
240    /// using the given stateful decoder,
241    /// with extra parsing options.
242    pub fn new_with_options(parser: S, options: LazyDataSetReaderOptions) -> Self
243    where
244        S: StatefulDecode,
245    {
246        LazyDataSetReader {
247            parser,
248            options,
249            seq_delimiters: Vec::new(),
250            delimiter_check_pending: false,
251            in_sequence: false,
252            hard_break: false,
253            last_header: None,
254            peek: None,
255        }
256    }
257}
258
259impl<S> LazyDataSetReader<S>
260where
261    S: StatefulDecode,
262{
263    fn update_seq_delimiters<'b>(&mut self) -> Result<Option<LazyDataToken<&'b mut S>>> {
264        if let Some(sd) = self.seq_delimiters.last() {
265            if let Some(len) = sd.len.get() {
266                let end_of_sequence = sd.base_offset + len as u64;
267                let bytes_read = self.parser.position();
268                match end_of_sequence.cmp(&bytes_read) {
269                    Ordering::Equal => {
270                        // end of delimiter, as indicated by the element's length
271                        let token;
272                        match sd.typ {
273                            SeqTokenType::Sequence => {
274                                self.in_sequence = false;
275                                token = LazyDataToken::SequenceEnd;
276                            }
277                            SeqTokenType::Item => {
278                                self.in_sequence = true;
279                                token = LazyDataToken::ItemEnd;
280                            }
281                        }
282                        self.seq_delimiters.pop();
283                        return Ok(Some(token));
284                    }
285                    Ordering::Less => {
286                        return InconsistentSequenceEndSnafu {
287                            end_of_sequence,
288                            bytes_read,
289                        }
290                        .fail();
291                    }
292                    Ordering::Greater => {} // continue normally
293                }
294            }
295        }
296        self.delimiter_check_pending = false;
297        Ok(None)
298    }
299
300    #[inline]
301    fn push_sequence_token(&mut self, typ: SeqTokenType, len: Length, pixel_data: bool) {
302        self.seq_delimiters.push(SeqToken {
303            typ,
304            pixel_data,
305            len,
306            base_offset: self.parser.position(),
307        })
308    }
309
310    /// Retrieve the inner stateful decoder from this data set reader.
311    pub fn into_decoder(self) -> S {
312        self.parser
313    }
314
315    /// Advance and retrieve the next DICOM data token.
316    ///
317    /// **Note:** For the data set to be successfully parsed,
318    /// the resulting data tokens needs to be consumed
319    /// if they are of a value type.
320    pub fn advance(&mut self) -> Option<Result<LazyDataToken<&mut S>>> {
321        if self.hard_break {
322            return None;
323        }
324
325        // if there was a peek, consume peeked token
326        if let Some(peek) = self.peek.take() {
327            let token = match peek {
328                DataToken::ElementHeader(header) => LazyDataToken::ElementHeader(header),
329                DataToken::SequenceStart { tag, len } => LazyDataToken::SequenceStart { tag, len },
330                DataToken::ItemStart { len } => LazyDataToken::ItemStart { len },
331                DataToken::ItemEnd => LazyDataToken::ItemEnd,
332                DataToken::SequenceEnd => LazyDataToken::SequenceEnd,
333                DataToken::PixelSequenceStart => LazyDataToken::PixelSequenceStart,
334                _ => unreachable!("peeked token should not be a value token"),
335            };
336            return Some(Ok(token));
337        }
338
339        // record the reading position before any further reading
340        let bytes_read = self.parser.position();
341
342        // item or sequence delimitation logic for explicit lengths
343        if self.delimiter_check_pending {
344            match self.update_seq_delimiters() {
345                Err(e) => {
346                    self.hard_break = true;
347                    return Some(Err(e));
348                }
349                Ok(Some(token)) => return Some(Ok(token)),
350                Ok(None) => { /* no-op */ }
351            }
352        }
353
354        if self.in_sequence {
355            // at sequence level, expecting item header
356
357            match self.parser.decode_item_header() {
358                Ok(header) => {
359                    match header {
360                        SequenceItemHeader::Item { len } => {
361                            // sanitize length
362                            let Some(len) = self.sanitize_length(len) else {
363                                return Some(
364                                    InvalidItemLengthSnafu {
365                                        len: len.0,
366                                        bytes_read: self.parser.position(),
367                                    }
368                                    .fail(),
369                                );
370                            };
371
372                            // entered a new item
373                            self.in_sequence = false;
374                            self.push_sequence_token(
375                                SeqTokenType::Item,
376                                len,
377                                self.seq_delimiters.last()
378                                    .expect("item header should be read only inside an existing sequence")
379                                    .pixel_data);
380                            // items can be empty
381                            if len == Length(0) {
382                                self.delimiter_check_pending = true;
383                            }
384                            Some(Ok(LazyDataToken::ItemStart { len }))
385                        }
386                        SequenceItemHeader::ItemDelimiter => {
387                            // closed an item
388                            self.seq_delimiters.pop();
389                            self.in_sequence = true;
390                            // sequences can end after an item delimiter
391                            self.delimiter_check_pending = true;
392                            Some(Ok(LazyDataToken::ItemEnd))
393                        }
394                        SequenceItemHeader::SequenceDelimiter => {
395                            // closed a sequence
396                            self.seq_delimiters.pop();
397                            self.in_sequence = false;
398                            // items can end after a nested sequence ends
399                            self.delimiter_check_pending = true;
400                            Some(Ok(LazyDataToken::SequenceEnd))
401                        }
402                    }
403                }
404                Err(e) => {
405                    self.hard_break = true;
406                    Some(Err(e).context(ReadItemHeaderSnafu { bytes_read }))
407                }
408            }
409        } else if let Some(SeqToken {
410            typ: SeqTokenType::Item,
411            pixel_data: true,
412            len,
413            ..
414        }) = self.seq_delimiters.last()
415        {
416            // item value
417
418            let Some(len) = self.sanitize_length(*len) else {
419                return Some(
420                    InvalidItemLengthSnafu {
421                        len: len.0,
422                        bytes_read: self.parser.position(),
423                    }
424                    .fail(),
425                );
426            };
427
428            let len = match len
429                .get()
430                .with_context(|| UndefinedLengthSnafu { bytes_read })
431            {
432                Ok(len) => len,
433                Err(e) => return Some(Err(e)),
434            };
435
436            // need to pop item delimiter on the next iteration
437            self.delimiter_check_pending = true;
438            Some(Ok(LazyDataToken::LazyItemValue {
439                len,
440                decoder: &mut self.parser,
441            }))
442        } else if let Some(header) = self.last_header {
443            if header.is_encapsulated_pixeldata() {
444                self.push_sequence_token(SeqTokenType::Sequence, Length::UNDEFINED, true);
445                self.last_header = None;
446
447                // encapsulated pixel data, expecting offset table
448                match self.parser.decode_item_header() {
449                    Ok(header) => match header {
450                        SequenceItemHeader::Item { len } => {
451                            // sanitize length
452                            let Some(len) = self.sanitize_length(len) else {
453                                return Some(
454                                    InvalidItemLengthSnafu {
455                                        len: len.0,
456                                        bytes_read: self.parser.position(),
457                                    }
458                                    .fail(),
459                                );
460                            };
461
462                            // entered a new item
463                            self.in_sequence = false;
464                            self.push_sequence_token(SeqTokenType::Item, len, true);
465                            // items can be empty
466                            if len == Length(0) {
467                                self.delimiter_check_pending = true;
468                            }
469                            Some(Ok(LazyDataToken::ItemStart { len }))
470                        }
471                        SequenceItemHeader::SequenceDelimiter => {
472                            // empty pixel data
473                            self.seq_delimiters.pop();
474                            self.in_sequence = false;
475                            Some(Ok(LazyDataToken::SequenceEnd))
476                        }
477                        SequenceItemHeader::ItemDelimiter => {
478                            self.hard_break = true;
479                            Some(UnexpectedItemDelimiterSnafu { bytes_read }.fail())
480                        }
481                    },
482                    Err(e) => {
483                        self.hard_break = true;
484                        Some(Err(e).context(ReadItemHeaderSnafu { bytes_read }))
485                    }
486                }
487            } else {
488                // a plain element header was read, so an element value is expected
489                self.last_header = None;
490
491                // sequences can end after this token
492                self.delimiter_check_pending = true;
493
494                Some(Ok(LazyDataToken::LazyValue {
495                    header,
496                    decoder: &mut self.parser,
497                }))
498            }
499        } else {
500            // a data element header or item delimiter is expected
501            match self.parser.decode_header() {
502                Ok(DataElementHeader {
503                    tag,
504                    vr: VR::SQ,
505                    len,
506                }) => {
507                    let Some(len) = self.sanitize_length(len) else {
508                        return Some(
509                            InvalidElementLengthSnafu {
510                                tag,
511                                len: len.0,
512                                bytes_read: self.parser.position(),
513                            }
514                            .fail(),
515                        );
516                    };
517
518                    self.in_sequence = true;
519                    self.push_sequence_token(SeqTokenType::Sequence, len, false);
520
521                    // sequences can end right after they start
522                    if len == Length(0) {
523                        self.delimiter_check_pending = true;
524                    }
525
526                    Some(Ok(LazyDataToken::SequenceStart { tag, len }))
527                }
528                Ok(DataElementHeader {
529                    tag: Tag(0xFFFE, 0xE00D),
530                    ..
531                }) => {
532                    self.in_sequence = true;
533                    // pop item delimiter
534                    self.seq_delimiters.pop();
535                    // sequences can end after this token
536                    self.delimiter_check_pending = true;
537                    Some(Ok(LazyDataToken::ItemEnd))
538                }
539                Ok(header) if header.is_encapsulated_pixeldata() => {
540                    // encapsulated pixel data conditions:
541                    // expect a sequence of pixel data fragments
542
543                    // save it for the next step
544                    self.last_header = Some(header);
545                    Some(Ok(LazyDataToken::PixelSequenceStart))
546                }
547                Ok(header) if header.len.is_undefined() => {
548                    // treat other undefined length elements
549                    // as data set sequences,
550                    // discarding the VR in the process
551                    self.in_sequence = true;
552
553                    let DataElementHeader { tag, len, .. } = header;
554                    self.push_sequence_token(SeqTokenType::Sequence, len, false);
555
556                    Some(Ok(LazyDataToken::SequenceStart { tag, len }))
557                }
558                Ok(mut header) => {
559                    // sanitize length
560                    let Some(len) = self.sanitize_length(header.len) else {
561                        return Some(
562                            InvalidElementLengthSnafu {
563                                tag: header.tag,
564                                len: header.len.0,
565                                bytes_read: self.parser.position(),
566                            }
567                            .fail(),
568                        );
569                    };
570                    header.len = len;
571
572                    // save it for the next step
573                    self.last_header = Some(header);
574                    Some(Ok(LazyDataToken::ElementHeader(header)))
575                }
576                Err(DecoderError::DecodeElementHeader {
577                    source: dicom_encoding::decode::Error::ReadHeaderTag { source, .. },
578                    ..
579                }) if source.kind() == std::io::ErrorKind::UnexpectedEof => {
580                    // Note: if `UnexpectedEof` was reached while trying to read
581                    // an element tag, then we assume that
582                    // the end of a DICOM object was reached gracefully.
583                    // This approach is unlikely to consume trailing bytes,
584                    // but may ignore the current depth of the data set tree.
585                    self.hard_break = true;
586                    None
587                }
588                Err(e) => {
589                    self.hard_break = true;
590                    Some(Err(e).context(ReadHeaderSnafu { bytes_read }))
591                }
592            }
593        }
594    }
595
596    /// Peek the next token from the source by
597    /// reading a new token in the first call.
598    /// Subsequent calls to `peek` will return the same token
599    /// until another consumer method is called.
600    ///
601    /// Peeking only works in a data or item element boundary,
602    /// so the returned data token is either an element header or an item header.
603    /// At the moment, a failed peek will result in a hard break,
604    /// preventing further iteration.
605    pub fn peek(&mut self) -> Result<Option<&DataToken>> {
606        if self.peek.is_none() {
607            // try to read the next token
608            match self.advance() {
609                None => return Ok(None),
610                Some(Err(e)) => return Err(e),
611                Some(Ok(token)) => match token {
612                    LazyDataToken::ElementHeader(header) => {
613                        self.peek = Some(DataToken::ElementHeader(header));
614                    }
615                    LazyDataToken::SequenceStart { tag, len } => {
616                        self.peek = Some(DataToken::SequenceStart { tag, len });
617                    }
618                    LazyDataToken::ItemStart { len } => {
619                        self.peek = Some(DataToken::ItemStart { len });
620                    }
621                    LazyDataToken::ItemEnd => {
622                        self.peek = Some(DataToken::ItemEnd);
623                    }
624                    LazyDataToken::SequenceEnd => {
625                        self.peek = Some(DataToken::SequenceEnd);
626                    }
627                    LazyDataToken::PixelSequenceStart => {
628                        self.peek = Some(DataToken::PixelSequenceStart);
629                    }
630                    _ => {
631                        self.hard_break = true;
632                        return PeekSnafu {
633                            bytes_read: self.parser.position(),
634                        }
635                        .fail();
636                    }
637                },
638            }
639        }
640        Ok(self.peek.as_ref())
641    }
642
643    /// Check for a non-compliant length
644    /// and handle it according to the current strategy.
645    /// Returns `None` if the length cannot or should not be resolved.
646    fn sanitize_length(&self, length: Length) -> Option<Length> {
647        if length.is_defined() && length.0 & 1 != 0 {
648            match self.options.odd_length {
649                OddLengthStrategy::Accept => Some(length),
650                OddLengthStrategy::NextEven => Some(length + 1),
651                OddLengthStrategy::Fail => None,
652            }
653        } else {
654            Some(length)
655        }
656    }
657}
658
659#[cfg(test)]
660mod tests {
661    use super::{LazyDataSetReader, StatefulDecode};
662    use crate::{
663        dataset::{
664            lazy_read::LazyDataSetReaderOptions, read::OddLengthStrategy, DataToken, LazyDataToken,
665        },
666        StatefulDecoder,
667    };
668    use dicom_core::value::PrimitiveValue;
669    use dicom_core::{
670        dicom_value,
671        header::{DataElementHeader, Length},
672    };
673    use dicom_core::{Tag, VR};
674    use dicom_encoding::decode::{
675        explicit_le::ExplicitVRLittleEndianDecoder, implicit_le::ImplicitVRLittleEndianDecoder,
676    };
677    use dicom_encoding::{decode::basic::LittleEndianBasicDecoder, text::SpecificCharacterSet};
678
679    fn validate_dataset_reader_implicit_vr<I>(data: &[u8], ground_truth: I)
680    where
681        I: IntoIterator<Item = DataToken>,
682    {
683        let mut cursor = data;
684        let parser = StatefulDecoder::new(
685            &mut cursor,
686            ImplicitVRLittleEndianDecoder::default(),
687            LittleEndianBasicDecoder,
688            SpecificCharacterSet::default(),
689        );
690
691        validate_dataset_reader(data, parser, ground_truth)
692    }
693
694    fn validate_dataset_reader_explicit_vr<I>(data: &[u8], ground_truth: I)
695    where
696        I: IntoIterator<Item = DataToken>,
697    {
698        let mut cursor = data;
699        let parser = StatefulDecoder::new(
700            &mut cursor,
701            ExplicitVRLittleEndianDecoder::default(),
702            LittleEndianBasicDecoder,
703            SpecificCharacterSet::default(),
704        );
705
706        validate_dataset_reader(data, parser, ground_truth)
707    }
708
709    fn validate_dataset_reader<I, D>(data: &[u8], parser: D, ground_truth: I)
710    where
711        I: IntoIterator<Item = DataToken>,
712        D: StatefulDecode,
713    {
714        let mut dset_reader = LazyDataSetReader::new(parser);
715
716        let mut gt_iter = ground_truth.into_iter();
717        while let Some(res) = dset_reader.advance() {
718            let gt_token = gt_iter.next().expect("ground truth is shorter");
719            let token = res.expect("should parse without an error");
720            let token = token.into_owned().unwrap();
721            assert_eq!(token, gt_token);
722        }
723
724        assert_eq!(
725            gt_iter.count(), // consume til the end
726            0,               // we have already read all of them
727            "unexpected number of tokens remaining"
728        );
729        assert_eq!(dset_reader.parser.position(), data.len() as u64);
730    }
731
732    #[test]
733    fn lazy_read_sequence_explicit() {
734        #[rustfmt::skip]
735        static DATA: &[u8] = &[
736            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
737            b'S', b'Q', // VR
738            0x00, 0x00, // reserved
739            0x2e, 0x00, 0x00, 0x00, // length: 28 + 18 = 46 (#= 2)
740            // -- 12 --
741            0xfe, 0xff, 0x00, 0xe0, // item start tag
742            0x14, 0x00, 0x00, 0x00, // item length: 20 (#= 2)
743            // -- 20 --
744            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
745            // -- 30 --
746            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
747            // -- 40 --
748            0xfe, 0xff, 0x00, 0xe0, // item start tag
749            0x0a, 0x00, 0x00, 0x00, // item length: 10 (#= 1)
750            // -- 48 --
751            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
752            // -- 58 --
753            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
754            b'T', b'E', b'S', b'T', // value = "TEST"
755        ];
756
757        let ground_truth = vec![
758            DataToken::SequenceStart {
759                tag: Tag(0x0018, 0x6011),
760                len: Length(46),
761            },
762            DataToken::ItemStart { len: Length(20) },
763            DataToken::ElementHeader(DataElementHeader {
764                tag: Tag(0x0018, 0x6012),
765                vr: VR::US,
766                len: Length(2),
767            }),
768            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
769            DataToken::ElementHeader(DataElementHeader {
770                tag: Tag(0x0018, 0x6014),
771                vr: VR::US,
772                len: Length(2),
773            }),
774            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
775            DataToken::ItemEnd,
776            DataToken::ItemStart { len: Length(10) },
777            DataToken::ElementHeader(DataElementHeader {
778                tag: Tag(0x0018, 0x6012),
779                vr: VR::US,
780                len: Length(2),
781            }),
782            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
783            DataToken::ItemEnd,
784            DataToken::SequenceEnd,
785            DataToken::ElementHeader(DataElementHeader {
786                tag: Tag(0x0020, 0x4000),
787                vr: VR::LT,
788                len: Length(4),
789            }),
790            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
791        ];
792
793        validate_dataset_reader_explicit_vr(DATA, ground_truth);
794    }
795
796    #[test]
797    fn lazy_read_sequence_explicit_2() {
798        static DATA: &[u8] = &[
799            // SequenceStart: (0008,2218) ; len = 54 (#=3)
800            0x08, 0x00, 0x18, 0x22, b'S', b'Q', 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
801            // -- 12, --
802            // ItemStart: len = 46
803            0xfe, 0xff, 0x00, 0xe0, 0x2e, 0x00, 0x00, 0x00,
804            // -- 20, --
805            // ElementHeader: (0008,0100) CodeValue; len = 8
806            0x08, 0x00, 0x00, 0x01, b'S', b'H', 0x08, 0x00, // PrimitiveValue
807            0x54, 0x2d, 0x44, 0x31, 0x32, 0x31, 0x33, b' ',
808            // -- 36, --
809            // ElementHeader: (0008,0102) CodingSchemeDesignator; len = 4
810            0x08, 0x00, 0x02, 0x01, b'S', b'H', 0x04, 0x00, // PrimitiveValue
811            0x53, 0x52, 0x54, b' ',
812            // -- 48, --
813            // (0008,0104) CodeMeaning; len = 10
814            0x08, 0x00, 0x04, 0x01, b'L', b'O', 0x0a, 0x00, // PrimitiveValue
815            0x4a, 0x61, 0x77, b' ', 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e,
816            // -- 66 --
817            // SequenceStart: (0040,0555) AcquisitionContextSequence; len = 0
818            0x40, 0x00, 0x55, 0x05, b'S', b'Q', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
819            // ElementHeader: (2050,0020) PresentationLUTShape; len = 8
820            0x50, 0x20, 0x20, 0x00, b'C', b'S', 0x08, 0x00, // PrimitiveValue
821            b'I', b'D', b'E', b'N', b'T', b'I', b'T', b'Y',
822        ];
823
824        let ground_truth = vec![
825            DataToken::SequenceStart {
826                tag: Tag(0x0008, 0x2218),
827                len: Length(54),
828            },
829            DataToken::ItemStart { len: Length(46) },
830            DataToken::ElementHeader(DataElementHeader {
831                tag: Tag(0x0008, 0x0100),
832                vr: VR::SH,
833                len: Length(8),
834            }),
835            DataToken::PrimitiveValue(PrimitiveValue::Strs(
836                ["T-D1213 ".to_owned()].as_ref().into(),
837            )),
838            DataToken::ElementHeader(DataElementHeader {
839                tag: Tag(0x0008, 0x0102),
840                vr: VR::SH,
841                len: Length(4),
842            }),
843            DataToken::PrimitiveValue(PrimitiveValue::Strs(["SRT ".to_owned()].as_ref().into())),
844            DataToken::ElementHeader(DataElementHeader {
845                tag: Tag(0x0008, 0x0104),
846                vr: VR::LO,
847                len: Length(10),
848            }),
849            DataToken::PrimitiveValue(PrimitiveValue::Strs(
850                ["Jaw region".to_owned()].as_ref().into(),
851            )),
852            DataToken::ItemEnd,
853            DataToken::SequenceEnd,
854            DataToken::SequenceStart {
855                tag: Tag(0x0040, 0x0555),
856                len: Length(0),
857            },
858            DataToken::SequenceEnd,
859            DataToken::ElementHeader(DataElementHeader {
860                tag: Tag(0x2050, 0x0020),
861                vr: VR::CS,
862                len: Length(8),
863            }),
864            DataToken::PrimitiveValue(PrimitiveValue::Strs(
865                ["IDENTITY".to_owned()].as_ref().into(),
866            )),
867        ];
868
869        validate_dataset_reader_explicit_vr(DATA, ground_truth);
870    }
871
872    #[test]
873    fn lazy_read_sequence_implicit() {
874        #[rustfmt::skip]
875        static DATA: &[u8] = &[
876            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
877            b'S', b'Q', // VR
878            0x00, 0x00, // reserved
879            0xff, 0xff, 0xff, 0xff, // length: undefined
880            // -- 12 --
881            0xfe, 0xff, 0x00, 0xe0, // item start tag
882            0xff, 0xff, 0xff, 0xff, // item length: undefined
883            // -- 20 --
884            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x01, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 1
885            // -- 30 --
886            0x18, 0x00, 0x14, 0x60, b'U', b'S', 0x02, 0x00, 0x02, 0x00, // (0018, 6012) RegionDataType, len = 2, value = 2
887            // -- 40 --
888            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
889            // -- 48 --
890            0xfe, 0xff, 0x00, 0xe0, // item start tag
891            0xff, 0xff, 0xff, 0xff, // item length: undefined
892            // -- 56 --
893            0x18, 0x00, 0x12, 0x60, b'U', b'S', 0x02, 0x00, 0x04, 0x00, // (0018, 6012) RegionSpatialformat, len = 2, value = 4
894            // -- 66 --
895            0xfe, 0xff, 0x0d, 0xe0, 0x00, 0x00, 0x00, 0x00, // item end
896            // -- 74 --
897            0xfe, 0xff, 0xdd, 0xe0, 0x00, 0x00, 0x00, 0x00, // sequence end
898            // -- 82 --
899            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
900            b'T', b'E', b'S', b'T', // value = "TEST"
901        ];
902
903        let ground_truth = vec![
904            DataToken::SequenceStart {
905                tag: Tag(0x0018, 0x6011),
906                len: Length::UNDEFINED,
907            },
908            DataToken::ItemStart {
909                len: Length::UNDEFINED,
910            },
911            DataToken::ElementHeader(DataElementHeader {
912                tag: Tag(0x0018, 0x6012),
913                vr: VR::US,
914                len: Length(2),
915            }),
916            DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
917            DataToken::ElementHeader(DataElementHeader {
918                tag: Tag(0x0018, 0x6014),
919                vr: VR::US,
920                len: Length(2),
921            }),
922            DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
923            DataToken::ItemEnd,
924            DataToken::ItemStart {
925                len: Length::UNDEFINED,
926            },
927            DataToken::ElementHeader(DataElementHeader {
928                tag: Tag(0x0018, 0x6012),
929                vr: VR::US,
930                len: Length(2),
931            }),
932            DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
933            DataToken::ItemEnd,
934            DataToken::SequenceEnd,
935            DataToken::ElementHeader(DataElementHeader {
936                tag: Tag(0x0020, 0x4000),
937                vr: VR::LT,
938                len: Length(4),
939            }),
940            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
941        ];
942
943        validate_dataset_reader_explicit_vr(DATA, ground_truth);
944    }
945
946    #[test]
947    fn lazy_read_dataset_in_dataset() {
948        #[rustfmt::skip]
949        const DATA: &[u8; 138] = &[
950            // 0: (2001, 9000) private sequence
951            0x01, 0x20, 0x00, 0x90, //
952            // length: undefined
953            0xFF, 0xFF, 0xFF, 0xFF, //
954            // 8: Item start
955            0xFE, 0xFF, 0x00, 0xE0, //
956            // Item length explicit (114 bytes)
957            0x72, 0x00, 0x00, 0x00, //
958            // 16: (0008,1115) ReferencedSeriesSequence
959            0x08, 0x00, 0x15, 0x11, //
960            // length: undefined
961            0xFF, 0xFF, 0xFF, 0xFF, //
962            // 24: Item start
963            0xFE, 0xFF, 0x00, 0xE0, //
964            // Item length undefined
965            0xFF, 0xFF, 0xFF, 0xFF, //
966            // 32: (0008,1140) ReferencedImageSequence
967            0x08, 0x00, 0x40, 0x11, //
968            // length: undefined
969            0xFF, 0xFF, 0xFF, 0xFF, //
970            // 40: Item start
971            0xFE, 0xFF, 0x00, 0xE0, //
972            // Item length undefined
973            0xFF, 0xFF, 0xFF, 0xFF, //
974            // 48: (0008,1150) ReferencedSOPClassUID
975            0x08, 0x00, 0x50, 0x11, //
976            // length: 26
977            0x1a, 0x00, 0x00, 0x00, //
978            // Value: "1.2.840.10008.5.1.4.1.1.7\0" (SecondaryCaptureImageStorage)
979            b'1', b'.', b'2', b'.', b'8', b'4', b'0', b'.', b'1', b'0', b'0', b'0', b'8', b'.',
980            b'5', b'.', b'1', b'.', b'4', b'.', b'1', b'.', b'1', b'.', b'7', b'\0',
981            // 82: Item End (ReferencedImageSequence)
982            0xFE, 0xFF, 0x0D, 0xE0, //
983            0x00, 0x00, 0x00, 0x00, //
984            // 90: Sequence End (ReferencedImageSequence)
985            0xFE, 0xFF, 0xDD, 0xE0, //
986            0x00, 0x00, 0x00, 0x00, //
987            // 98: Item End (ReferencedSeriesSequence)
988            0xFE, 0xFF, 0x0D, 0xE0, //
989            0x00, 0x00, 0x00, 0x00, //
990            // 106: Sequence End (ReferencedSeriesSequence)
991            0xFE, 0xFF, 0xDD, 0xE0, //
992            0x00, 0x00, 0x00, 0x00, //
993            // 114: (2050,0020) PresentationLUTShape (CS)
994            0x50, 0x20, 0x20, 0x00, //
995            // length: 8
996            0x08, 0x00, 0x00, 0x00, //
997            b'I', b'D', b'E', b'N', b'T', b'I', b'T', b'Y', //
998            // 130: Sequence end
999            0xFE, 0xFF, 0xDD, 0xE0, //
1000            0x00, 0x00, 0x00, 0x00, //
1001        ];
1002
1003        let ground_truth = vec![
1004            DataToken::SequenceStart {
1005                tag: Tag(0x2001, 0x9000),
1006                len: Length::UNDEFINED,
1007            },
1008            DataToken::ItemStart { len: Length(114) },
1009            DataToken::SequenceStart {
1010                tag: Tag(0x0008, 0x1115),
1011                len: Length::UNDEFINED,
1012            },
1013            DataToken::ItemStart {
1014                len: Length::UNDEFINED,
1015            },
1016            DataToken::SequenceStart {
1017                tag: Tag(0x0008, 0x1140),
1018                len: Length::UNDEFINED,
1019            },
1020            DataToken::ItemStart {
1021                len: Length::UNDEFINED,
1022            },
1023            DataToken::ElementHeader(DataElementHeader {
1024                tag: Tag(0x0008, 0x1150),
1025                vr: VR::UI,
1026                len: Length(26),
1027            }),
1028            DataToken::PrimitiveValue(PrimitiveValue::from("1.2.840.10008.5.1.4.1.1.7\0")),
1029            DataToken::ItemEnd,
1030            DataToken::SequenceEnd,
1031            DataToken::ItemEnd,
1032            DataToken::SequenceEnd,
1033            DataToken::ElementHeader(DataElementHeader {
1034                tag: Tag(0x2050, 0x0020),
1035                vr: VR::CS,
1036                len: Length(8),
1037            }),
1038            DataToken::PrimitiveValue(PrimitiveValue::from("IDENTITY")),
1039            DataToken::ItemEnd, // inserted automatically
1040            DataToken::SequenceEnd,
1041        ];
1042
1043        validate_dataset_reader_implicit_vr(DATA, ground_truth);
1044    }
1045
1046    #[test]
1047    fn lazy_read_implicit_len_sequence_implicit_vr_unknown() {
1048        #[rustfmt::skip]
1049        static DATA: &[u8] = &[
1050            0x33, 0x55, 0x33, 0x55, // sequence tag: (5533,5533) «private, unknown attribute»
1051            0xff, 0xff, 0xff, 0xff, // length: undefined
1052            // -- 8 --
1053            0xfe, 0xff, 0x00, 0xe0, // item begin
1054            0xff, 0xff, 0xff, 0xff, // length: undefined
1055            // -- 16 --
1056            0xfe, 0xff, 0x0d, 0xe0, // item end
1057            0x00, 0x00, 0x00, 0x00, // length is always zero
1058            // -- 24 --
1059            0xfe, 0xff, 0xdd, 0xe0,
1060            0x00, 0x00, 0x00, 0x00, // sequence end
1061            // -- 32 --
1062        ];
1063
1064        let ground_truth = vec![
1065            DataToken::SequenceStart {
1066                tag: Tag(0x5533, 0x5533),
1067                len: Length::UNDEFINED,
1068            },
1069            DataToken::ItemStart {
1070                len: Length::UNDEFINED,
1071            },
1072            DataToken::ItemEnd,
1073            DataToken::SequenceEnd,
1074        ];
1075
1076        validate_dataset_reader_implicit_vr(DATA, ground_truth);
1077    }
1078
1079    #[test]
1080    fn read_encapsulated_pixeldata() {
1081        #[rustfmt::skip]
1082        static DATA: &[u8] = &[
1083            0xe0, 0x7f, 0x10, 0x00, // (7FE0, 0010) PixelData
1084            b'O', b'B', // VR 
1085            0x00, 0x00, // reserved
1086            0xff, 0xff, 0xff, 0xff, // length: undefined
1087            // -- 12 -- Basic offset table
1088            0xfe, 0xff, 0x00, 0xe0, // item start tag
1089            0x00, 0x00, 0x00, 0x00, // item length: 0
1090            // -- 20 -- First fragment of pixel data
1091            0xfe, 0xff, 0x00, 0xe0, // item start tag
1092            0x20, 0x00, 0x00, 0x00, // item length: 32
1093            // -- 28 -- Compressed Fragment
1094            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1095            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1096            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1097            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1098            // -- 60 -- End of pixel data
1099            0xfe, 0xff, 0xdd, 0xe0, // sequence end tag
1100            0x00, 0x00, 0x00, 0x00,
1101            // -- 68 -- padding
1102            0xfc, 0xff, 0xfc, 0xff, // (fffc,fffc) DataSetTrailingPadding
1103            b'O', b'B', // VR
1104            0x00, 0x00, // reserved
1105            0x08, 0x00, 0x00, 0x00, // length: 8
1106            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1107        ];
1108
1109        let ground_truth = vec![
1110            DataToken::PixelSequenceStart,
1111            DataToken::ItemStart { len: Length(0) },
1112            DataToken::ItemEnd,
1113            DataToken::ItemStart { len: Length(32) },
1114            DataToken::ItemValue(vec![0x99; 32]),
1115            DataToken::ItemEnd,
1116            DataToken::SequenceEnd,
1117            DataToken::ElementHeader(DataElementHeader::new(
1118                Tag(0xfffc, 0xfffc),
1119                VR::OB,
1120                Length(8),
1121            )),
1122            DataToken::PrimitiveValue(PrimitiveValue::U8([0x00; 8].as_ref().into())),
1123        ];
1124
1125        validate_dataset_reader_explicit_vr(DATA, ground_truth);
1126    }
1127
1128    #[test]
1129    fn lazy_read_encapsulated_pixeldata_with_offset_table() {
1130        #[rustfmt::skip]
1131        static DATA: &[u8] = &[
1132            0xe0, 0x7f, 0x10, 0x00, // (7FE0, 0010) PixelData
1133            b'O', b'B', // VR 
1134            0x00, 0x00, // reserved
1135            0xff, 0xff, 0xff, 0xff, // length: undefined
1136            // -- 12 -- Basic offset table
1137            0xfe, 0xff, 0x00, 0xe0, // item start tag
1138            0x04, 0x00, 0x00, 0x00, // item length: 4
1139            // -- 20 -- item value
1140            0x10, 0x00, 0x00, 0x00, // 16
1141            // -- 24 -- First fragment of pixel data
1142            0xfe, 0xff, 0x00, 0xe0, // item start tag
1143            0x20, 0x00, 0x00, 0x00, // item length: 32
1144            // -- 32 -- Compressed Fragment
1145            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1146            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1147            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1148            0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99, 0x99,
1149            // -- 60 -- End of pixel data
1150            0xfe, 0xff, 0xdd, 0xe0, // sequence end tag
1151            0x00, 0x00, 0x00, 0x00,
1152            // -- 68 -- padding
1153            0xfc, 0xff, 0xfc, 0xff, // (fffc,fffc) DataSetTrailingPadding
1154            b'O', b'B', // VR
1155            0x00, 0x00, // reserved
1156            0x08, 0x00, 0x00, 0x00, // length: 8
1157            0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1158        ];
1159
1160        let ground_truth = vec![
1161            DataToken::PixelSequenceStart,
1162            DataToken::ItemStart { len: Length(4) },
1163            DataToken::ItemValue(vec![0x10, 0x00, 0x00, 0x00]),
1164            DataToken::ItemEnd,
1165            DataToken::ItemStart { len: Length(32) },
1166            DataToken::ItemValue(vec![0x99; 32]),
1167            DataToken::ItemEnd,
1168            DataToken::SequenceEnd,
1169            DataToken::ElementHeader(DataElementHeader::new(
1170                Tag(0xfffc, 0xfffc),
1171                VR::OB,
1172                Length(8),
1173            )),
1174            DataToken::PrimitiveValue(PrimitiveValue::U8([0x00; 8].as_ref().into())),
1175        ];
1176
1177        validate_dataset_reader_explicit_vr(DATA, ground_truth);
1178    }
1179
1180    #[test]
1181    fn lazy_read_sequence_explicit_2_skip_values() {
1182        static DATA: &[u8] = &[
1183            // SequenceStart: (0008,2218) ; len = 54 (#=3)
1184            0x08, 0x00, 0x18, 0x22, b'S', b'Q', 0x00, 0x00, 0x36, 0x00, 0x00, 0x00,
1185            // -- 12, --
1186            // ItemStart: len = 46
1187            0xfe, 0xff, 0x00, 0xe0, 0x2e, 0x00, 0x00, 0x00,
1188            // -- 20, --
1189            // ElementHeader: (0008,0100) CodeValue; len = 8
1190            0x08, 0x00, 0x00, 0x01, b'S', b'H', 0x08, 0x00, // PrimitiveValue
1191            0x54, 0x2d, 0x44, 0x31, 0x32, 0x31, 0x33, b' ',
1192            // -- 36, --
1193            // ElementHeader: (0008,0102) CodingSchemeDesignator; len = 4
1194            0x08, 0x00, 0x02, 0x01, b'S', b'H', 0x04, 0x00, // PrimitiveValue
1195            0x53, 0x52, 0x54, b' ',
1196            // -- 48, --
1197            // (0008,0104) CodeMeaning; len = 10
1198            0x08, 0x00, 0x04, 0x01, b'L', b'O', 0x0a, 0x00, // PrimitiveValue
1199            0x4a, 0x61, 0x77, b' ', 0x72, 0x65, 0x67, 0x69, 0x6f, 0x6e,
1200            // -- 66 --
1201            // SequenceStart: (0040,0555) AcquisitionContextSequence; len = 0
1202            0x40, 0x00, 0x55, 0x05, b'S', b'Q', 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
1203            // ElementHeader: (2050,0020) PresentationLUTShape; len = 8
1204            0x50, 0x20, 0x20, 0x00, b'C', b'S', 0x08, 0x00, // PrimitiveValue
1205            b'I', b'D', b'E', b'N', b'T', b'I', b'T', b'Y',
1206        ];
1207
1208        let ground_truth = vec![
1209            DataToken::SequenceStart {
1210                tag: Tag(0x0008, 0x2218),
1211                len: Length(54),
1212            },
1213            DataToken::ItemStart { len: Length(46) },
1214            DataToken::ElementHeader(DataElementHeader {
1215                tag: Tag(0x0008, 0x0100),
1216                vr: VR::SH,
1217                len: Length(8),
1218            }),
1219            DataToken::PrimitiveValue(PrimitiveValue::Strs(
1220                ["T-D1213 ".to_owned()].as_ref().into(),
1221            )),
1222            DataToken::ElementHeader(DataElementHeader {
1223                tag: Tag(0x0008, 0x0102),
1224                vr: VR::SH,
1225                len: Length(4),
1226            }),
1227            DataToken::PrimitiveValue(PrimitiveValue::Strs(["SRT ".to_owned()].as_ref().into())),
1228            DataToken::ElementHeader(DataElementHeader {
1229                tag: Tag(0x0008, 0x0104),
1230                vr: VR::LO,
1231                len: Length(10),
1232            }),
1233            DataToken::PrimitiveValue(PrimitiveValue::Strs(
1234                ["Jaw region".to_owned()].as_ref().into(),
1235            )),
1236            DataToken::ItemEnd,
1237            DataToken::SequenceEnd,
1238            DataToken::SequenceStart {
1239                tag: Tag(0x0040, 0x0555),
1240                len: Length(0),
1241            },
1242            DataToken::SequenceEnd,
1243            DataToken::ElementHeader(DataElementHeader {
1244                tag: Tag(0x2050, 0x0020),
1245                vr: VR::CS,
1246                len: Length(8),
1247            }),
1248            DataToken::PrimitiveValue(PrimitiveValue::Strs(
1249                ["IDENTITY".to_owned()].as_ref().into(),
1250            )),
1251        ];
1252
1253        let mut cursor = DATA;
1254        let parser = StatefulDecoder::new(
1255            &mut cursor,
1256            ExplicitVRLittleEndianDecoder::default(),
1257            LittleEndianBasicDecoder,
1258            SpecificCharacterSet::default(),
1259        );
1260
1261        let mut dset_reader = LazyDataSetReader::new(parser);
1262
1263        let mut gt_iter = ground_truth.into_iter();
1264        while let Some(res) = dset_reader.advance() {
1265            let token = res.expect("should parse without an error");
1266            let gt_token = gt_iter.next().expect("ground truth is shorter");
1267            match token {
1268                LazyDataToken::LazyValue { .. } | LazyDataToken::LazyItemValue { .. } => {
1269                    token.skip().unwrap();
1270                }
1271                token => {
1272                    let token = token.into_owned().unwrap();
1273                    assert_eq!(token, gt_token);
1274                }
1275            }
1276        }
1277
1278        assert_eq!(
1279            gt_iter.count(), // consume til the end
1280            0,               // we have already read all of them
1281            "unexpected number of tokens remaining"
1282        );
1283        assert_eq!(dset_reader.parser.position(), DATA.len() as u64);
1284    }
1285
1286    #[test]
1287    fn lazy_read_value_via_into_value() {
1288        // manually crafted DICOM data elements
1289        //  Tag: (0002,0002) Media Storage SOP Class UID
1290        //  VR: UI
1291        //  Length: 26
1292        //  Value: "1.2.840.10008.5.1.4.1.1.1\0"
1293        // --
1294        //  Tag: (0002,0010) Transfer Syntax UID
1295        //  VR: UI
1296        //  Length: 20
1297        //  Value: "1.2.840.10008.1.2.1\0" == ExplicitVRLittleEndian
1298        // --
1299        const RAW: &[u8; 62] = &[
1300            0x02, 0x00, 0x02, 0x00, 0x55, 0x49, 0x1a, 0x00, 0x31, 0x2e, 0x32, 0x2e, 0x38, 0x34,
1301            0x30, 0x2e, 0x31, 0x30, 0x30, 0x30, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x2e, 0x34, 0x2e,
1302            0x31, 0x2e, 0x31, 0x2e, 0x31, 0x00, 0x02, 0x00, 0x10, 0x00, 0x55, 0x49, 0x14, 0x00,
1303            0x31, 0x2e, 0x32, 0x2e, 0x38, 0x34, 0x30, 0x2e, 0x31, 0x30, 0x30, 0x30, 0x38, 0x2e,
1304            0x31, 0x2e, 0x32, 0x2e, 0x31, 0x00,
1305        ];
1306        let mut cursor = &RAW[..];
1307        let parser = StatefulDecoder::new(
1308            &mut cursor,
1309            ExplicitVRLittleEndianDecoder::default(),
1310            LittleEndianBasicDecoder,
1311            SpecificCharacterSet::default(),
1312        );
1313
1314        let mut dset_reader = LazyDataSetReader::new(parser);
1315
1316        let token = dset_reader
1317            .advance()
1318            .expect("Expected token 1")
1319            .expect("Failed to read token 1");
1320
1321        let header_token1 = match token {
1322            LazyDataToken::ElementHeader(header) => header,
1323            _ => {
1324                panic!("Unexpected token type (1)");
1325            }
1326        };
1327
1328        let token = dset_reader
1329            .advance()
1330            .expect("Expected token 2")
1331            .expect("Failed to read token 2");
1332
1333        match token {
1334            LazyDataToken::LazyValue { header, decoder: _ } => {
1335                assert_eq!(header_token1, header);
1336            }
1337            _ => {
1338                panic!("Unexpected token type (2)");
1339            }
1340        }
1341
1342        // consume via into_value
1343        assert_eq!(
1344            token.into_value().unwrap(),
1345            dicom_value!(Strs, ["1.2.840.10008.5.1.4.1.1.1\0"]),
1346        );
1347
1348        let token = dset_reader
1349            .advance()
1350            .expect("Expected token 3")
1351            .expect("Failed to read token 3");
1352
1353        let header_token3 = match token {
1354            LazyDataToken::ElementHeader(header) => header,
1355            _ => {
1356                panic!("Unexpected token type (3)");
1357            }
1358        };
1359
1360        let token = dset_reader
1361            .advance()
1362            .expect("Expected token 4")
1363            .expect("Failed to read token 4");
1364
1365        match token {
1366            LazyDataToken::LazyValue { header, decoder: _ } => {
1367                assert_eq!(header_token3, header);
1368            }
1369            _ => {
1370                panic!("Unexpected token type (4)");
1371            }
1372        }
1373
1374        // consume via into_value
1375        assert_eq!(
1376            token.into_value().unwrap(),
1377            dicom_value!(Strs, ["1.2.840.10008.1.2.1\0"]),
1378        );
1379
1380        assert!(
1381            dset_reader.advance().is_none(),
1382            "unexpected number of tokens remaining"
1383        );
1384    }
1385
1386    #[test]
1387    fn peek_data_elements() {
1388        #[rustfmt::skip]
1389        static DATA: &[u8] = &[
1390            0x18, 0x00, 0x11, 0x60, // sequence tag: (0018,6011) SequenceOfUltrasoundRegions
1391            b'S', b'Q', // VR
1392            0x00, 0x00, // reserved
1393            0xff, 0xff, 0xff, 0xff, // length: undefined
1394            // -- 12 --
1395            0xfe, 0xff, 0xdd, 0xe0, 0x00, 0x00, 0x00, 0x00, // sequence end
1396            // -- 20 --
1397            0x20, 0x00, 0x00, 0x40, b'L', b'T', 0x04, 0x00, // (0020,4000) ImageComments, len = 4
1398            // -- 28 --
1399            b'T', b'E', b'S', b'T', // value = "TEST"
1400            // -- 32 --
1401        ];
1402
1403        let ground_truth = vec![
1404            DataToken::SequenceStart {
1405                tag: Tag(0x0018, 0x6011),
1406                len: Length::UNDEFINED,
1407            },
1408            DataToken::SequenceEnd,
1409            DataToken::ElementHeader(DataElementHeader {
1410                tag: Tag(0x0020, 0x4000),
1411                vr: VR::LT,
1412                len: Length(4),
1413            }),
1414            DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
1415        ];
1416
1417        let mut cursor = DATA;
1418        let parser = StatefulDecoder::new(
1419            &mut cursor,
1420            ExplicitVRLittleEndianDecoder::default(),
1421            LittleEndianBasicDecoder::default(),
1422            SpecificCharacterSet::default(),
1423        );
1424        let mut dset_reader = LazyDataSetReader::new(parser);
1425
1426        // peek at first token
1427        let token = dset_reader.peek().expect("should peek first token OK");
1428        assert_eq!(token, Some(&ground_truth[0]));
1429
1430        assert_eq!(dset_reader.parser.position(), 12);
1431
1432        // peeking multiple times gives the same result
1433        let token = dset_reader
1434            .peek()
1435            .expect("should peek first token again OK");
1436        assert_eq!(token, Some(&ground_truth[0]));
1437
1438        assert_eq!(dset_reader.parser.position(), 12);
1439
1440        // Using `advance` give us the same token
1441        let token = dset_reader
1442            .advance()
1443            .expect("expected token")
1444            .expect("should read token peeked OK");
1445        assert_eq!(&token.into_owned().unwrap(), &ground_truth[0]);
1446
1447        assert_eq!(dset_reader.parser.position(), 12);
1448
1449        // sequence end
1450        let token = dset_reader
1451            .advance()
1452            .expect("expected token")
1453            .expect("should read token OK");
1454        assert_eq!(&token.into_owned().unwrap(), &ground_truth[1]);
1455
1456        assert_eq!(dset_reader.parser.position(), 20);
1457
1458        // peek data element header
1459        let token = dset_reader.peek().expect("should peek first token OK");
1460        assert_eq!(token, Some(&ground_truth[2]));
1461
1462        assert_eq!(dset_reader.parser.position(), 28);
1463
1464        // read data element header
1465        let token = dset_reader
1466            .advance()
1467            .expect("expected token")
1468            .expect("should read token OK");
1469        assert_eq!(&token.into_owned().unwrap(), &ground_truth[2]);
1470
1471        // should not have read anything else
1472        assert_eq!(dset_reader.parser.position(), 28);
1473
1474        // read string value
1475        let token = dset_reader
1476            .advance()
1477            .expect("expected token")
1478            .expect("should read token OK");
1479        assert_eq!(&token.into_owned().unwrap(), &ground_truth[3]);
1480
1481        // finished reading, peek should return None
1482        assert!(dset_reader.peek().unwrap().is_none());
1483    }
1484
1485    #[test]
1486    fn read_odd_length_element() {
1487        #[rustfmt::skip]
1488        static DATA: &[u8] = &[
1489            0x08, 0x00, 0x16, 0x00, // (0008,0016) SOPClassUID
1490            b'U', b'I', // VR
1491            0x0b, 0x00, // len = 11
1492            b'1', b'.', b'2', b'.', b'8', b'4', b'0', b'.', b'1', b'0', b'0',
1493            0x00, // padding
1494        ];
1495
1496        let ground_truth = vec![
1497            DataToken::ElementHeader(DataElementHeader {
1498                tag: Tag(0x0008, 0x0016),
1499                vr: VR::UI,
1500                len: Length(12),
1501            }),
1502            DataToken::PrimitiveValue(PrimitiveValue::from("1.2.840.100\0")),
1503        ];
1504
1505        // strategy: assume next even
1506
1507        let mut cursor = DATA;
1508        let parser = StatefulDecoder::new(
1509            &mut cursor,
1510            ExplicitVRLittleEndianDecoder::default(),
1511            LittleEndianBasicDecoder,
1512            SpecificCharacterSet::default(),
1513        );
1514        let mut dset_reader = LazyDataSetReader::new_with_options(
1515            parser,
1516            LazyDataSetReaderOptions {
1517                odd_length: OddLengthStrategy::NextEven,
1518                ..Default::default()
1519            },
1520        );
1521
1522        // read next
1523        let token = dset_reader
1524            .advance()
1525            .expect("expected token")
1526            .expect("should read token OK");
1527
1528        assert_eq!(&token.into_owned().unwrap(), &ground_truth[0],);
1529
1530        // strategy: fail
1531
1532        let mut cursor = DATA;
1533        let parser = StatefulDecoder::new(
1534            &mut cursor,
1535            ExplicitVRLittleEndianDecoder::default(),
1536            LittleEndianBasicDecoder,
1537            SpecificCharacterSet::default(),
1538        );
1539        let mut dset_reader = LazyDataSetReader::new_with_options(
1540            parser,
1541            LazyDataSetReaderOptions {
1542                odd_length: OddLengthStrategy::Fail,
1543                ..Default::default()
1544            },
1545        );
1546
1547        let token = dset_reader.advance();
1548
1549        assert!(
1550            matches!(
1551                token,
1552                Some(Err(super::Error::InvalidElementLength {
1553                    tag: Tag(0x0008, 0x0016),
1554                    len: 11,
1555                    bytes_read: 8,
1556                    ..
1557                })),
1558            ),
1559            "got: {:?}",
1560            token
1561        );
1562    }
1563}