Skip to main content

dicom_toolkit_data/io/
reader.rs

1//! DICOM Part 10 file reader.
2//!
3//! Reads binary DICOM files into a `FileFormat` or raw `DataSet`.
4
5use crate::dataset::DataSet;
6use crate::element::Element;
7use crate::file_format::FileFormat;
8use crate::io::transfer::{implicit_vr_for_tag, TransferSyntaxProperties};
9use crate::meta_info::FileMetaInformation;
10use crate::value::{DicomDate, DicomDateTime, DicomTime, PersonName, PixelData, Value};
11use dicom_toolkit_core::charset::DicomCharsetDecoder;
12use dicom_toolkit_core::error::{DcmError, DcmResult};
13use dicom_toolkit_dict::{tags, Tag, Vr};
14use std::io::Read;
15
16/// Streaming DICOM reader.
17pub struct DicomReader<R: Read> {
18    reader: R,
19}
20
21impl<R: Read> DicomReader<R> {
22    pub fn new(reader: R) -> Self {
23        Self { reader }
24    }
25
26    /// Read a complete DICOM Part 10 file.
27    pub fn read_file(&mut self) -> DcmResult<FileFormat> {
28        let mut data = Vec::new();
29        self.reader.read_to_end(&mut data)?;
30        parse_file(&data)
31    }
32
33    /// Read a raw dataset (no preamble/meta) using the given transfer syntax UID.
34    pub fn read_dataset(&mut self, ts_uid: &str) -> DcmResult<DataSet> {
35        let mut data = Vec::new();
36        self.reader.read_to_end(&mut data)?;
37        let props = TransferSyntaxProperties::from_uid(ts_uid);
38        let actual: std::borrow::Cow<[u8]> = if props.is_deflated {
39            std::borrow::Cow::Owned(decompress_deflated(&data)?)
40        } else {
41            std::borrow::Cow::Borrowed(&data)
42        };
43        let mut cursor = DicomCursor::new(&actual);
44        cursor.read_dataset_impl(
45            props.is_explicit_vr(),
46            props.is_little_endian(),
47            actual.len(),
48        )
49    }
50}
51
52// ── Internal parse entry point ────────────────────────────────────────────────
53
54pub(crate) fn parse_file(data: &[u8]) -> DcmResult<FileFormat> {
55    // Short files without preamble — try raw implicit VR LE
56    if data.len() < 132 {
57        let mut cursor = DicomCursor::new(data);
58        let ds = cursor.read_dataset_impl(false, true, data.len())?;
59        let meta = FileMetaInformation::new("", "", "1.2.840.10008.1.2");
60        return Ok(FileFormat::new(meta, ds));
61    }
62
63    let has_dicm = &data[128..132] == b"DICM";
64
65    if !has_dicm {
66        // No magic: try implicit VR LE from the start
67        let mut cursor = DicomCursor::new(data);
68        let ds = cursor.read_dataset_impl(false, true, data.len())?;
69        let meta = FileMetaInformation::new("", "", "1.2.840.10008.1.2");
70        return Ok(FileFormat::new(meta, ds));
71    }
72
73    let mut cursor = DicomCursor::new(data);
74    cursor.pos = 132; // skip 128-byte preamble + "DICM"
75
76    // Read File Meta Information (always explicit VR LE)
77    let meta_ds = cursor.read_meta()?;
78    let meta = FileMetaInformation::from_dataset(&meta_ds)?;
79    let ts_uid = meta.transfer_syntax_uid.clone();
80    let props = TransferSyntaxProperties::from_uid(&ts_uid);
81
82    let dataset = if props.is_deflated {
83        let remaining = &data[cursor.pos..];
84        let decompressed = decompress_deflated(remaining)?;
85        let mut dc = DicomCursor::new(&decompressed);
86        dc.read_dataset_impl(true, true, decompressed.len())?
87    } else {
88        cursor.read_dataset_impl(props.is_explicit_vr(), props.is_little_endian(), data.len())?
89    };
90
91    Ok(FileFormat::new(meta, dataset))
92}
93
94fn decompress_deflated(data: &[u8]) -> DcmResult<Vec<u8>> {
95    use flate2::read::DeflateDecoder;
96    let mut decoder = DeflateDecoder::new(data);
97    let mut out = Vec::new();
98    decoder.read_to_end(&mut out).map_err(DcmError::Io)?;
99    Ok(out)
100}
101
102// ── Cursor ────────────────────────────────────────────────────────────────────
103
104struct DicomCursor<'a> {
105    data: &'a [u8],
106    pos: usize,
107    /// Character set decoder, updated when (0008,0005) is encountered.
108    charset: DicomCharsetDecoder,
109}
110
111impl<'a> DicomCursor<'a> {
112    fn new(data: &'a [u8]) -> Self {
113        Self {
114            data,
115            pos: 0,
116            charset: DicomCharsetDecoder::default_ascii(),
117        }
118    }
119
120    // ── Primitives ────────────────────────────────────────────────────────────
121
122    fn read_u8(&mut self) -> DcmResult<u8> {
123        if self.pos >= self.data.len() {
124            return Err(DcmError::UnexpectedEof {
125                offset: self.pos as u64,
126            });
127        }
128        let b = self.data[self.pos];
129        self.pos += 1;
130        Ok(b)
131    }
132
133    fn read_u16(&mut self, le: bool) -> DcmResult<u16> {
134        let a = self.read_u8()?;
135        let b = self.read_u8()?;
136        Ok(if le {
137            u16::from_le_bytes([a, b])
138        } else {
139            u16::from_be_bytes([a, b])
140        })
141    }
142
143    fn read_u32(&mut self, le: bool) -> DcmResult<u32> {
144        let a = self.read_u8()?;
145        let b = self.read_u8()?;
146        let c = self.read_u8()?;
147        let d = self.read_u8()?;
148        Ok(if le {
149            u32::from_le_bytes([a, b, c, d])
150        } else {
151            u32::from_be_bytes([a, b, c, d])
152        })
153    }
154
155    fn read_bytes(&mut self, n: usize) -> DcmResult<&'a [u8]> {
156        if self.pos + n > self.data.len() {
157            return Err(DcmError::UnexpectedEof {
158                offset: self.pos as u64,
159            });
160        }
161        let slice = &self.data[self.pos..self.pos + n];
162        self.pos += n;
163        Ok(slice)
164    }
165
166    fn peek_tag(&self, le: bool) -> DcmResult<Tag> {
167        if self.pos + 4 > self.data.len() {
168            return Err(DcmError::UnexpectedEof {
169                offset: self.pos as u64,
170            });
171        }
172        let g0 = self.data[self.pos];
173        let g1 = self.data[self.pos + 1];
174        let e0 = self.data[self.pos + 2];
175        let e1 = self.data[self.pos + 3];
176        let group = if le {
177            u16::from_le_bytes([g0, g1])
178        } else {
179            u16::from_be_bytes([g0, g1])
180        };
181        let element = if le {
182            u16::from_le_bytes([e0, e1])
183        } else {
184            u16::from_be_bytes([e0, e1])
185        };
186        Ok(Tag::new(group, element))
187    }
188
189    fn read_tag(&mut self, le: bool) -> DcmResult<Tag> {
190        let tag = self.peek_tag(le)?;
191        self.pos += 4;
192        Ok(tag)
193    }
194
195    // ── Meta ──────────────────────────────────────────────────────────────────
196
197    /// Read group 0002 elements (explicit VR LE). Stops when group != 0002.
198    fn read_meta(&mut self) -> DcmResult<DataSet> {
199        let mut meta = DataSet::new();
200        while self.pos + 4 <= self.data.len() {
201            let group = u16::from_le_bytes([self.data[self.pos], self.data[self.pos + 1]]);
202            if group != 0x0002 {
203                break;
204            }
205            let elem = self.read_element(true, true)?;
206            // Skip group-length element — computed at write time
207            if !elem.tag.is_group_length() {
208                meta.insert(elem);
209            }
210        }
211        Ok(meta)
212    }
213
214    // ── Dataset ───────────────────────────────────────────────────────────────
215
216    fn read_dataset_impl(&mut self, explicit: bool, le: bool, end: usize) -> DcmResult<DataSet> {
217        let mut ds = DataSet::new();
218        while self.pos < end && self.pos + 4 <= self.data.len() {
219            let tag = self.peek_tag(le)?;
220
221            // Stop on sequence or item delimitation
222            if tag.is_sequence_delimitation() || tag.is_item_delimitation() {
223                self.pos += 4;
224                let _ = self.read_u32(true); // consume length
225                break;
226            }
227
228            // ITEM tags shouldn't appear at dataset level; stop gracefully
229            if tag.is_item() {
230                break;
231            }
232
233            let elem = self.read_element(explicit, le)?;
234
235            // Update charset decoder when Specific Character Set is encountered
236            if elem.tag == tags::SPECIFIC_CHARACTER_SET {
237                if let Value::Strings(ref terms) = elem.value {
238                    let charset_value = terms.join("\\");
239                    if let Ok(decoder) = DicomCharsetDecoder::new(&charset_value) {
240                        self.charset = decoder;
241                    }
242                }
243            }
244
245            ds.insert(elem);
246        }
247        Ok(ds)
248    }
249
250    // ── Element ───────────────────────────────────────────────────────────────
251
252    fn read_element(&mut self, explicit: bool, le: bool) -> DcmResult<Element> {
253        let tag = self.read_tag(le)?;
254
255        let (vr, len, undef_len) = if tag.is_delimiter() {
256            let len = self.read_u32(true)?;
257            (Vr::UN, len, false)
258        } else if explicit {
259            let vr_b0 = self.read_u8()?;
260            let vr_b1 = self.read_u8()?;
261            let vr = Vr::from_bytes([vr_b0, vr_b1]).unwrap_or(Vr::UN);
262            if vr.has_long_explicit_length() {
263                let _reserved = self.read_u16(le)?;
264                let len = self.read_u32(le)?;
265                (vr, len, len == 0xFFFF_FFFF)
266            } else {
267                let len = self.read_u16(le)? as u32;
268                (vr, len, false)
269            }
270        } else {
271            let len = self.read_u32(le)?;
272            let vr = implicit_vr_for_tag(tag);
273            (vr, len, len == 0xFFFF_FFFF)
274        };
275
276        let value = self.read_value(tag, vr, len, undef_len, explicit, le)?;
277        Ok(Element::new(tag, vr, value))
278    }
279
280    // ── Value ─────────────────────────────────────────────────────────────────
281
282    fn read_value(
283        &mut self,
284        tag: Tag,
285        vr: Vr,
286        len: u32,
287        undef_len: bool,
288        explicit: bool,
289        le: bool,
290    ) -> DcmResult<Value> {
291        match vr {
292            Vr::SQ => {
293                let items = self.read_sequence(len, undef_len, explicit, le)?;
294                Ok(Value::Sequence(items))
295            }
296            _ if tag == tags::PIXEL_DATA => self.read_pixel_data(len, undef_len, le),
297            _ => {
298                if undef_len {
299                    return Err(DcmError::InvalidLength {
300                        group: tag.group,
301                        element: tag.element,
302                        length: 0xFFFF_FFFF,
303                    });
304                }
305                let bytes = self.read_bytes(len as usize)?;
306                parse_value_bytes(vr, bytes, le, &self.charset)
307            }
308        }
309    }
310
311    // ── Sequence ──────────────────────────────────────────────────────────────
312
313    fn read_sequence(
314        &mut self,
315        len: u32,
316        undef_len: bool,
317        explicit: bool,
318        le: bool,
319    ) -> DcmResult<Vec<DataSet>> {
320        let end = if undef_len {
321            usize::MAX
322        } else {
323            self.pos.saturating_add(len as usize)
324        };
325
326        let mut items = Vec::new();
327
328        while self.pos < end && self.pos + 4 <= self.data.len() {
329            let tag = self.peek_tag(le)?;
330
331            if tag.is_sequence_delimitation() {
332                self.pos += 4;
333                let _ = self.read_u32(true);
334                break;
335            }
336
337            if tag.is_item() {
338                self.pos += 4; // consume ITEM tag
339                let item_len = self.read_u32(le)?;
340                let item_undef = item_len == 0xFFFF_FFFF;
341                let item_end = if item_undef {
342                    usize::MAX
343                } else {
344                    self.pos.saturating_add(item_len as usize)
345                };
346                let item_ds = self.read_dataset_impl(explicit, le, item_end)?;
347                items.push(item_ds);
348            } else {
349                break;
350            }
351        }
352
353        Ok(items)
354    }
355
356    // ── Pixel data ────────────────────────────────────────────────────────────
357
358    fn read_pixel_data(&mut self, len: u32, undef_len: bool, le: bool) -> DcmResult<Value> {
359        if !undef_len {
360            let bytes = self.read_bytes(len as usize)?.to_vec();
361            return Ok(Value::PixelData(PixelData::Native { bytes }));
362        }
363
364        // Encapsulated pixel data — undefined length
365        let mut offset_table: Vec<u32> = Vec::new();
366        let mut fragments: Vec<Vec<u8>> = Vec::new();
367        let mut first_item = true;
368
369        loop {
370            if self.pos + 4 > self.data.len() {
371                break;
372            }
373            let tag = self.peek_tag(le)?;
374
375            if tag.is_sequence_delimitation() {
376                self.pos += 4;
377                let _ = self.read_u32(true);
378                break;
379            }
380
381            if tag.is_item() {
382                self.pos += 4;
383                let item_len = self.read_u32(le)?;
384                let item_bytes = self.read_bytes(item_len as usize)?.to_vec();
385
386                if first_item {
387                    // Basic offset table
388                    let n = item_bytes.len() / 4;
389                    for i in 0..n {
390                        let b = &item_bytes[i * 4..i * 4 + 4];
391                        offset_table.push(u32::from_le_bytes([b[0], b[1], b[2], b[3]]));
392                    }
393                    first_item = false;
394                } else {
395                    fragments.push(item_bytes);
396                }
397            } else {
398                break;
399            }
400        }
401
402        Ok(Value::PixelData(PixelData::Encapsulated {
403            offset_table,
404            fragments,
405        }))
406    }
407}
408
409// ── Value byte parser ─────────────────────────────────────────────────────────
410
411fn parse_value_bytes(
412    vr: Vr,
413    bytes: &[u8],
414    le: bool,
415    charset: &DicomCharsetDecoder,
416) -> DcmResult<Value> {
417    if bytes.is_empty() {
418        return Ok(Value::Empty);
419    }
420
421    match vr {
422        Vr::UI => {
423            // UIDs are always ASCII — no charset decoding needed
424            let s = std::str::from_utf8(bytes)
425                .unwrap_or("")
426                .trim_end_matches('\0');
427            Ok(Value::Uid(s.to_string()))
428        }
429
430        // VRs that use the Specific Character Set:
431        // AE, CS are restricted to ASCII in DICOM, but we decode them through
432        // the charset decoder for robustness (some non-conformant files exist).
433        Vr::AE | Vr::AS | Vr::CS | Vr::LO | Vr::SH => {
434            let s = decode_string_with_charset(bytes, charset);
435            let s = s.trim_end_matches('\0').trim_end_matches(' ');
436            let parts: Vec<String> = s.split('\\').map(str::to_string).collect();
437            Ok(Value::Strings(parts))
438        }
439        Vr::LT | Vr::ST | Vr::UT | Vr::UC | Vr::UR => {
440            let s = decode_string_with_charset(bytes, charset);
441            let s = s.trim_end_matches('\0').trim_end_matches(' ').to_string();
442            Ok(Value::Strings(vec![s]))
443        }
444        Vr::PN => {
445            let s = decode_string_with_charset(bytes, charset);
446            let s = s.trim_end_matches('\0').trim_end_matches(' ');
447            if s.is_empty() {
448                return Ok(Value::Empty);
449            }
450            let names: Vec<PersonName> = s.split('\\').map(PersonName::parse).collect();
451            Ok(Value::PersonNames(names))
452        }
453
454        // Numeric-string VRs — always ASCII content, but decoded through charset
455        // for consistent handling of padding.
456        Vr::DA => {
457            let s = decode_ascii_string(bytes);
458            if s.is_empty() {
459                return Ok(Value::Empty);
460            }
461            let res: Result<Vec<_>, _> = s
462                .split('\\')
463                .map(|p| DicomDate::from_da_str(p.trim()))
464                .collect();
465            res.map(Value::Date)
466                .map_err(|_| DcmError::Other("invalid DA value".into()))
467        }
468        Vr::TM => {
469            let s = decode_ascii_string(bytes);
470            if s.is_empty() {
471                return Ok(Value::Empty);
472            }
473            let res: Result<Vec<_>, _> =
474                s.split('\\').map(|p| DicomTime::parse(p.trim())).collect();
475            res.map(Value::Time)
476                .map_err(|_| DcmError::Other("invalid TM value".into()))
477        }
478        Vr::DT => {
479            let s = decode_ascii_string(bytes);
480            if s.is_empty() {
481                return Ok(Value::Empty);
482            }
483            let res: Result<Vec<_>, _> = s
484                .split('\\')
485                .map(|p| DicomDateTime::parse(p.trim()))
486                .collect();
487            res.map(Value::DateTime)
488                .map_err(|_| DcmError::Other("invalid DT value".into()))
489        }
490        Vr::IS => {
491            let s = decode_ascii_string(bytes);
492            if s.is_empty() {
493                return Ok(Value::Empty);
494            }
495            let res: Result<Vec<i64>, _> = s
496                .split('\\')
497                .map(|p| {
498                    p.trim()
499                        .parse::<i64>()
500                        .map_err(|_| DcmError::Other(format!("invalid IS: {p}")))
501                })
502                .collect();
503            res.map(Value::Ints)
504        }
505        Vr::DS => {
506            let s = decode_ascii_string(bytes);
507            if s.is_empty() {
508                return Ok(Value::Empty);
509            }
510            let res: Result<Vec<f64>, _> = s
511                .split('\\')
512                .map(|p| {
513                    p.trim()
514                        .parse::<f64>()
515                        .map_err(|_| DcmError::Other(format!("invalid DS: {p}")))
516                })
517                .collect();
518            res.map(Value::Decimals)
519        }
520
521        Vr::US | Vr::OW => {
522            if bytes.len() % 2 != 0 {
523                return Err(DcmError::Other(format!(
524                    "{} value has odd byte length",
525                    vr.code()
526                )));
527            }
528            let vals: Vec<u16> = bytes
529                .chunks_exact(2)
530                .map(|c| {
531                    if le {
532                        u16::from_le_bytes([c[0], c[1]])
533                    } else {
534                        u16::from_be_bytes([c[0], c[1]])
535                    }
536                })
537                .collect();
538            Ok(Value::U16(vals))
539        }
540        Vr::SS => {
541            if bytes.len() % 2 != 0 {
542                return Err(DcmError::Other("SS value has odd byte length".into()));
543            }
544            let vals: Vec<i16> = bytes
545                .chunks_exact(2)
546                .map(|c| {
547                    if le {
548                        i16::from_le_bytes([c[0], c[1]])
549                    } else {
550                        i16::from_be_bytes([c[0], c[1]])
551                    }
552                })
553                .collect();
554            Ok(Value::I16(vals))
555        }
556        Vr::UL | Vr::OL => {
557            if bytes.len() % 4 != 0 {
558                return Err(DcmError::Other(format!(
559                    "{} value length not multiple of 4",
560                    vr.code()
561                )));
562            }
563            let vals: Vec<u32> = bytes
564                .chunks_exact(4)
565                .map(|c| {
566                    if le {
567                        u32::from_le_bytes([c[0], c[1], c[2], c[3]])
568                    } else {
569                        u32::from_be_bytes([c[0], c[1], c[2], c[3]])
570                    }
571                })
572                .collect();
573            Ok(Value::U32(vals))
574        }
575        Vr::SL => {
576            if bytes.len() % 4 != 0 {
577                return Err(DcmError::Other("SL value length not multiple of 4".into()));
578            }
579            let vals: Vec<i32> = bytes
580                .chunks_exact(4)
581                .map(|c| {
582                    if le {
583                        i32::from_le_bytes([c[0], c[1], c[2], c[3]])
584                    } else {
585                        i32::from_be_bytes([c[0], c[1], c[2], c[3]])
586                    }
587                })
588                .collect();
589            Ok(Value::I32(vals))
590        }
591        Vr::FL | Vr::OF => {
592            if bytes.len() % 4 != 0 {
593                return Err(DcmError::Other(format!(
594                    "{} value length not multiple of 4",
595                    vr.code()
596                )));
597            }
598            let vals: Vec<f32> = bytes
599                .chunks_exact(4)
600                .map(|c| {
601                    if le {
602                        f32::from_le_bytes([c[0], c[1], c[2], c[3]])
603                    } else {
604                        f32::from_be_bytes([c[0], c[1], c[2], c[3]])
605                    }
606                })
607                .collect();
608            Ok(Value::F32(vals))
609        }
610        Vr::FD | Vr::OD => {
611            if bytes.len() % 8 != 0 {
612                return Err(DcmError::Other(format!(
613                    "{} value length not multiple of 8",
614                    vr.code()
615                )));
616            }
617            let vals: Vec<f64> = bytes
618                .chunks_exact(8)
619                .map(|c| {
620                    if le {
621                        f64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]])
622                    } else {
623                        f64::from_be_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]])
624                    }
625                })
626                .collect();
627            Ok(Value::F64(vals))
628        }
629        Vr::SV => {
630            if bytes.len() % 8 != 0 {
631                return Err(DcmError::Other("SV value length not multiple of 8".into()));
632            }
633            let vals: Vec<i64> = bytes
634                .chunks_exact(8)
635                .map(|c| {
636                    if le {
637                        i64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]])
638                    } else {
639                        i64::from_be_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]])
640                    }
641                })
642                .collect();
643            Ok(Value::I64(vals))
644        }
645        Vr::UV | Vr::OV => {
646            if bytes.len() % 8 != 0 {
647                return Err(DcmError::Other(format!(
648                    "{} value length not multiple of 8",
649                    vr.code()
650                )));
651            }
652            let vals: Vec<u64> = bytes
653                .chunks_exact(8)
654                .map(|c| {
655                    if le {
656                        u64::from_le_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]])
657                    } else {
658                        u64::from_be_bytes([c[0], c[1], c[2], c[3], c[4], c[5], c[6], c[7]])
659                    }
660                })
661                .collect();
662            Ok(Value::U64(vals))
663        }
664        Vr::AT => {
665            if bytes.len() % 4 != 0 {
666                return Err(DcmError::Other("AT value length not multiple of 4".into()));
667            }
668            let tags: Vec<Tag> = bytes
669                .chunks_exact(4)
670                .map(|c| {
671                    let g = if le {
672                        u16::from_le_bytes([c[0], c[1]])
673                    } else {
674                        u16::from_be_bytes([c[0], c[1]])
675                    };
676                    let e = if le {
677                        u16::from_le_bytes([c[2], c[3]])
678                    } else {
679                        u16::from_be_bytes([c[2], c[3]])
680                    };
681                    Tag::new(g, e)
682                })
683                .collect();
684            Ok(Value::Tags(tags))
685        }
686        Vr::OB | Vr::UN => Ok(Value::U8(bytes.to_vec())),
687        Vr::SQ => Err(DcmError::Other("parse_value_bytes called for SQ".into())),
688    }
689}
690
691/// Decode a byte slice using the active charset decoder.
692fn decode_string_with_charset(bytes: &[u8], charset: &DicomCharsetDecoder) -> String {
693    charset
694        .decode(bytes)
695        .unwrap_or_else(|_| String::from_utf8_lossy(bytes).into_owned())
696}
697
698/// Decode an ASCII-only string (for numeric VRs like DA, TM, IS, DS).
699fn decode_ascii_string(bytes: &[u8]) -> String {
700    String::from_utf8_lossy(bytes)
701        .trim_end_matches('\0')
702        .trim_end_matches(' ')
703        .to_string()
704}
705
706// ── Tests ─────────────────────────────────────────────────────────────────────
707
708#[cfg(test)]
709mod tests {
710    use super::*;
711    use crate::value::Value;
712    use dicom_toolkit_dict::Vr;
713
714    fn ascii() -> DicomCharsetDecoder {
715        DicomCharsetDecoder::default_ascii()
716    }
717
718    #[test]
719    fn parse_us_bytes() {
720        let bytes = 512u16.to_le_bytes();
721        let v = parse_value_bytes(Vr::US, &bytes, true, &ascii()).unwrap();
722        assert_eq!(v.as_u16(), Some(512));
723    }
724
725    #[test]
726    fn parse_ui_bytes() {
727        let uid = b"1.2.840.10008.1.2.1";
728        let v = parse_value_bytes(Vr::UI, uid, true, &ascii()).unwrap();
729        assert_eq!(v.as_string(), Some("1.2.840.10008.1.2.1"));
730    }
731
732    #[test]
733    fn parse_lo_bytes_backslash() {
734        let s = b"foo\\bar";
735        let v = parse_value_bytes(Vr::LO, s, true, &ascii()).unwrap();
736        match v {
737            Value::Strings(ss) => assert_eq!(ss, &["foo", "bar"]),
738            other => panic!("unexpected: {:?}", other),
739        }
740    }
741
742    #[test]
743    fn parse_ds_bytes() {
744        let s = b"2.78";
745        let v = parse_value_bytes(Vr::DS, s, true, &ascii()).unwrap();
746        match v {
747            Value::Decimals(ds) => assert!((ds[0] - 2.78).abs() < 1e-9),
748            other => panic!("unexpected: {:?}", other),
749        }
750    }
751
752    #[test]
753    fn parse_is_bytes() {
754        let s = b"-42";
755        let v = parse_value_bytes(Vr::IS, s, true, &ascii()).unwrap();
756        match v {
757            Value::Ints(is) => assert_eq!(is[0], -42),
758            other => panic!("unexpected: {:?}", other),
759        }
760    }
761
762    #[test]
763    fn parse_ob_bytes() {
764        let bytes = vec![0xDE, 0xAD, 0xBE, 0xEF];
765        let v = parse_value_bytes(Vr::OB, &bytes, true, &ascii()).unwrap();
766        assert_eq!(v.as_bytes(), Some(bytes.as_slice()));
767    }
768
769    #[test]
770    fn parse_lo_latin1() {
771        // "Müller" in ISO-8859-1
772        let bytes = vec![b'M', 0xFC, b'l', b'l', b'e', b'r'];
773        let latin1 = DicomCharsetDecoder::new("ISO_IR 100").unwrap();
774        let v = parse_value_bytes(Vr::LO, &bytes, true, &latin1).unwrap();
775        match v {
776            Value::Strings(ss) => assert_eq!(ss, &["Müller"]),
777            other => panic!("unexpected: {:?}", other),
778        }
779    }
780
781    #[test]
782    fn parse_pn_utf8() {
783        let name = "田中^太郎";
784        let utf8 = DicomCharsetDecoder::new("ISO_IR 192").unwrap();
785        let v = parse_value_bytes(Vr::PN, name.as_bytes(), true, &utf8).unwrap();
786        match v {
787            Value::PersonNames(names) => assert_eq!(names[0].to_string(), "田中^太郎"),
788            other => panic!("unexpected: {:?}", other),
789        }
790    }
791}