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, WriteItemDelimiterSnafu, WriteItemHeaderSnafu,
6    WriteOffsetTableSnafu, WriteSequenceDelimiterSnafu, WriteTagSnafu,
7};
8
9use byteordered::byteorder::{BigEndian, ByteOrder};
10use byteordered::Endianness;
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 ExplicitVRBigEndian
17#[derive(Debug, Default, Clone)]
18pub struct ExplicitVRBigEndianEncoder {
19    basic: BigEndianBasicEncoder,
20}
21
22impl BasicEncode for ExplicitVRBigEndianEncoder {
23    fn endianness(&self) -> Endianness {
24        Endianness::Big
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 ExplicitVRBigEndianEncoder {
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        BigEndian::write_u16(&mut buf[..], tag.group());
91        BigEndian::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 mut buf = [0u8; 8];
128                BigEndian::write_u16(&mut buf[0..], de.tag().group());
129                BigEndian::write_u16(&mut buf[2..], de.tag().element());
130                let vr_bytes = de.vr().to_bytes();
131                buf[4] = vr_bytes[0];
132                buf[5] = vr_bytes[1];
133                BigEndian::write_u16(&mut buf[6..], de.length().0 as u16);
134                to.write_all(&buf).context(WriteHeaderSnafu)?;
135
136                Ok(8)
137            }
138            // PS3.5 7.1.2:
139            // for all other VRs the 16 bits following the two byte VR Field
140            // are reserved for use by later versions of the DICOM Standard.
141            // These reserved bytes shall be set to 0000H and shall not be
142            // used or decoded (Table 7.1-1). The Value Length Field is a
143            // 32-bit unsigned integer.
144            _ => {
145                let mut buf = [0u8; 12];
146                BigEndian::write_u16(&mut buf[0..], de.tag().group());
147                BigEndian::write_u16(&mut buf[2..], de.tag().element());
148                let vr_bytes = de.vr().to_bytes();
149                buf[4] = vr_bytes[0];
150                buf[5] = vr_bytes[1];
151                // buf[6..8] is kept zero'd
152                BigEndian::write_u32(&mut buf[8..], de.length().0);
153                to.write_all(&buf).context(WriteHeaderSnafu)?;
154
155                Ok(12)
156            }
157        }
158    }
159
160    fn encode_item_header<W>(&self, mut to: W, len: u32) -> Result<()>
161    where
162        W: Write,
163    {
164        let mut buf = [0u8; 8];
165        BigEndian::write_u16(&mut buf, 0xFFFE);
166        BigEndian::write_u16(&mut buf[2..], 0xE000);
167        BigEndian::write_u32(&mut buf[4..], len);
168        to.write_all(&buf).context(WriteItemHeaderSnafu)
169    }
170
171    fn encode_item_delimiter<W>(&self, mut to: W) -> Result<()>
172    where
173        W: Write,
174    {
175        let mut buf = [0u8; 8];
176        BigEndian::write_u16(&mut buf, 0xFFFE);
177        BigEndian::write_u16(&mut buf[2..], 0xE00D);
178        // remaining bytes are already zero, so it's ready to write
179        to.write_all(&buf).context(WriteItemDelimiterSnafu)
180    }
181
182    fn encode_sequence_delimiter<W>(&self, mut to: W) -> Result<()>
183    where
184        W: Write,
185    {
186        let mut buf = [0u8; 8];
187        BigEndian::write_u16(&mut buf, 0xFFFE);
188        BigEndian::write_u16(&mut buf[2..], 0xE0DD);
189        // remaining bytes are already zero, so it's ready to write
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::ExplicitVRBigEndianEncoder;
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        0x00, 0x02, 0x00, 0x02,     // (0002,0002) (BE) Media Storage SOP Class UID
227            b'U', b'I',             // VR: UI (UID)
228            0x00, 0x1A,             // Length: 26 bytes (BE)
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        0x00, 0x02, 0x00, 0x10,     // (0002,0010) (BE) Transfer Syntax UID
234            b'U', b'I',             // VR: UI (UID)
235            0x00, 0x14,             // Length: 20 bytes (BE)
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        0x00, 0x08, 0x00, 0x54,     // (0008,0054) (BE) Retrieve AE Title
241            b'A', b'E',             // VR: AE (Application Entity)
242            0x00, 0x06,             // Length: 6 bytes (BE)
243                // String "TITLE"
244                b'T', b'I', b'T', b'L', b'E',
245                b' ',               // Padding to make length even
246        0x00, 0x10, 0x10, 0x10,     // (0010,1010) (BE) Patient's Age
247            b'A', b'S',             // VR: AS (Age String)
248            0x00, 0x02,             // Length: 2 bytes (BE)
249                // String "8Y"
250                b'8', b'Y',
251        0x00, 0x72, 0x00, 0x26,     // (0072,0026) (BE) Selector Attribute
252            b'A', b'T',             // VR: AT (Attribute Tag)
253            0x00, 0x04,             // Length: 4 bytes (BE)
254                // Tag: (0028,2110) (BE) Lossy Image Compression
255                0x00, 0x28, 0x21, 0x10,
256        0x00, 0x10, 0x00, 0x40,     // (0010,0040) (BE) Patient Sex
257            b'C', b'S',             // VR: CS (Code String)
258            0x00, 0x02,             // Length: 2 bytes (BE)
259                // Text: "O"
260                b'O',
261                b' ',               // Padding to make length even
262        0x00, 0x10, 0x00, 0x30,     // (0010,0030) (BE) Patient's Birth Date
263            b'D', b'A',             // VR: DA (Date)
264            0x00, 0x08,             // Length: 8 bytes (BE)
265                // String "19800101"
266                b'1', b'9', b'8', b'0', b'0', b'1', b'0', b'1',
267        0x00, 0x10, 0x10, 0x20,     // (0010,1020) (BE) Patient's size
268            b'D', b'S',             // VR: DS (Decimal String)
269            0x00, 0x04,             // Length: 4 bytes (BE)
270                // String: "1.70"
271                b'1', b'.', b'7', b'0',
272        0x00, 0x08, 0x00, 0x15,     // (0008,0015) (BE) Instance coercion datetime
273            b'D', b'T',             // VR: DT (Date Time)
274            0x00, 0x0E,             // Length: 14 bytes (BE)
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        0x00, 0x10, 0x94, 0x31,     // (0010,9431) (BE) Examined Body Thickness
278            b'F', b'L',             // VR: FL (Floating-point IEEE-754)
279            0x00, 0x04,             // Length: 4 bytes (BE)
280                // Value: 3.1415927 (BE)
281                0x40, 0x49, 0x0F, 0xDB,
282        0x00, 0x40, 0x92, 0x25,     // (0040,9225) (BE) Real World Value Slope
283            b'F', b'D',             // VR: FD (Double-precision floating-point IEEE-754)
284            0x00, 0x08,             // Length: 8 bytes (BE)
285                // Value: 3.141592653589793 (BE)
286                0x40, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18,
287        0x00, 0x20, 0x00, 0x13,     // (0020,0013) (BE) Instance Number
288            b'I', b'S',             // VR: IS (Integer String)
289            0x00, 0x08,             // Length: 8 bytes (BE)
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        0x00, 0x10, 0x00, 0x20,     // (0010,0020) (BE) Patient ID
294            b'L', b'O',             // VR: LO (Long string)
295            0x00, 0x0A,             // Length: 10 bytes (BE)
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        0x00, 0x10, 0x40, 0x00,     // (0010,4000) (BE) Patient Comments
299            b'L', b'T',             // VR: LT (Long Text)
300            0x00, 0x04,             // Length: 4 bytes (BE)
301                // String "None"
302                b'N', b'o', b'n', b'e',
303        0x00, 0x08, 0x04, 0x1B,     // (0008,041B) (BE) RecordKey
304            b'O', b'B',             // VR: OB (Other Byte)
305            0x00, 0x00,             // Reserved, always 0
306            0x00, 0x00, 0x00, 0x02, // Length: 2 bytes (BE)
307                // Value: [0x12, 0x34]
308                0x12, 0x34,
309        0x7F, 0xE0, 0x00, 0x09,     // (7FE0,0009) (BE) Double Float Pixel Data
310            b'O', b'D',             // VR: OD (Other Double)
311            0x00, 0x00,             // Reserved, always 0
312            0x00, 0x00, 0x00, 0x08, // Length: 8 bytes (BE)
313                // Value: [3.141592653589793] (BE)
314                0x40, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18,
315        0x7F, 0xE0, 0x00, 0x08,     // (7FE0,0008) (BE) Float Pixel Data
316            b'O', b'F',             // VR: OF (Other Float)
317            0x00, 0x00,             // Reserved, always 0
318            0x00, 0x00, 0x00, 0x04, // Length: 4 bytes (BE)
319                // Value: [3.1415927] (BE)
320                0x40, 0x49, 0x0F, 0xDB,
321        0x00, 0x72, 0x00, 0x75,     // (0072,0075) (BE) Selector OL Value
322            b'O', b'L',             // VR: OL (Other Long)
323            0x00, 0x00,             // Reserved, always 0
324            0x00, 0x00, 0x00, 0x04, // Length: 4 bytes (BE)
325                // Value: [0x12345678] (BE)
326                0x12, 0x34, 0x56, 0x78,
327        0x00, 0x72, 0x00, 0x81,     // (0072,0081) (BE) Selector OV Value
328            b'O', b'V',             // VR: OV (Other Very long)
329            0x00, 0x00,             // Reserved, always 0
330            0x00, 0x00, 0x00, 0x08, // Length: 8 bytes (BE)
331                // Value: [0x192A3B4C5D6E7F80] (BE)
332                0x19, 0x2A, 0x3B, 0x4C, 0x5D, 0x6E, 0x7F, 0x80,
333        0x00, 0x72, 0x00, 0x69,     // (0072,0069) (BE) Selector OW Value
334            b'O', b'W',             // VR: OW (Other Word)
335            0x00, 0x00,             // Reserved, always 0
336            0x00, 0x00, 0x00, 0x02, // Length: 2 bytes (BE)
337                // Value: [0x1234] (BE)
338                0x12, 0x34,
339        0x00, 0x10, 0x00, 0x10,     // (0010,0010) (BE) Patient Name
340            b'P', b'N',             // VR: PN (Person Name)
341            0x00, 0x08,             // Length: 8 bytes (BE)
342                // String: "Doe^John"
343                b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
344        0x00, 0x40, 0x92, 0x10,     // (0040,9210) (BE) LUT Label
345            b'S', b'H',             // VR: SH (Short string)
346            0x00, 0x04,             // Length: 4 bytes (BE)
347                // String: "LBL"
348                b'L', b'B', b'L',
349                b' ',               // Padding to make length even
350        0x00, 0x18, 0x60, 0x20,     // (0018,6020) (BE) Reference Pixel X0
351            b'S', b'L',             // VR: SL (Signed Long)
352            0x00, 0x04,             // Length: 4 bytes (BE)
353                // Value: -12345678 (BE)
354                0xFF, 0x43, 0x9E, 0xB2,
355        // Sequences (VR: SQ) tested elsewhere
356        0x00, 0x28, 0x95, 0x03,     // (0028,9503) (BE) Vertices of the Region (VM 2-2n)
357            b'S', b'S',             // VR: SS (Signed Short)
358            0x00, 0x04,             // Length: 4 bytes (2 * 2) (BE)
359                // Value: -4567 (BE)
360                0xEE, 0x29,
361                // Value: 4321 (BE)
362                0x10, 0xE1,
363        0x00, 0x40, 0x02, 0x80,     // (0040,0280) (BE) Comments on the Performed Procedure Step
364            b'S', b'T',             // VR: ST (Short Text)
365            0x00, 0x0A,             // Length: 10 bytes (BE)
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        0x00, 0x72, 0x00, 0x82,     // (0072,0082) (BE) SelectorSVValue (VM: 1-n)
369            b'S', b'V',             // VR: SV (Signed Very long)
370            0x00, 0x00,             // Reserved, always 0
371            0x00, 0x00, 0x00, 0x10, // Length: 16 bytes (2 * 8) (BE)
372                // Value: -123456789012345678 (BE)
373                0xFE, 0x49, 0x64, 0xB4, 0x59, 0xCF, 0x0C, 0xB2,
374                // Value: 123456789012345678 (BE)
375                0x01, 0xB6, 0x9B, 0x4B, 0xA6, 0x30, 0xF3, 0x4E,
376        0x00, 0x10, 0x00, 0x32,     // (0010,0032) (BE) Patient's Birth Time
377            b'T', b'M',             // VR: TM (Time)
378            0x00, 0x06,             // Length: 6 bytes (BE)
379                // String: "123456"
380                b'1', b'2', b'3', b'4', b'5', b'6',
381        0x00, 0x08, 0x01, 0x19,     // (0008,0119) (BE) Long Code Value
382            b'U', b'C',             // VR: UC (Unlimited Characters)
383            0x00, 0x00,             // Reserved, always 0
384            0x00, 0x00, 0x00, 0x04, // Length: 4 bytes (BE)
385                // String: "Code"
386                b'C', b'o', b'd', b'e',
387        // UI already tested above
388        0x00, 0x18, 0x60, 0x16,     // (0018,6016) (BE) Region Flags
389            b'U', b'L',
390            0x00, 0x04,             // Length: 4 bytes (BE)
391                // Value: 1 (BE)
392                0x00, 0x00, 0x00, 0x01,
393        0xC0, 0x01, 0x12, 0x34,     // (C001,1234) (BE) (Private data element)
394            b'U', b'N',             // VR: UN (Unknown)
395            0x00, 0x00,             // Reserved, always 0
396            0x00, 0x00, 0x00, 0x06, // Length: 6 bytes (BE)
397                // Value: [0x01, 0x02, 0x03, 0x04, 0x05, 0x06]
398                0x01, 0x02, 0x03, 0x04, 0x05, 0x06,
399        0x00, 0x08, 0x01, 0x0E,     // (0008,010E) (BE) Coding Scheme URL
400            b'U', b'R',             // VR: UR (Universal Resource Locator, URL)
401            0x00, 0x00,             // Reserved, always 0
402            0x00, 0x00, 0x00, 0x12, // Length: 18 bytes (BE)
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        0x00, 0x08, 0x00, 0x40,     // (0008,0040) (BE) Data Set Type
407            b'U', b'S',             // VR: US (Unsigned Short)
408            0x00, 0x02,             // Length: 2 bytes (BE)
409                // Value: 34567 (BE)
410                0x87, 0x07,
411        0x00, 0x18, 0x99, 0x17,     // (0018,9917) (BE) Instruction Description
412            b'U', b'T',             // VR: UT (Unlimited Text)
413            0x00, 0x00,             // Reserved, always 0
414            0x00, 0x00, 0x00, 0x08, // Length: 8 bytes (BE)
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        0x00, 0x08, 0x04, 0x0C,     // (0008,040C) (BE) File Offset in Container
419            b'U', b'V',             // VR: UV (Unsigned Very long)
420            0x00, 0x00,             // Reserved, always 0
421            0x00, 0x00, 0x00, 0x08, // Length: 8 bytes (BE)
422                // Value: 12345678901234567890 (BE)
423                0xAB, 0x54, 0xA9, 0x8C, 0xEB, 0x1F, 0x0A, 0xD2,
424    ];
425
426    #[test]
427    fn encode_explicit_vr_be() {
428        let mut buf = vec![0u8; RAW.len()];
429
430        let enc = ExplicitVRBigEndianEncoder::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: &ExplicitVRBigEndianEncoder,
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(
463                Tag(group, element),
464                vr,
465                Length(value.len() as u32),
466            );
467            let _written_len = enc
468                .encode_element_header(&mut writer, de)
469                .expect("should write it fine");
470            writer.write_all(value).expect("should write the value fine");
471            let to = writer.position() as usize;
472
473            // Compare the current slice
474            if &writer.get_ref()[from..to] != &RAW[from..to] {
475                panic!(
476                    "Failure on ({:04x},{:04x})  {:?}  {:02x?}\n\
477                    Expected: {:02x?}",
478                    group,
479                    element,
480                    vr,
481                    value,
482                    &RAW[from..to],
483                );
484            }
485        }
486
487        write_elem(&enc, &mut writer, 0x0008, 0x0054, VR::AE, b"TITLE ");
488        write_elem(&enc, &mut writer, 0x0010, 0x1010, VR::AS, b"8Y");
489        write_elem(
490            &enc,
491            &mut writer,
492            0x0072,
493            0x0026,
494            VR::AT,
495            &[0x00, 0x28, 0x21, 0x10],
496        );
497        write_elem(&enc, &mut writer, 0x0010, 0x0040, VR::CS, b"O ");
498        write_elem(&enc, &mut writer, 0x0010, 0x0030, VR::DA, b"19800101");
499        write_elem(&enc, &mut writer, 0x0010, 0x1020, VR::DS, b"1.70");
500        write_elem(
501            &enc,
502            &mut writer,
503            0x0008,
504            0x0015,
505            VR::DT,
506            b"20051231235960",
507        );
508        write_elem(
509            &enc,
510            &mut writer,
511            0x0010,
512            0x9431,
513            VR::FL,
514            &[0x40, 0x49, 0x0F, 0xDB],
515        );
516        write_elem(
517            &enc,
518            &mut writer,
519            0x0040,
520            0x9225,
521            VR::FD,
522            &[0x40, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18],
523        );
524        write_elem(&enc, &mut writer, 0x0020, 0x0013, VR::IS, b"1234567 ");
525        write_elem(&enc, &mut writer, 0x0010, 0x0020, VR::LO, b"P12345678X");
526        write_elem(&enc, &mut writer, 0x0010, 0x4000, VR::LT, b"None");
527        write_elem(&enc, &mut writer, 0x0008, 0x041B, VR::OB, &[0x12, 0x34]);
528        write_elem(
529            &enc,
530            &mut writer,
531            0x7FE0,
532            0x0009,
533            VR::OD,
534            &[0x40, 0x09, 0x21, 0xFB, 0x54, 0x44, 0x2D, 0x18],
535        );
536        write_elem(
537            &enc,
538            &mut writer,
539            0x7FE0,
540            0x0008,
541            VR::OF,
542            &[0x40, 0x49, 0x0F, 0xDB],
543        );
544        write_elem(
545            &enc,
546            &mut writer,
547            0x0072,
548            0x0075,
549            VR::OL,
550            &[0x12, 0x34, 0x56, 0x78],
551        );
552        write_elem(
553            &enc,
554            &mut writer,
555            0x0072,
556            0x0081,
557            VR::OV,
558            &[0x19, 0x2A, 0x3B, 0x4C, 0x5D, 0x6E, 0x7F, 0x80],
559        );
560        write_elem(&enc, &mut writer, 0x0072, 0x0069, VR::OW, &[0x12, 0x34]);
561        write_elem(&enc, &mut writer, 0x0010, 0x0010, VR::PN, b"Doe^John");
562        write_elem(&enc, &mut writer, 0x0040, 0x9210, VR::SH, b"LBL ");
563        write_elem(
564            &enc,
565            &mut writer,
566            0x0018,
567            0x6020,
568            VR::SL,
569            &[0xFF, 0x43, 0x9E, 0xB2],
570        );
571        write_elem(
572            &enc,
573            &mut writer,
574            0x0028,
575            0x9503,
576            VR::SS,
577            &[0xEE, 0x29, 0x10, 0xE1],
578        );
579        write_elem(&enc, &mut writer, 0x0040, 0x0280, VR::ST, b"No comment");
580        write_elem(
581            &enc,
582            &mut writer,
583            0x0072,
584            0x0082,
585            VR::SV,
586            &[
587                0xFE, 0x49, 0x64, 0xB4, 0x59, 0xCF, 0x0C, 0xB2, 0x01, 0xB6, 0x9B, 0x4B, 0xA6, 0x30,
588                0xF3, 0x4E,
589            ],
590        );
591        write_elem(&enc, &mut writer, 0x0010, 0x0032, VR::TM, b"123456");
592        write_elem(&enc, &mut writer, 0x0008, 0x0119, VR::UC, b"Code");
593        write_elem(
594            &enc,
595            &mut writer,
596            0x0018,
597            0x6016,
598            VR::UL,
599            &[0x00, 0x00, 0x00, 0x01],
600        );
601        write_elem(
602            &enc,
603            &mut writer,
604            0xC001,
605            0x1234,
606            VR::UN,
607            &[0x1, 0x2, 0x3, 0x4, 0x5, 0x6],
608        );
609        write_elem(
610            &enc,
611            &mut writer,
612            0x0008,
613            0x010E,
614            VR::UR,
615            b"http://example.com",
616        );
617        write_elem(&enc, &mut writer, 0x0008, 0x0040, VR::US, &[0x87, 0x07]);
618        write_elem(&enc, &mut writer, 0x0018, 0x9917, VR::UT, b"No text ");
619        write_elem(
620            &enc,
621            &mut writer,
622            0x0008,
623            0x040C,
624            VR::UV,
625            &[0xAB, 0x54, 0xA9, 0x8C, 0xEB, 0x1F, 0x0A, 0xD2],
626        );
627
628        assert_eq!(&buf[..], &RAW[..]);
629    }
630
631    // manually crafting some DICOM sequence/item delimiters
632    //  Tag: (0008,103F) Series Description Code Sequence
633    //  VR: SQ
634    //  Reserved bytes: 0x0000
635    //  Length: 0xFFFF_FFFF
636    // --
637    //  Tag: (FFFE,E000) Item
638    //  Length: 0xFFFF_FFFF (unspecified)
639    // --
640    //  Tag: (FFFE,E00D) Item Delimitation Item
641    //  Length: 0
642    // --
643    //  Tag: (FFFE,E0DD) Sequence Delimitation Item
644    //  Length: 0
645    // --
646    const RAW_SEQUENCE_ITEMS: &[u8] = &[
647        0x00, 0x08, 0x10, 0x3F, b'S', b'Q', 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xE0,
648        0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xE0, 0x0D, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFE,
649        0xE0, 0xDD, 0x00, 0x00, 0x00, 0x00,
650    ];
651
652    #[test]
653    fn encode_items() -> Result {
654        let enc = ExplicitVRBigEndianEncoder::default();
655        let mut out = Vec::new();
656
657        {
658            let bytes_written = enc.encode_element_header(
659                &mut out,
660                DataElementHeader::new(Tag(0x0008, 0x103F), VR::SQ, Length::UNDEFINED),
661            )?;
662            assert_eq!(bytes_written, 12);
663        }
664        assert_eq!(out.len(), 12);
665
666        enc.encode_item_header(&mut out, Length::UNDEFINED.0)?;
667        assert_eq!(out.len(), 20);
668
669        enc.encode_item_delimiter(&mut out)?;
670        assert_eq!(out.len(), 28);
671
672        enc.encode_sequence_delimiter(&mut out)?;
673
674        assert_eq!(&out[..], RAW_SEQUENCE_ITEMS);
675
676        Ok(())
677    }
678}