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