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            VR::OB
100            | VR::OD
101            | VR::OF
102            | VR::OL
103            | VR::OW
104            | VR::SQ
105            | VR::UC
106            | VR::UR
107            | VR::UT
108            | VR::UN => {
109                let mut buf = [0u8; 12];
110                LittleEndian::write_u16(&mut buf[0..], de.tag().group());
111                LittleEndian::write_u16(&mut buf[2..], de.tag().element());
112                let vr_bytes = de.vr().to_bytes();
113                buf[4] = vr_bytes[0];
114                buf[5] = vr_bytes[1];
115                // buf[6..8] is kept zero'd
116                LittleEndian::write_u32(&mut buf[8..], de.length().0);
117                to.write_all(&buf).context(WriteHeaderSnafu)?;
118                Ok(12)
119            }
120            _ => {
121                let mut buf = [0u8; 8];
122                LittleEndian::write_u16(&mut buf[0..], de.tag().group());
123                LittleEndian::write_u16(&mut buf[2..], de.tag().element());
124                let vr_bytes = de.vr().to_bytes();
125                buf[4] = vr_bytes[0];
126                buf[5] = vr_bytes[1];
127                LittleEndian::write_u16(&mut buf[6..], de.length().0 as u16);
128                to.write_all(&buf).context(WriteHeaderSnafu)?;
129                Ok(8)
130            }
131        }
132    }
133
134    fn encode_item_header<W>(&self, mut to: W, len: u32) -> Result<()>
135    where
136        W: Write,
137    {
138        let mut buf = [0u8; 8];
139        LittleEndian::write_u16(&mut buf, 0xFFFE);
140        LittleEndian::write_u16(&mut buf[2..], 0xE000);
141        LittleEndian::write_u32(&mut buf[4..], len);
142        to.write_all(&buf).context(WriteItemHeaderSnafu)
143    }
144
145    fn encode_item_delimiter<W>(&self, mut to: W) -> Result<()>
146    where
147        W: Write,
148    {
149        let mut buf = [0u8; 8];
150        LittleEndian::write_u16(&mut buf, 0xFFFE);
151        LittleEndian::write_u16(&mut buf[2..], 0xE00D);
152        to.write_all(&buf).context(WriteItemDelimiterSnafu)
153    }
154
155    fn encode_sequence_delimiter<W>(&self, mut to: W) -> Result<()>
156    where
157        W: Write,
158    {
159        let mut buf = [0u8; 8];
160        LittleEndian::write_u16(&mut buf, 0xFFFE);
161        LittleEndian::write_u16(&mut buf[2..], 0xE0DD);
162        to.write_all(&buf).context(WriteSequenceDelimiterSnafu)
163    }
164
165    fn encode_primitive<W>(&self, to: W, value: &PrimitiveValue) -> Result<usize>
166    where
167        W: Write,
168    {
169        self.basic.encode_primitive(to, value)
170    }
171
172    fn encode_offset_table<W>(&self, mut to: W, offset_table: &[u32]) -> Result<usize>
173    where
174        W: Write,
175    {
176        for v in offset_table {
177            self.basic
178                .encode_ul(&mut to, *v)
179                .context(WriteOffsetTableSnafu)?;
180        }
181        Ok(offset_table.len() * 4)
182    }
183}
184
185#[cfg(test)]
186mod tests {
187    use super::ExplicitVRLittleEndianEncoder;
188    use crate::encode::Encode;
189    use dicom_core::header::{DataElementHeader, Length};
190    use dicom_core::{Tag, VR};
191    use std::io::{Cursor, Write};
192
193    type Result = std::result::Result<(), Box<dyn std::error::Error>>;
194
195    // manually crafting some DICOM data elements
196    //  Tag: (0002,0002) Media Storage SOP Class UID
197    //  VR: UI
198    //  Length: 26
199    //  Value: "1.2.840.10008.5.1.4.1.1.1\0"
200    // --
201    //  Tag: (0002,0010) Transfer Syntax UID
202    //  VR: UI
203    //  Length: 20
204    //  Value: "1.2.840.10008.1.2.1\0" == ExplicitVRLittleEndian
205    // --
206    const RAW: &'static [u8; 62] = &[
207        0x02, 0x00, 0x02, 0x00, 0x55, 0x49, 0x1a, 0x00, 0x31, 0x2e, 0x32, 0x2e, 0x38, 0x34, 0x30,
208        0x2e, 0x31, 0x30, 0x30, 0x30, 0x38, 0x2e, 0x35, 0x2e, 0x31, 0x2e, 0x34, 0x2e, 0x31, 0x2e,
209        0x31, 0x2e, 0x31, 0x00, 0x02, 0x00, 0x10, 0x00, 0x55, 0x49, 0x14, 0x00, 0x31, 0x2e, 0x32,
210        0x2e, 0x38, 0x34, 0x30, 0x2e, 0x31, 0x30, 0x30, 0x30, 0x38, 0x2e, 0x31, 0x2e, 0x32, 0x2e,
211        0x31, 0x00,
212    ];
213
214    #[test]
215    fn encode_data_elements() {
216        let mut buf = [0u8; 62];
217        {
218            let enc = ExplicitVRLittleEndianEncoder::default();
219            let mut writer = Cursor::new(&mut buf[..]);
220
221            // encode first element
222            let de = DataElementHeader::new(Tag(0x0002, 0x0002), VR::UI, Length(26));
223            let len = enc
224                .encode_element_header(&mut writer, de)
225                .expect("should write it fine");
226            assert_eq!(len, 8);
227            writer
228                .write_all(b"1.2.840.10008.5.1.4.1.1.1\0".as_ref())
229                .expect("should write the value fine");
230        }
231        assert_eq!(&buf[0..8], &RAW[0..8]);
232        {
233            let enc = ExplicitVRLittleEndianEncoder::default();
234            let mut writer = Cursor::new(&mut buf[34..]);
235
236            // encode second element
237            let de = DataElementHeader::new(Tag(0x0002, 0x0010), VR::UI, Length(20));
238            let len = enc
239                .encode_element_header(&mut writer, de)
240                .expect("should write it fine");
241            assert_eq!(len, 8);
242            writer
243                .write_all(b"1.2.840.10008.1.2.1\0".as_ref())
244                .expect("should write the value fine");
245        }
246        assert_eq!(&buf[34..42], &RAW[34..42]);
247
248        assert_eq!(&buf[..], &RAW[..]);
249    }
250
251    // manually crafting some DICOM sequence/item delimiters
252    //  Tag: (0008,103F) Series Description Code Sequence
253    //  VR: SQ
254    //  Reserved bytes: 0x0000
255    //  Length: 0xFFFF_FFFF
256    // --
257    //  Tag: (FFFE,E000) Item
258    //  Length: 0xFFFF_FFFF (unspecified)
259    // --
260    //  Tag: (FFFE,E00D) Item Delimitation Item
261    //  Length: 0
262    // --
263    //  Tag: (FFFE,E0DD) Sequence Delimitation Item
264    //  Length: 0
265    // --
266    const RAW_SEQUENCE_ITEMS: &'static [u8] = &[
267        0x08, 0x00, 0x3F, 0x10, b'S', b'Q', 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00,
268        0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x0D, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF,
269        0xDD, 0xE0, 0x00, 0x00, 0x00, 0x00,
270    ];
271
272    #[test]
273    fn encode_items() -> Result {
274        let enc = ExplicitVRLittleEndianEncoder::default();
275        let mut out = Vec::new();
276
277        {
278            let bytes_written = enc.encode_element_header(
279                &mut out,
280                DataElementHeader::new(Tag(0x0008, 0x103F), VR::SQ, Length::UNDEFINED),
281            )?;
282            assert_eq!(bytes_written, 12);
283        }
284        assert_eq!(out.len(), 12);
285
286        enc.encode_item_header(&mut out, Length::UNDEFINED.0)?;
287        assert_eq!(out.len(), 20);
288
289        enc.encode_item_delimiter(&mut out)?;
290        assert_eq!(out.len(), 28);
291
292        enc.encode_sequence_delimiter(&mut out)?;
293
294        assert_eq!(&out[..], RAW_SEQUENCE_ITEMS);
295
296        Ok(())
297    }
298}