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