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