Skip to main content

dicom_encoding/encode/
explicit_be.rs

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