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(
434 &dec,
435 &mut cursor,
436 0x0008,
437 0x0015,
438 VR::DT,
439 b"20051231235960",
440 );
441 test_vr(
442 &dec,
443 &mut cursor,
444 0x0010,
445 0x9431,
446 VR::FL,
447 &[0xDB, 0x0F, 0x49, 0x40],
448 );
449 test_vr(
450 &dec,
451 &mut cursor,
452 0x0040,
453 0x9225,
454 VR::FD,
455 &[0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40],
456 );
457 test_vr(&dec, &mut cursor, 0x0020, 0x0013, VR::IS, b"1234567 ");
458 test_vr(&dec, &mut cursor, 0x0010, 0x0020, VR::LO, b"P12345678X");
459 test_vr(&dec, &mut cursor, 0x0010, 0x4000, VR::LT, b"None");
460 test_vr(&dec, &mut cursor, 0x0008, 0x041B, VR::OB, &[0x12, 0x34]);
461 test_vr(
462 &dec,
463 &mut cursor,
464 0x7FE0,
465 0x0009,
466 VR::OD,
467 &[0x18, 0x2D, 0x44, 0x54, 0xFB, 0x21, 0x09, 0x40],
468 );
469 test_vr(
470 &dec,
471 &mut cursor,
472 0x7FE0,
473 0x0008,
474 VR::OF,
475 &[0xDB, 0x0F, 0x49, 0x40],
476 );
477 test_vr(
478 &dec,
479 &mut cursor,
480 0x0072,
481 0x0075,
482 VR::OL,
483 &[0x78, 0x56, 0x34, 0x12],
484 );
485 test_vr(
486 &dec,
487 &mut cursor,
488 0x0072,
489 0x0081,
490 VR::OV,
491 &[0x80, 0x7F, 0x6E, 0x5D, 0x4C, 0x3B, 0x2A, 0x19],
492 );
493 test_vr(&dec, &mut cursor, 0x0072, 0x0069, VR::OW, &[0x34, 0x12]);
494 test_vr(&dec, &mut cursor, 0x0010, 0x0010, VR::PN, b"Doe^John");
495 test_vr(&dec, &mut cursor, 0x0040, 0x9210, VR::SH, b"LBL ");
496 test_vr(
497 &dec,
498 &mut cursor,
499 0x0018,
500 0x6020,
501 VR::SL,
502 &[0xB2, 0x9E, 0x43, 0xFF],
503 );
504 test_vr(
505 &dec,
506 &mut cursor,
507 0x0028,
508 0x9503,
509 VR::SS,
510 &[0x29, 0xEE, 0xE1, 0x10],
511 );
512 test_vr(&dec, &mut cursor, 0x0040, 0x0280, VR::ST, b"No comment");
513 test_vr(
514 &dec,
515 &mut cursor,
516 0x0072,
517 0x0082,
518 VR::SV,
519 &[
520 0xB2, 0x0C, 0xCF, 0x59, 0xB4, 0x64, 0x49, 0xFE, 0x4E, 0xF3, 0x30, 0xA6, 0x4B, 0x9B,
521 0xB6, 0x01,
522 ],
523 );
524 test_vr(&dec, &mut cursor, 0x0010, 0x0032, VR::TM, b"123456");
525 test_vr(&dec, &mut cursor, 0x0008, 0x0119, VR::UC, b"Code");
526 test_vr(
527 &dec,
528 &mut cursor,
529 0x0018,
530 0x6016,
531 VR::UL,
532 &[0x01, 0x00, 0x00, 0x00],
533 );
534 test_vr(
535 &dec,
536 &mut cursor,
537 0xC001,
538 0x1234,
539 VR::UN,
540 &[0x1, 0x2, 0x3, 0x4, 0x5, 0x6],
541 );
542 test_vr(
543 &dec,
544 &mut cursor,
545 0x0008,
546 0x010E,
547 VR::UR,
548 b"http://example.com",
549 );
550 test_vr(&dec, &mut cursor, 0x0008, 0x0040, VR::US, &[0x07, 0x87]);
551 test_vr(&dec, &mut cursor, 0x0018, 0x9917, VR::UT, b"No text ");
552 test_vr(
553 &dec,
554 &mut cursor,
555 0x0008,
556 0x040C,
557 VR::UV,
558 &[0xD2, 0x0A, 0x1F, 0xEB, 0x8C, 0xA9, 0x54, 0xAB],
559 );
560 }
561
562 // manually crafting some DICOM sequence/item delimiters
563 // Tag: (0008,103F) Series Description Code Sequence
564 // VR: SQ
565 // Reserved bytes: 0x0000
566 // Length: 0xFFFF_FFFF
567 // --
568 // Tag: (FFFE,E000) Item
569 // Length: 0xFFFF_FFFF (unspecified)
570 // --
571 // Tag: (FFFE,E00D) Item Delimitation Item
572 // Length: 0
573 // --
574 // Tag: (FFFE,E0DD) Sequence Delimitation Item
575 // Length: 0
576 // --
577 const RAW_SEQUENCE_ITEMS: &[u8] = &[
578 0x08, 0x00, 0x3F, 0x10, b'S', b'Q', 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x00,
579 0xE0, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, 0xFF, 0x0D, 0xE0, 0x00, 0x00, 0x00, 0x00, 0xFE, 0xFF,
580 0xDD, 0xE0, 0x00, 0x00, 0x00, 0x00,
581 ];
582
583 #[test]
584 fn decode_items() {
585 let dec = ExplicitVRLittleEndianDecoder::default();
586 let mut cursor = Cursor::new(RAW_SEQUENCE_ITEMS);
587 {
588 // read first element
589 let (elem, bytes_read) = dec
590 .decode_header(&mut cursor)
591 .expect("should find an element header");
592 assert_eq!(elem.tag(), Tag(8, 0x103F));
593 assert_eq!(elem.vr(), VR::SQ);
594 assert!(elem.length().is_undefined());
595 assert_eq!(bytes_read, 12);
596 }
597 // cursor should now be @ #12
598 assert_eq!(cursor.stream_position().unwrap(), 12);
599 {
600 let elem = dec
601 .decode_item_header(&mut cursor)
602 .expect("should find an item header");
603 assert!(elem.is_item());
604 assert_eq!(elem.tag(), Tag(0xFFFE, 0xE000));
605 assert!(elem.length().is_undefined());
606 }
607 // cursor should now be @ #20
608 assert_eq!(cursor.stream_position().unwrap(), 20);
609 {
610 let elem = dec
611 .decode_item_header(&mut cursor)
612 .expect("should find an item header");
613 assert!(elem.is_item_delimiter());
614 assert_eq!(elem.tag(), Tag(0xFFFE, 0xE00D));
615 assert_eq!(elem.length(), Length(0));
616 }
617 // cursor should now be @ #28
618 assert_eq!(cursor.stream_position().unwrap(), 28);
619 {
620 let elem = dec
621 .decode_item_header(&mut cursor)
622 .expect("should find an item header");
623 assert!(elem.is_sequence_delimiter());
624 assert_eq!(elem.tag(), Tag(0xFFFE, 0xE0DD));
625 assert_eq!(elem.length(), Length(0));
626 }
627 }
628}