dicomweb_util/
lib.rs

1use bytes::{Buf, Bytes};
2use dicom::object::mem::InMemElement;
3use dicom::object::{
4    DefaultDicomObject, FileMetaTable, FileMetaTableBuilder, InMemDicomObject,
5    StandardDataDictionary,
6};
7use enum_as_inner::EnumAsInner;
8use log::{debug, error, info, log_enabled, trace, warn, Level};
9use serde::Deserialize;
10use serde_json::Value;
11use std::{borrow::Borrow, io::BufRead};
12use std::{
13    collections::HashMap,
14    io::{self, Cursor, Read},
15};
16use thiserror::Error;
17
18#[derive(Error, Debug)]
19pub enum Error {
20    #[error("{0}")]
21    Io(#[from] std::io::Error),
22    #[error("{0}")]
23    Serde(#[from] serde_json::Error),
24    #[error("{0}")]
25    Dicom(#[from] dicom::object::Error),
26    #[error("{0}")]
27    DicomCastValue(#[from] dicom::core::value::CastValueError),
28    #[error("{0}")]
29    Custom(String),
30}
31pub type Result<T> = std::result::Result<T, Error>;
32
33pub mod decode;
34pub mod encode;
35
36#[derive(Debug)]
37enum MultipartParserStates {
38    NextPart,
39    InHeader,
40    InBinary,
41}
42
43pub fn parse_multipart_body(body: Bytes, boundary: &str) -> Result<Vec<Vec<u8>>> {
44    let mut reader = Cursor::new(body).reader();
45    let mut line = String::new();
46
47    let mut result = vec![];
48
49    let mut state = MultipartParserStates::NextPart;
50    let mut content_length: usize = 0;
51
52    loop {
53        match reader.read_line(&mut line) {
54            Ok(bytes_read) => {
55                if bytes_read == 0 {
56                    break;
57                }
58                trace!("{:?}", state);
59                trace!("{:?}", line);
60                match state {
61                    MultipartParserStates::NextPart => {
62                        if line.trim().ends_with(boundary) {
63                            debug!("found start of part in multipart body");
64                            state = MultipartParserStates::InHeader;
65                        }
66                    }
67                    MultipartParserStates::InHeader => {
68                        if line.starts_with("Content-Length") {
69                            content_length =
70                                usize::from_str_radix(line.split_whitespace().last().unwrap(), 10)
71                                    .unwrap();
72                            debug!("content length:{}", content_length);
73                        } else if line.trim() == "" {
74                            state = MultipartParserStates::InBinary;
75                        }
76                    }
77                    _ => {
78                        return Err(Error::Custom(
79                            "in wrong state when reading multipart header".to_string(),
80                        ));
81                    }
82                }
83
84                line.clear();
85            }
86            Err(err) => {
87                error!("{}", err);
88                break;
89            }
90        };
91        match state {
92            MultipartParserStates::InBinary => {
93                if content_length > 0 {
94                    let mut buffer = vec![0u8; content_length];
95                    reader.read_exact(&mut buffer)?;
96                    result.push(buffer);
97                } else {
98                    // length not specified, assuming single part and trailing boundary like CRLF--boundary--
99                    let mut buffer = Vec::new();
100                    reader.read_to_end(&mut buffer)?;
101                    let len = buffer.len() - boundary.len() - 6;
102                    result.push(buffer[..len].into());
103                }
104                state = MultipartParserStates::NextPart
105            }
106            _ => {}
107        }
108    }
109    Ok(result)
110}
111
112pub fn dicom_from_reader<R: Read>(mut file: R) -> Result<DefaultDicomObject> {
113    // skip preamble
114    {
115        let mut buf = [0u8; 128];
116        // skip the preamble
117        file.read_exact(&mut buf)?;
118    }
119    let result = DefaultDicomObject::from_reader(file)?;
120    Ok(result)
121}
122
123#[derive(Debug, Deserialize, EnumAsInner)]
124#[serde(untagged)]
125pub enum DICOMJsonTagValue {
126    Str(String),
127    Int(i32),
128    DICOMJson(DICOMJson),
129    Value(Value),
130}
131
132#[derive(Debug, Deserialize)]
133pub struct DICOMJsonTag {
134    pub vr: String,
135    pub Value: Vec<DICOMJsonTagValue>,
136}
137
138pub type DICOMJson = Vec<HashMap<String, DICOMJsonTag>>;
139pub type DicomResponse = InMemDicomObject<StandardDataDictionary>;
140
141pub fn json2dicom(parsed: &Vec<Value>) -> Result<Vec<DicomResponse>> {
142    // let parsed: Vec<Value> = serde_json::from_str(injson)?;
143    println!("{:?}", parsed);
144
145    let ds = parsed.iter().map(decode::decode_response_item).collect();
146    Ok(ds)
147}
148
149#[cfg(test)]
150mod tests {
151    #[test]
152    fn it_works() {
153        assert_eq!(2 + 2, 4);
154    }
155}