Skip to main content

dicom_encoding/decode/
explicit_le.rs

1//! Explicit VR Little Endian syntax transfer implementation
2
3use crate::decode::basic::LittleEndianBasicDecoder;
4use crate::decode::{
5    BadSequenceHeaderSnafu, BasicDecode, Decode, DecodeFrom, ReadHeaderTagSnafu,
6    ReadItemHeaderSnafu, ReadItemLengthSnafu, ReadLengthSnafu, ReadReservedSnafu, ReadTagSnafu,
7    ReadVrSnafu, Result,
8};
9use byteordered::byteorder::{ByteOrder, LittleEndian};
10use dicom_core::header::{DataElementHeader, Length, SequenceItemHeader};
11use dicom_core::{Tag, VR};
12use snafu::ResultExt;
13use std::io::Read;
14
15/// A data element decoder for the Explicit VR Little Endian transfer syntax.
16#[derive(Debug, Default, Clone)]
17pub struct ExplicitVRLittleEndianDecoder {
18    basic: LittleEndianBasicDecoder,
19}
20
21impl Decode for ExplicitVRLittleEndianDecoder {
22    fn decode_header<S>(&self, mut source: &mut S) -> Result<(DataElementHeader, usize)>
23    where
24        S: ?Sized + Read,
25    {
26        // retrieve tag
27        let Tag(group, element) = self
28            .basic
29            .decode_tag(&mut source)
30            .context(ReadHeaderTagSnafu)?;
31
32        let mut buf = [0u8; 4];
33        if group == 0xFFFE {
34            // item delimiters do not have VR or reserved field
35            source.read_exact(&mut buf).context(ReadItemLengthSnafu)?;
36            let len = LittleEndian::read_u32(&buf);
37            return Ok((
38                DataElementHeader::new((group, element), VR::UN, Length(len)),
39                8, // tag + len
40            ));
41        }
42
43        // retrieve explicit VR
44        source.read_exact(&mut buf[0..2]).context(ReadVrSnafu)?;
45        let vr = VR::from_binary([buf[0], buf[1]]).unwrap_or(VR::UN);
46        let bytes_read;
47
48        // retrieve data length
49        let len = match vr {
50            // PS3.5 7.1.2:
51            // for VRs of AE, AS, AT, CS, DA, DS, DT, FL, FD, IS, LO, LT, PN,
52            // SH, SL, SS, ST, TM, UI, UL and US the Value Length Field is the
53            // 16-bit unsigned integer following the two byte VR Field (Table
54            // 7.1-2). The value of the Value Length Field shall equal the
55            // length of the Value Field.
56            VR::AE
57            | VR::AS
58            | VR::AT
59            | VR::CS
60            | VR::DA
61            | VR::DS
62            | VR::DT
63            | VR::FL
64            | VR::FD
65            | VR::IS
66            | VR::LO
67            | VR::LT
68            | VR::PN
69            | VR::SH
70            | VR::SL
71            | VR::SS
72            | VR::ST
73            | VR::TM
74            | VR::UI
75            | VR::UL
76            | VR::US => {
77                // read 2 bytes for the data length
78                source.read_exact(&mut buf[0..2]).context(ReadLengthSnafu)?;
79                bytes_read = 8;
80                u32::from(LittleEndian::read_u16(&buf[0..2]))
81            }
82            // PS3.5 7.1.2:
83            // for all other VRs the 16 bits following the two byte VR Field
84            // are reserved for use by later versions of the DICOM Standard.
85            // These reserved bytes shall be set to 0000H and shall not be
86            // used or decoded (Table 7.1-1). The Value Length Field is a
87            // 32-bit unsigned integer.
88            _ => {
89                // read 2 reserved bytes, then 4 bytes for data length
90                source
91                    .read_exact(&mut buf[0..2])
92                    .context(ReadReservedSnafu)?;
93                source.read_exact(&mut buf).context(ReadLengthSnafu)?;
94                bytes_read = 12;
95                LittleEndian::read_u32(&buf)
96            }
97        };
98
99        Ok((
100            DataElementHeader::new((group, element), vr, Length(len)),
101            bytes_read,
102        ))
103    }
104
105    fn decode_item_header<S>(&self, source: &mut S) -> Result<SequenceItemHeader>
106    where
107        S: ?Sized + Read,
108    {
109        let mut buf = [0u8; 8];
110        source.read_exact(&mut buf).context(ReadItemHeaderSnafu)?;
111        // retrieve tag
112        let group = LittleEndian::read_u16(&buf[0..2]);
113        let element = LittleEndian::read_u16(&buf[2..4]);
114        let len = LittleEndian::read_u32(&buf[4..8]);
115
116        SequenceItemHeader::new((group, element), Length(len)).context(BadSequenceHeaderSnafu)
117    }
118
119    fn decode_tag<S>(&self, source: &mut S) -> Result<Tag>
120    where
121        S: ?Sized + Read,
122    {
123        let mut buf = [0u8; 4];
124        source.read_exact(&mut buf).context(ReadTagSnafu)?;
125        Ok(Tag(
126            LittleEndian::read_u16(&buf[0..2]),
127            LittleEndian::read_u16(&buf[2..4]),
128        ))
129    }
130}
131
132impl<S: ?Sized> DecodeFrom<S> for ExplicitVRLittleEndianDecoder
133where
134    S: Read,
135{
136    #[inline]
137    fn decode_header(&self, source: &mut S) -> Result<(DataElementHeader, usize)> {
138        Decode::decode_header(self, source)
139    }
140
141    #[inline]
142    fn decode_item_header(&self, source: &mut S) -> Result<SequenceItemHeader> {
143        Decode::decode_item_header(self, source)
144    }
145
146    #[inline]
147    fn decode_tag(&self, source: &mut S) -> Result<Tag> {
148        Decode::decode_tag(self, source)
149    }
150}
151
152#[cfg(test)]
153mod tests {
154    use super::ExplicitVRLittleEndianDecoder;
155    use crate::decode::Decode;
156    use dicom_core::header::{HasLength, Header, Length};
157    use dicom_core::{Tag, VR};
158    use std::io::{Cursor, Seek, SeekFrom};
159
160    // manually crafting some DICOM data elements
161    #[rustfmt::skip]
162    const RAW: &[u8] = &[
163        0x02, 0x00, 0x02, 0x00,     // (0002,0002) (LE) Media Storage SOP Class UID
164            b'U', b'I',             // VR: UI (UID)
165            0x1A, 0x00,             // Length: 26 bytes (LE)
166                // UID: 1.2.840.10008.5.1.4.1.1.1
167                b'1', b'.', b'2', b'.', b'8', b'4', b'0', b'.', b'1', b'0', b'0', b'0', b'8', b'.',
168                b'5', b'.', b'1', b'.', b'4', b'.', b'1', b'.', b'1', b'.', b'1',
169                0x00,               // Padding to make length even
170        0x02, 0x00, 0x10, 0x00,     // (0002,0010) (LE) Transfer Syntax UID
171            b'U', b'I',             // VR: UI (UID)
172            0x14, 0x00,             // Length: 20 bytes (LE)
173                // UID: 1.2.840.10008.1.2.1 (ExplicitVRLittleEndian)
174                b'1', b'.', b'2', b'.', b'8', b'4', b'0', b'.', b'1', b'0', b'0', b'0', b'8', b'.',
175                b'1', b'.', b'2', b'.', b'1',
176                0x00,               // Padding to make length even
177        0x08, 0x00, 0x54, 0x00,     // (0008,0054) (LE) Retrieve AE Title
178            b'A', b'E',             // VR: AE (Application Entity)
179            0x06, 0x00,             // Length: 6 bytes (LE)
180                // String "TITLE"
181                b'T', b'I', b'T', b'L', b'E',
182                b' ',               // Padding to make length even
183        0x10, 0x00, 0x10, 0x10,     // (0010,1010) (LE) Patient's Age
184            b'A', b'S',             // VR: AS (Age String)
185            0x02, 0x00,             // Length: 2 bytes (LE)
186                // String "8Y"
187                b'8', b'Y',
188        0x72, 0x00, 0x26, 0x00,     // (0072,0026) (LE) Selector Attribute
189            b'A', b'T',             // VR: AT (Attribute Tag)
190            0x04, 0x00,             // Length: 4 bytes (LE)
191                // Tag: (0028,2110) (LE) Lossy Image Compression
192                0x28, 0x00, 0x10, 0x21,
193        0x10, 0x00, 0x40, 0x00,     // (0010,0040) (LE) Patient Sex
194            b'C', b'S',             // VR: CS (Code String)
195            0x02, 0x00,             // Length: 2 bytes (LE)
196                // Text: "O"
197                b'O',
198                b' ',               // Padding to make length even
199        0x10, 0x00, 0x30, 0x00,     // (0010,0030) (LE) Patient's Birth Date
200            b'D', b'A',             // VR: DA (Date)
201            0x08, 0x00,             // Length: 8 bytes (LE)
202                // String "19800101"
203                b'1', b'9', b'8', b'0', b'0', b'1', b'0', b'1',
204        0x10, 0x00, 0x20, 0x10,     // (0010,1020) (LE) Patient's size
205            b'D', b'S',             // VR: DS (Decimal String)
206            0x04, 0x00,             // Length: 4 bytes (LE)
207                // String: "1.70"
208                b'1', b'.', b'7', b'0',
209        0x08, 0x00, 0x15, 0x00,     // (0008,0015) (LE) Instance coercion datetime
210            b'D', b'T',             // VR: DT (Date Time)
211            0x0E, 0x00,             // Length: 14 bytes (LE)
212                // String "20051231235960"
213                b'2', b'0', b'0', b'5', b'1', b'2', b'3', b'1', b'2', b'3', b'5', b'9', b'6', b'0',
214        0x10, 0x00, 0x31, 0x94,     // (0010,9431) (LE) Examined Body Thickness
215            b'F', b'L',             // VR: FL (Floating-point IEEE-754)
216            0x04, 0x00,             // Length: 4 bytes (LE)
217                // Value: 3.1415927 (LE)
218                0xDB, 0x0F, 0x49, 0x40,
219        0x40, 0x00, 0x25, 0x92,     // (0040,9225) (LE) Real World Value Slope
220            b'F', b'D',             // VR: FD (Double-precision floating-point IEEE-754)
221            0x08, 0x00,             // Length: 8 bytes (LE)
222                // Value: 3.141592653589793 (LE)
223                0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40,
224        0x20, 0x00, 0x13, 0x00,     // (0020,0013) (LE) Instance Number
225            b'I', b'S',             // VR: IS (Integer String)
226            0x08, 0x00,             // Length: 8 bytes (LE)
227                // String: "1234567"
228                b'1', b'2', b'3', b'4', b'5', b'6', b'7',
229                b' ',               // Padding to make length even
230        0x10, 0x00, 0x20, 0x00,     // (0010,0020) (LE) Patient ID
231            b'L', b'O',             // VR: LO (Long string)
232            0x0A, 0x00,             // Length: 10 bytes (LE)
233                // String "P12345678X"
234                b'P', b'1', b'2', b'3', b'4', b'5', b'6', b'7', b'8', b'X',
235        0x10, 0x00, 0x00, 0x40,     // (0010,4000) (LE) Patient Comments
236            b'L', b'T',             // VR: LT (Long Text)
237            0x04, 0x00,             // Length: 4 bytes (LE)
238                // String "None"
239                b'N', b'o', b'n', b'e',
240        0x08, 0x00, 0x1B, 0x04,     // (0008,041B) (LE) RecordKey
241            b'O', b'B',             // VR: OB (Other Byte)
242            0x00, 0x00,             // Reserved, always 0
243            0x02, 0x00, 0x00, 0x00, // Length: 2 bytes (LE)
244                // Value: [0x12, 0x34]
245                0x12, 0x34,
246        0xE0, 0x7F, 0x09, 0x00,     // (7FE0,0009) (LE) Double Float Pixel Data
247            b'O', b'D',             // VR: OD (Other Double)
248            0x00, 0x00,             // Reserved, always 0
249            0x08, 0x00, 0x00, 0x00, // Length: 8 bytes (LE)
250                // Value: [3.141592653589793] (LE)
251                0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40,
252        0xE0, 0x7F, 0x08, 0x00,     // (7FE0,0008) (LE) Float Pixel Data
253            b'O', b'F',             // VR: OF (Other Float)
254            0x00, 0x00,             // Reserved, always 0
255            0x04, 0x00, 0x00, 0x00, // Length: 4 bytes (LE)
256                // Value: [3.1415927] (LE)
257                0xDB, 0x0F, 0x49, 0x40,
258        0x72, 0x00, 0x75, 0x00,     // (0072,0075) (LE) Selector OL Value
259            b'O', b'L',             // VR: OL (Other Long)
260            0x00, 0x00,             // Reserved, always 0
261            0x04, 0x00, 0x00, 0x00, // Length: 4 bytes (LE)
262                // Value: [0x12345678] (LE)
263                0x78, 0x56, 0x34, 0x12,
264        0x72, 0x00, 0x81, 0x00,     // (0072,0081) (LE) Selector OV Value
265            b'O', b'V',             // VR: OV (Other Very long)
266            0x00, 0x00,             // Reserved, always 0
267            0x08, 0x00, 0x00, 0x00, // Length: 8 bytes (LE)
268                // Value: [0x192A3B4C5D6E7F80] (LE)
269                0x80, 0x7F, 0x6E, 0x5D, 0x4C, 0x3B, 0x2A, 0x19,
270        0x72, 0x00, 0x69, 0x00,     // (0072,0069) (LE) Selector OW Value
271            b'O', b'W',             // VR: OW (Other Word)
272            0x00, 0x00,             // Reserved, always 0
273            0x02, 0x00, 0x00, 0x00, // Length: 2 bytes (LE)
274                // Value: [0x1234] (LE)
275                0x34, 0x12,
276        0x10, 0x00, 0x10, 0x00,     // (0010,0010) (LE) Patient Name
277            b'P', b'N',             // VR: PN (Person Name)
278            0x08, 0x00,             // Length: 8 bytes (LE)
279                // String: "Doe^John"
280                b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
281        0x40, 0x00, 0x10, 0x92,     // (0040,9210) (LE) LUT Label
282            b'S', b'H',             // VR: SH (Short string)
283            0x04, 0x00,             // Length: 4 bytes (LE)
284                // String: "LBL"
285                b'L', b'B', b'L',
286                b' ',               // Padding to make length even
287        0x18, 0x00, 0x20, 0x60,     // (0018,6020) (LE) Reference Pixel X0
288            b'S', b'L',             // VR: SL (Signed Long)
289            0x04, 0x00,             // Length: 4 bytes (LE)
290                // Value: -12345678 (LE)
291                0xB2, 0x9E, 0x43, 0xFF,
292        // Sequences (VR: SQ) tested elsewhere
293        0x28, 0x00, 0x03, 0x95,     // (0028,9503) (LE) Vertices of the Region (VM 2-2n)
294            b'S', b'S',             // VR: SS (Signed Short)
295            0x04, 0x00,             // Length: 4 bytes (2 * 2) (LE)
296                // Value: -4567 (LE)
297                0x29, 0xEE,
298                // Value: 4321 (LE)
299                0xE1, 0x10,
300        0x40, 0x00, 0x80, 0x02,     // (0040,0280) (LE) Comments on the Performed Procedure Step
301            b'S', b'T',             // VR: ST (Short Text)
302            0x0A, 0x00,             // Length: 10 bytes (LE)
303                // String: "No comment"
304                b'N', b'o', b' ', b'c', b'o', b'm', b'm', b'e', b'n', b't',
305        0x72, 0x00, 0x82, 0x00,     // (0072,0082) (LE) SelectorSVValue (VM: 1-n)
306            b'S', b'V',             // VR: SV (Signed Very long)
307            0x00, 0x00,             // Reserved, always 0
308            0x10, 0x00, 0x00, 0x00, // Length: 16 bytes (2 * 8) (LE)
309                // Value: -123456789012345678 (LE)
310                0xB2, 0x0C, 0xCF, 0x59, 0xB4, 0x64, 0x49, 0xFE,
311                // Value: 123456789012345678 (LE)
312                0x4E, 0xF3, 0x30, 0xA6, 0x4B, 0x9B, 0xB6, 0x01,
313        0x10, 0x00, 0x32, 0x00,     // (0010,0032) (LE) Patient's Birth Time
314            b'T', b'M',             // VR: TM (Time)
315            0x06, 0x00,             // Length: 6 bytes (LE)
316                // String: "123456"
317                b'1', b'2', b'3', b'4', b'5', b'6',
318        0x08, 0x00, 0x19, 0x01,     // (0008,0119) (LE) Long Code Value
319            b'U', b'C',             // VR: UC (Unlimited Characters)
320            0x00, 0x00,             // Reserved, always 0
321            0x04, 0x00, 0x00, 0x00, // Length: 4 bytes (LE)
322                // String: "Code"
323                b'C', b'o', b'd', b'e',
324        // UI already tested above
325        0x18, 0x00, 0x16, 0x60,     // (0018,6016) (LE) Region Flags
326            b'U', b'L',
327            0x04, 0x00,             // Length: 4 bytes (LE)
328                // Value: 1 (LE)
329                0x01, 0x00, 0x00, 0x00,
330        0x01, 0xC0, 0x34, 0x12,     // (C001,1234) (LE) (Private data element)
331            b'U', b'N',             // VR: UN (Unknown)
332            0x00, 0x00,             // Reserved, always 0
333            0x06, 0x00, 0x00, 0x00, // Length: 6 bytes (LE)
334                // Value: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]
335                0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
336        0x08, 0x00, 0x0E, 0x01,     // (0008,010E) (LE) Coding Scheme URL
337            b'U', b'R',             // VR: UR (Universal Resource Locator, URL)
338            0x00, 0x00,             // Reserved, always 0
339            0x12, 0x00, 0x00, 0x00, // Length: 18 bytes (LE)
340                // String: "http://example.com"
341                b'h', b't', b't', b'p', b':', b'/', b'/', b'e', b'x', b'a', b'm', b'p', b'l', b'e',
342                b'.', b'c', b'o', b'm',
343        0x08, 0x00, 0x40, 0x00,     // (0008,0040) (LE) Data Set Type
344            b'U', b'S',             // VR: US (Unsigned Short)
345            0x02, 0x00,             // Length: 2 bytes (LE)
346                // Value: 34567 (LE)
347                0x07, 0x87,
348        0x18, 0x00, 0x17, 0x99,     // (0018,9917) (LE) Instruction Description
349            b'U', b'T',             // VR: UT (Unlimited Text)
350            0x00, 0x00,             // Reserved, always 0
351            0x08, 0x00, 0x00, 0x00, // Length: 8 bytes (LE)
352                // String: "No text"
353                b'N', b'o', b' ', b't', b'e', b'x', b't',
354                b' ',               // Padding to make length even
355        0x08, 0x00, 0x0C, 0x04,     // (0008,040C) (LE) File Offset in Container
356            b'U', b'V',             // VR: UV (Unsigned Very long)
357            0x00, 0x00,             // Reserved, always 0
358            0x08, 0x00, 0x00, 0x00, // Length: 8 bytes (LE)
359                // Value: 12345678901234567890 (LE)
360                0xD2, 0x0A, 0x1F, 0xEB, 0x8C, 0xA9, 0x54, 0xAB,
361    ];
362
363    #[test]
364    fn decode_data_elements() {
365        let dec = ExplicitVRLittleEndianDecoder::default();
366        let mut cursor = Cursor::new(RAW.as_ref());
367
368        fn read_n<'a>(cursor: &mut Cursor<&'a [u8]>, n: usize) -> &'a [u8] {
369            let pos = cursor.position() as usize;
370            let slice = &cursor.get_ref()[pos..pos + n]; // panic if too short
371            cursor.set_position((pos + n) as u64);
372            slice
373        }
374
375        fn test_vr(
376            dec: &ExplicitVRLittleEndianDecoder,
377            cursor: &mut Cursor<&[u8]>,
378            group: u16,
379            element: u16,
380            vr: VR,
381            value: &[u8],
382        ) {
383            let (elem, _bytes_read) = dec.decode_header(cursor).expect("should find an element");
384            assert_eq!(elem.tag(), Tag(group, element));
385            assert_eq!(elem.vr(), vr);
386            assert_eq!(elem.length(), Length(value.len() as u32));
387            let buffer = read_n(cursor, value.len());
388            assert_eq!(&buffer, &value);
389        }
390
391        // read first element
392        let (elem, bytes_read) = dec
393            .decode_header(&mut cursor)
394            .expect("should find an element");
395        assert_eq!(elem.tag(), Tag(0x0002, 0x0002));
396        assert_eq!(elem.vr(), VR::UI);
397        assert_eq!(elem.length(), Length(26));
398        assert_eq!(bytes_read, 8);
399        // read only half of the value data
400        let buffer = read_n(&mut cursor, 13);
401        assert_eq!(&buffer, b"1.2.840.10008");
402
403        // cursor should now be @ #21 (there is no automatic skipping)
404        assert_eq!(cursor.stream_position().unwrap(), 21);
405        // cursor should now be @ #34 after skipping
406        assert_eq!(cursor.seek(SeekFrom::Current(13)).unwrap(), 34);
407
408        // read second element
409        let (elem, _bytes_read) = dec
410            .decode_header(&mut cursor)
411            .expect("should find an element");
412        assert_eq!(elem.tag(), Tag(0x0002, 0x0010));
413        assert_eq!(elem.vr(), VR::UI);
414        assert_eq!(elem.length(), Length(20));
415        // read all data
416        let buffer = read_n(&mut cursor, 20);
417        assert_eq!(&buffer, b"1.2.840.10008.1.2.1\0");
418
419        // read various VRs
420        test_vr(&dec, &mut cursor, 0x0008, 0x0054, VR::AE, b"TITLE ");
421        test_vr(&dec, &mut cursor, 0x0010, 0x1010, VR::AS, b"8Y");
422        test_vr(
423            &dec,
424            &mut cursor,
425            0x0072,
426            0x0026,
427            VR::AT,
428            &[0x28, 0x00, 0x10, 0x21],
429        );
430        test_vr(&dec, &mut cursor, 0x0010, 0x0040, VR::CS, b"O ");
431        test_vr(&dec, &mut cursor, 0x0010, 0x0030, VR::DA, b"19800101");
432        test_vr(&dec, &mut cursor, 0x0010, 0x1020, VR::DS, b"1.70");
433        test_vr(
434            &dec,
435            &mut cursor,
436            0x0008,
437            0x0015,
438            VR::DT,
439            b"20051231235960",
440        );
441        test_vr(
442            &dec,
443            &mut cursor,
444            0x0010,
445            0x9431,
446            VR::FL,
447            &[0xDB, 0x0F, 0x49, 0x40],
448        );
449        test_vr(
450            &dec,
451            &mut cursor,
452            0x0040,
453            0x9225,
454            VR::FD,
455            &[0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40],
456        );
457        test_vr(&dec, &mut cursor, 0x0020, 0x0013, VR::IS, b"1234567 ");
458        test_vr(&dec, &mut cursor, 0x0010, 0x0020, VR::LO, b"P12345678X");
459        test_vr(&dec, &mut cursor, 0x0010, 0x4000, VR::LT, b"None");
460        test_vr(&dec, &mut cursor, 0x0008, 0x041B, VR::OB, &[0x12, 0x34]);
461        test_vr(
462            &dec,
463            &mut cursor,
464            0x7FE0,
465            0x0009,
466            VR::OD,
467            &[0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40],
468        );
469        test_vr(
470            &dec,
471            &mut cursor,
472            0x7FE0,
473            0x0008,
474            VR::OF,
475            &[0xDB, 0x0F, 0x49, 0x40],
476        );
477        test_vr(
478            &dec,
479            &mut cursor,
480            0x0072,
481            0x0075,
482            VR::OL,
483            &[0x78, 0x56, 0x34, 0x12],
484        );
485        test_vr(
486            &dec,
487            &mut cursor,
488            0x0072,
489            0x0081,
490            VR::OV,
491            &[0x80, 0x7F, 0x6E, 0x5D, 0x4C, 0x3B, 0x2A, 0x19],
492        );
493        test_vr(&dec, &mut cursor, 0x0072, 0x0069, VR::OW, &[0x34, 0x12]);
494        test_vr(&dec, &mut cursor, 0x0010, 0x0010, VR::PN, b"Doe^John");
495        test_vr(&dec, &mut cursor, 0x0040, 0x9210, VR::SH, b"LBL ");
496        test_vr(
497            &dec,
498            &mut cursor,
499            0x0018,
500            0x6020,
501            VR::SL,
502            &[0xB2, 0x9E, 0x43, 0xFF],
503        );
504        test_vr(
505            &dec,
506            &mut cursor,
507            0x0028,
508            0x9503,
509            VR::SS,
510            &[0x29, 0xEE, 0xE1, 0x10],
511        );
512        test_vr(&dec, &mut cursor, 0x0040, 0x0280, VR::ST, b"No comment");
513        test_vr(
514            &dec,
515            &mut cursor,
516            0x0072,
517            0x0082,
518            VR::SV,
519            &[
520                0xB2, 0x0C, 0xCF, 0x59, 0xB4, 0x64, 0x49, 0xFE, 0x4E, 0xF3, 0x30, 0xA6, 0x4B, 0x9B,
521                0xB6, 0x01,
522            ],
523        );
524        test_vr(&dec, &mut cursor, 0x0010, 0x0032, VR::TM, b"123456");
525        test_vr(&dec, &mut cursor, 0x0008, 0x0119, VR::UC, b"Code");
526        test_vr(
527            &dec,
528            &mut cursor,
529            0x0018,
530            0x6016,
531            VR::UL,
532            &[0x01, 0x00, 0x00, 0x00],
533        );
534        test_vr(
535            &dec,
536            &mut cursor,
537            0xC001,
538            0x1234,
539            VR::UN,
540            &[0x1, 0x2, 0x3, 0x4, 0x5, 0x6],
541        );
542        test_vr(
543            &dec,
544            &mut cursor,
545            0x0008,
546            0x010E,
547            VR::UR,
548            b"http://example.com",
549        );
550        test_vr(&dec, &mut cursor, 0x0008, 0x0040, VR::US, &[0x07, 0x87]);
551        test_vr(&dec, &mut cursor, 0x0018, 0x9917, VR::UT, b"No text ");
552        test_vr(
553            &dec,
554            &mut cursor,
555            0x0008,
556            0x040C,
557            VR::UV,
558            &[0xD2, 0x0A, 0x1F, 0xEB, 0x8C, 0xA9, 0x54, 0xAB],
559        );
560    }
561
562    // manually crafting some DICOM sequence/item delimiters
563    //  Tag: (0008,103F) Series Description Code Sequence
564    //  VR: SQ
565    //  Reserved bytes: 0x0000
566    //  Length: 0xFFFF_FFFF
567    // --
568    //  Tag: (FFFE,E000) Item
569    //  Length: 0xFFFF_FFFF (unspecified)
570    // --
571    //  Tag: (FFFE,E00D) Item Delimitation Item
572    //  Length: 0
573    // --
574    //  Tag: (FFFE,E0DD) Sequence Delimitation Item
575    //  Length: 0
576    // --
577    const RAW_SEQUENCE_ITEMS: &[u8] = &[
578        0x08, 0x00, 0x3F, 0x10, b'S', b'Q', 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00,
579        0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x0D, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF,
580        0xDD, 0xE0, 0x00, 0x00, 0x00, 0x00,
581    ];
582
583    #[test]
584    fn decode_items() {
585        let dec = ExplicitVRLittleEndianDecoder::default();
586        let mut cursor = Cursor::new(RAW_SEQUENCE_ITEMS);
587        {
588            // read first element
589            let (elem, bytes_read) = dec
590                .decode_header(&mut cursor)
591                .expect("should find an element header");
592            assert_eq!(elem.tag(), Tag(8, 0x103F));
593            assert_eq!(elem.vr(), VR::SQ);
594            assert!(elem.length().is_undefined());
595            assert_eq!(bytes_read, 12);
596        }
597        // cursor should now be @ #12
598        assert_eq!(cursor.stream_position().unwrap(), 12);
599        {
600            let elem = dec
601                .decode_item_header(&mut cursor)
602                .expect("should find an item header");
603            assert!(elem.is_item());
604            assert_eq!(elem.tag(), Tag(0xFFFE, 0xE000));
605            assert!(elem.length().is_undefined());
606        }
607        // cursor should now be @ #20
608        assert_eq!(cursor.stream_position().unwrap(), 20);
609        {
610            let elem = dec
611                .decode_item_header(&mut cursor)
612                .expect("should find an item header");
613            assert!(elem.is_item_delimiter());
614            assert_eq!(elem.tag(), Tag(0xFFFE, 0xE00D));
615            assert_eq!(elem.length(), Length(0));
616        }
617        // cursor should now be @ #28
618        assert_eq!(cursor.stream_position().unwrap(), 28);
619        {
620            let elem = dec
621                .decode_item_header(&mut cursor)
622                .expect("should find an item header");
623            assert!(elem.is_sequence_delimiter());
624            assert_eq!(elem.tag(), Tag(0xFFFE, 0xE0DD));
625            assert_eq!(elem.length(), Length(0));
626        }
627    }
628}