dcm_dump/dicom/
meta.rs

1use std::io::{self, Read};
2
3#[derive(Debug, Clone)]
4pub struct DataElement {
5    pub tag: (u16, u16),
6    pub vr: [u8; 2],
7    pub length: u32,
8    pub value: Vec<u8>,
9}
10
11/// Reads the next data element assuming Explicit VR Little Endian encoding.
12pub fn read_element_explicit_le<R: Read>(reader: &mut R) -> io::Result<Option<DataElement>> {
13    let mut tag_bytes = [0u8; 4];
14    if !fill(reader, &mut tag_bytes)? {
15        return Ok(None);
16    }
17
18    let group = u16::from_le_bytes([tag_bytes[0], tag_bytes[1]]);
19    let element = u16::from_le_bytes([tag_bytes[2], tag_bytes[3]]);
20
21    let mut vr = [0u8; 2];
22    fill(reader, &mut vr)?;
23
24    let length = if uses_32bit_length(&vr) {
25        let mut reserved = [0u8; 2];
26        fill(reader, &mut reserved)?;
27
28        let mut len_bytes = [0u8; 4];
29        fill(reader, &mut len_bytes)?;
30        u32::from_le_bytes(len_bytes)
31    } else {
32        let mut len_bytes = [0u8; 2];
33        fill(reader, &mut len_bytes)?;
34        u16::from_le_bytes(len_bytes) as u32
35    };
36
37    let mut value = vec![0u8; length as usize];
38    if length > 0 {
39        read_exact(reader, &mut value)?;
40    }
41
42    Ok(Some(DataElement {
43        tag: (group, element),
44        vr,
45        length,
46        value,
47    }))
48}
49
50pub fn read_transfer_syntax_uid<R: Read>(reader: &mut R) -> io::Result<Option<String>> {
51    while let Some(element) = read_element_explicit_le(reader)? {
52        if element.tag.0 != 0x0002 {
53            // Outside File Meta Information group; stop searching
54            return Ok(None);
55        }
56
57        if element.tag == (0x0002, 0x0010) {
58            let trimmed = element
59                .value
60                .split(|&b| b == 0)
61                .next()
62                .unwrap_or(&[])
63                .to_vec();
64            let as_str = String::from_utf8_lossy(&trimmed).to_string();
65            return Ok(Some(as_str));
66        }
67    }
68
69    Ok(None)
70}
71
72fn uses_32bit_length(vr: &[u8; 2]) -> bool {
73    matches!(
74        std::str::from_utf8(vr).ok(),
75        Some("OB" | "OD" | "OF" | "OL" | "OW" | "SQ" | "UC" | "UR" | "UT" | "UN")
76    )
77}
78
79fn fill<R: Read>(reader: &mut R, buf: &mut [u8]) -> io::Result<bool> {
80    let mut read = 0usize;
81    while read < buf.len() {
82        match reader.read(&mut buf[read..])? {
83            0 if read == 0 => return Ok(false),
84            0 => {
85                return Err(io::Error::new(
86                    io::ErrorKind::UnexpectedEof,
87                    "unexpected EOF while reading element",
88                ))
89            }
90            n => read += n,
91        }
92    }
93    Ok(true)
94}
95
96fn read_exact<R: Read>(reader: &mut R, buf: &mut [u8]) -> io::Result<()> {
97    let mut offset = 0usize;
98    while offset < buf.len() {
99        match reader.read(&mut buf[offset..])? {
100            0 => {
101                return Err(io::Error::new(
102                    io::ErrorKind::UnexpectedEof,
103                    "unexpected EOF while reading element value",
104                ))
105            }
106            n => offset += n,
107        }
108    }
109    Ok(())
110}