use crate::dataset::DataSet;
use crate::element::Element;
use dicom_toolkit_core::error::{DcmError, DcmResult};
use dicom_toolkit_dict::{tags, Vr};
pub const META_VERSION: [u8; 2] = [0x00, 0x01];
pub const IMPL_CLASS_UID: &str = "1.2.276.0.7230010.3.1.9999.1";
pub const IMPL_VERSION_NAME: &str = "DCMTK-RS-0.1";
#[derive(Debug, Clone, PartialEq)]
pub struct FileMetaInformation {
pub media_storage_sop_class_uid: String,
pub media_storage_sop_instance_uid: String,
pub transfer_syntax_uid: String,
pub implementation_class_uid: String,
pub implementation_version_name: String,
}
impl FileMetaInformation {
pub fn new(sop_class_uid: &str, sop_instance_uid: &str, ts_uid: &str) -> Self {
Self {
media_storage_sop_class_uid: sop_class_uid.to_string(),
media_storage_sop_instance_uid: sop_instance_uid.to_string(),
transfer_syntax_uid: ts_uid.to_string(),
implementation_class_uid: IMPL_CLASS_UID.to_string(),
implementation_version_name: IMPL_VERSION_NAME.to_string(),
}
}
pub fn to_dataset(&self) -> DataSet {
let mut ds = DataSet::new();
ds.insert(Element::bytes(
tags::FILE_META_INFORMATION_VERSION,
Vr::OB,
META_VERSION.to_vec(),
));
ds.insert(Element::uid(
tags::MEDIA_STORAGE_SOP_CLASS_UID,
&self.media_storage_sop_class_uid,
));
ds.insert(Element::uid(
tags::MEDIA_STORAGE_SOP_INSTANCE_UID,
&self.media_storage_sop_instance_uid,
));
ds.insert(Element::uid(
tags::TRANSFER_SYNTAX_UID,
&self.transfer_syntax_uid,
));
ds.insert(Element::uid(
tags::IMPLEMENTATION_CLASS_UID,
&self.implementation_class_uid,
));
ds.insert(Element::string(
tags::IMPLEMENTATION_VERSION_NAME,
Vr::SH,
&self.implementation_version_name,
));
ds
}
pub fn from_dataset(ds: &DataSet) -> DcmResult<Self> {
let transfer_syntax_uid = ds
.get_string(tags::TRANSFER_SYNTAX_UID)
.ok_or_else(|| DcmError::InvalidFile {
reason: "missing Transfer Syntax UID (0002,0010)".into(),
})?
.trim_end_matches('\0')
.to_string();
let media_storage_sop_class_uid = ds
.get_string(tags::MEDIA_STORAGE_SOP_CLASS_UID)
.unwrap_or("")
.trim_end_matches('\0')
.to_string();
let media_storage_sop_instance_uid = ds
.get_string(tags::MEDIA_STORAGE_SOP_INSTANCE_UID)
.unwrap_or("")
.trim_end_matches('\0')
.to_string();
let implementation_class_uid = ds
.get_string(tags::IMPLEMENTATION_CLASS_UID)
.unwrap_or(IMPL_CLASS_UID)
.trim_end_matches('\0')
.to_string();
let implementation_version_name = ds
.get_string(tags::IMPLEMENTATION_VERSION_NAME)
.unwrap_or(IMPL_VERSION_NAME)
.trim_end_matches('\0')
.to_string();
Ok(Self {
media_storage_sop_class_uid,
media_storage_sop_instance_uid,
transfer_syntax_uid,
implementation_class_uid,
implementation_version_name,
})
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn meta_roundtrip_to_from_dataset() {
let meta = FileMetaInformation::new(
"1.2.840.10008.5.1.4.1.1.2",
"1.2.3.4.5.6.7",
"1.2.840.10008.1.2.1",
);
let ds = meta.to_dataset();
let back = FileMetaInformation::from_dataset(&ds).unwrap();
assert_eq!(meta.transfer_syntax_uid, back.transfer_syntax_uid);
assert_eq!(
meta.media_storage_sop_class_uid,
back.media_storage_sop_class_uid
);
assert_eq!(
meta.media_storage_sop_instance_uid,
back.media_storage_sop_instance_uid
);
}
#[test]
fn meta_from_dataset_missing_ts_uid_errors() {
let ds = DataSet::new();
assert!(FileMetaInformation::from_dataset(&ds).is_err());
}
#[test]
fn meta_to_dataset_has_version() {
let meta = FileMetaInformation::new("", "", "1.2.840.10008.1.2.1");
let ds = meta.to_dataset();
let ver = ds.get_bytes(tags::FILE_META_INFORMATION_VERSION).unwrap();
assert_eq!(ver, &[0x00, 0x01]);
}
}