Skip to main content

dicom_encoding/encode/
explicit_le.rs

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