1use dicom_core::ops::{
40 ApplyOp, AttributeAction, AttributeOp, AttributeSelector, AttributeSelectorStep,
41};
42use dicom_parser::dataset::read::{DataSetReaderOptions, OddLengthStrategy};
43use itertools::Itertools;
44use smallvec::SmallVec;
45use snafu::{ensure, OptionExt, ResultExt};
46use std::borrow::Cow;
47use std::fs::File;
48use std::io::{BufRead, BufReader, Read};
49use std::path::Path;
50use std::{collections::BTreeMap, io::Write};
51
52use crate::file::ReadPreamble;
53use crate::ops::{
54 ApplyError, ApplyResult, IncompatibleTypesSnafu, ModifySnafu, UnsupportedActionSnafu,
55};
56use crate::{meta::FileMetaTable, FileMetaTableBuilder};
57use crate::{
58 AccessByNameError, AccessError, AtAccessError, BuildMetaTableSnafu, CreateParserSnafu,
59 CreatePrinterSnafu, DicomObject, ElementNotFoundSnafu, FileDicomObject, InvalidGroupSnafu,
60 MissingElementValueSnafu, MissingLeafElementSnafu, NoSpaceSnafu, NoSuchAttributeNameSnafu,
61 NoSuchDataElementAliasSnafu, NoSuchDataElementTagSnafu, NotASequenceSnafu, OpenFileSnafu,
62 ParseMetaDataSetSnafu, ParseSopAttributeSnafu, PrematureEndSnafu, PrepareMetaTableSnafu,
63 PrintDataSetSnafu, PrivateCreatorNotFoundSnafu, PrivateElementError, ReadError, ReadFileSnafu,
64 ReadPreambleBytesSnafu, ReadTokenSnafu, ReadUnsupportedTransferSyntaxSnafu,
65 UnexpectedTokenSnafu, WithMetaError, WriteError,
66};
67use dicom_core::dictionary::{DataDictionary, DataDictionaryEntry};
68use dicom_core::header::{GroupNumber, HasLength, Header};
69use dicom_core::value::{DataSetSequence, PixelFragmentSequence, Value, ValueType, C};
70use dicom_core::{DataElement, Length, PrimitiveValue, Tag, VR};
71use dicom_dictionary_std::{tags, StandardDataDictionary};
72use dicom_encoding::transfer_syntax::TransferSyntaxIndex;
73use dicom_encoding::{encode::EncodeTo, text::SpecificCharacterSet, TransferSyntax};
74use dicom_parser::dataset::{DataSetReader, DataToken, IntoTokensOptions};
75use dicom_parser::{
76 dataset::{read::Error as ParserError, DataSetWriter, IntoTokens},
77 StatefulDecode,
78};
79use dicom_transfer_syntax_registry::TransferSyntaxRegistry;
80
81pub type InMemElement<D = StandardDataDictionary> = DataElement<InMemDicomObject<D>, InMemFragment>;
83
84pub type InMemFragment = dicom_core::value::InMemFragment;
86
87type Result<T, E = AccessError> = std::result::Result<T, E>;
88
89type ParserResult<T> = std::result::Result<T, ParserError>;
90
91#[derive(Debug, Clone)]
96pub struct InMemDicomObject<D = StandardDataDictionary> {
97 entries: BTreeMap<Tag, InMemElement<D>>,
99 dict: D,
101 len: Length,
105 pub(crate) charset_changed: bool,
109}
110
111impl<D> PartialEq for InMemDicomObject<D> {
112 fn eq(&self, other: &Self) -> bool {
114 self.entries == other.entries
115 }
116}
117
118impl<D> HasLength for InMemDicomObject<D> {
119 fn length(&self) -> Length {
120 self.len
121 }
122}
123
124impl<'s, D: 's> DicomObject for &'s InMemDicomObject<D>
125where
126 D: DataDictionary,
127 D: Clone,
128{
129 type Element = &'s InMemElement<D>;
130
131 fn element(&self, tag: Tag) -> Result<Self::Element> {
132 self.entries
133 .get(&tag)
134 .context(NoSuchDataElementTagSnafu { tag })
135 }
136
137 fn element_by_name(&self, name: &str) -> Result<Self::Element, AccessByNameError> {
138 let tag = self.lookup_name(name)?;
139 self.element(tag).map_err(|e| e.into_access_by_name(name))
140 }
141}
142
143impl FileDicomObject<InMemDicomObject<StandardDataDictionary>> {
144 pub fn open_file<P: AsRef<Path>>(path: P) -> Result<Self, ReadError> {
152 Self::open_file_with_dict(path, StandardDataDictionary)
153 }
154
155 pub fn from_reader<S>(src: S) -> Result<Self, ReadError>
163 where
164 S: Read,
165 {
166 Self::from_reader_with_dict(src, StandardDataDictionary)
167 }
168}
169
170impl InMemDicomObject<StandardDataDictionary> {
171 pub fn new_empty() -> Self {
173 InMemDicomObject {
174 entries: BTreeMap::new(),
175 dict: StandardDataDictionary,
176 len: Length::UNDEFINED,
177 charset_changed: false,
178 }
179 }
180
181 #[inline]
183 pub fn from_element_source<I>(iter: I) -> Result<Self>
184 where
185 I: IntoIterator<Item = Result<InMemElement<StandardDataDictionary>>>,
186 {
187 Self::from_element_source_with_dict(iter, StandardDataDictionary)
188 }
189
190 #[inline]
192 pub fn from_element_iter<I>(iter: I) -> Self
193 where
194 I: IntoIterator<Item = InMemElement<StandardDataDictionary>>,
195 {
196 Self::from_iter_with_dict(iter, StandardDataDictionary)
197 }
198
199 #[inline]
206 pub fn command_from_element_iter<I>(iter: I) -> Self
207 where
208 I: IntoIterator<Item = InMemElement<StandardDataDictionary>>,
209 {
210 Self::command_from_iter_with_dict(iter, StandardDataDictionary)
211 }
212
213 #[inline]
221 pub fn read_dataset<S>(decoder: S) -> Result<Self, ReadError>
222 where
223 S: StatefulDecode,
224 {
225 Self::read_dataset_with_dict(decoder, StandardDataDictionary)
226 }
227
228 #[inline]
234 pub fn read_dataset_with_ts_cs<S>(
235 from: S,
236 ts: &TransferSyntax,
237 cs: SpecificCharacterSet,
238 ) -> Result<Self, ReadError>
239 where
240 S: Read,
241 {
242 Self::read_dataset_with_dict_ts_cs(from, StandardDataDictionary, ts, cs)
243 }
244
245 #[inline]
252 pub fn read_dataset_with_ts<S>(from: S, ts: &TransferSyntax) -> Result<Self, ReadError>
253 where
254 S: Read,
255 {
256 Self::read_dataset_with_dict_ts_cs(
257 from,
258 StandardDataDictionary,
259 ts,
260 SpecificCharacterSet::default(),
261 )
262 }
263}
264
265impl<D> FileDicomObject<InMemDicomObject<D>>
266where
267 D: DataDictionary,
268 D: Clone,
269{
270 pub fn new_empty_with_dict_and_meta(dict: D, meta: FileMetaTable) -> Self {
273 FileDicomObject {
274 meta,
275 obj: InMemDicomObject {
276 entries: BTreeMap::new(),
277 dict,
278 len: Length::UNDEFINED,
279 charset_changed: false,
280 },
281 }
282 }
283
284 pub fn open_file_with_dict<P: AsRef<Path>>(path: P, dict: D) -> Result<Self, ReadError> {
292 Self::open_file_with(path, dict, TransferSyntaxRegistry)
293 }
294
295 pub fn open_file_with<P, R>(path: P, dict: D, ts_index: R) -> Result<Self, ReadError>
309 where
310 P: AsRef<Path>,
311 R: TransferSyntaxIndex,
312 {
313 Self::open_file_with_all_options(
314 path,
315 dict,
316 ts_index,
317 None,
318 ReadPreamble::Auto,
319 Default::default(),
320 )
321 }
322
323 fn detect_preamble<S>(reader: &mut BufReader<S>) -> std::io::Result<ReadPreamble>
326 where
327 S: Read,
328 {
329 let buf = reader.fill_buf()?;
330 let buflen = buf.len();
331
332 if buflen < 4 {
333 return Err(std::io::ErrorKind::UnexpectedEof.into());
334 }
335
336 if buflen >= 132 && &buf[128..132] == b"DICM" {
337 return Ok(ReadPreamble::Always);
338 }
339
340 if &buf[0..4] == b"DICM" {
341 return Ok(ReadPreamble::Never);
342 }
343
344 Ok(ReadPreamble::Auto)
346 }
347
348 pub(crate) fn open_file_with_all_options<P, R>(
349 path: P,
350 dict: D,
351 ts_index: R,
352 read_until: Option<Tag>,
353 mut read_preamble: ReadPreamble,
354 odd_length: OddLengthStrategy,
355 ) -> Result<Self, ReadError>
356 where
357 P: AsRef<Path>,
358 R: TransferSyntaxIndex,
359 {
360 let path = path.as_ref();
361 let mut file =
362 BufReader::new(File::open(path).with_context(|_| OpenFileSnafu { filename: path })?);
363
364 if read_preamble == ReadPreamble::Auto {
365 read_preamble = Self::detect_preamble(&mut file)
366 .with_context(|_| ReadFileSnafu { filename: path })?;
367 }
368
369 if read_preamble == ReadPreamble::Auto || read_preamble == ReadPreamble::Always {
370 let mut buf = [0u8; 128];
371 file.read_exact(&mut buf)
373 .with_context(|_| ReadFileSnafu { filename: path })?;
374 }
375
376 let mut meta = FileMetaTable::from_reader(&mut file).context(ParseMetaDataSetSnafu)?;
378
379 if let Some(ts) = ts_index.get(&meta.transfer_syntax) {
381 let mut options = DataSetReaderOptions::default();
382 options.odd_length = odd_length;
383 let mut dataset = DataSetReader::new_with_ts_cs_options(
384 file,
385 ts,
386 SpecificCharacterSet::default(),
387 options,
388 )
389 .context(CreateParserSnafu)?;
390 let obj = InMemDicomObject::build_object(
391 &mut dataset,
392 dict,
393 false,
394 Length::UNDEFINED,
395 read_until,
396 )?;
397
398 if meta.media_storage_sop_class_uid().is_empty() {
400 if let Some(elem) = obj.get(tags::SOP_CLASS_UID) {
401 meta.media_storage_sop_class_uid = elem
402 .value()
403 .to_str()
404 .context(ParseSopAttributeSnafu)?
405 .to_string();
406 }
407 }
408
409 if meta.media_storage_sop_instance_uid().is_empty() {
411 if let Some(elem) = obj.get(tags::SOP_INSTANCE_UID) {
412 meta.media_storage_sop_instance_uid = elem
413 .value()
414 .to_str()
415 .context(ParseSopAttributeSnafu)?
416 .to_string();
417 }
418 }
419
420 Ok(FileDicomObject { meta, obj })
421 } else {
422 ReadUnsupportedTransferSyntaxSnafu {
423 uid: meta.transfer_syntax,
424 }
425 .fail()
426 }
427 }
428
429 pub fn from_reader_with_dict<S>(src: S, dict: D) -> Result<Self, ReadError>
437 where
438 S: Read,
439 {
440 Self::from_reader_with(src, dict, TransferSyntaxRegistry)
441 }
442
443 pub fn from_reader_with<'s, S, R>(src: S, dict: D, ts_index: R) -> Result<Self, ReadError>
457 where
458 S: Read + 's,
459 R: TransferSyntaxIndex,
460 {
461 Self::from_reader_with_all_options(
462 src,
463 dict,
464 ts_index,
465 None,
466 ReadPreamble::Auto,
467 Default::default(),
468 )
469 }
470
471 pub(crate) fn from_reader_with_all_options<'s, S, R>(
472 src: S,
473 dict: D,
474 ts_index: R,
475 read_until: Option<Tag>,
476 mut read_preamble: ReadPreamble,
477 odd_length: OddLengthStrategy,
478 ) -> Result<Self, ReadError>
479 where
480 S: Read + 's,
481 R: TransferSyntaxIndex,
482 {
483 let mut file = BufReader::new(src);
484
485 if read_preamble == ReadPreamble::Auto {
486 read_preamble = Self::detect_preamble(&mut file).context(ReadPreambleBytesSnafu)?;
487 }
488
489 if read_preamble == ReadPreamble::Always {
490 let mut buf = [0u8; 128];
492 file.read_exact(&mut buf).context(ReadPreambleBytesSnafu)?;
494 }
495
496 let meta = FileMetaTable::from_reader(&mut file).context(ParseMetaDataSetSnafu)?;
498
499 if let Some(ts) = ts_index.get(&meta.transfer_syntax) {
501 let mut options = DataSetReaderOptions::default();
502 options.odd_length = odd_length;
503 let mut dataset = DataSetReader::new_with_ts_options(
504 file,
505 ts,
506 options,
507 )
508 .context(CreateParserSnafu)?;
509 let obj = InMemDicomObject::build_object(
510 &mut dataset,
511 dict,
512 false,
513 Length::UNDEFINED,
514 read_until,
515 )?;
516 Ok(FileDicomObject { meta, obj })
517 } else {
518 ReadUnsupportedTransferSyntaxSnafu {
519 uid: meta.transfer_syntax,
520 }
521 .fail()
522 }
523 }
524}
525
526impl FileDicomObject<InMemDicomObject<StandardDataDictionary>> {
527 pub fn new_empty_with_meta(meta: FileMetaTable) -> Self {
529 FileDicomObject {
530 meta,
531 obj: InMemDicomObject {
532 entries: BTreeMap::new(),
533 dict: StandardDataDictionary,
534 len: Length::UNDEFINED,
535 charset_changed: false,
536 },
537 }
538 }
539}
540
541impl<D> InMemDicomObject<D>
542where
543 D: DataDictionary,
544 D: Clone,
545{
546 pub fn new_empty_with_dict(dict: D) -> Self {
548 InMemDicomObject {
549 entries: BTreeMap::new(),
550 dict,
551 len: Length::UNDEFINED,
552 charset_changed: false,
553 }
554 }
555
556 pub fn from_element_source_with_dict<I>(iter: I, dict: D) -> Result<Self>
558 where
559 I: IntoIterator<Item = Result<InMemElement<D>>>,
560 {
561 let entries: Result<_> = iter.into_iter().map_ok(|e| (e.tag(), e)).collect();
562 Ok(InMemDicomObject {
563 entries: entries?,
564 dict,
565 len: Length::UNDEFINED,
566 charset_changed: false,
567 })
568 }
569
570 pub fn from_iter_with_dict<I>(iter: I, dict: D) -> Self
572 where
573 I: IntoIterator<Item = InMemElement<D>>,
574 {
575 let entries = iter.into_iter().map(|e| (e.tag(), e)).collect();
576 InMemDicomObject {
577 entries,
578 dict,
579 len: Length::UNDEFINED,
580 charset_changed: false,
581 }
582 }
583
584 pub fn command_from_iter_with_dict<I>(iter: I, dict: D) -> Self
591 where
592 I: IntoIterator<Item = InMemElement<D>>,
593 {
594 let mut calculated_length: u32 = 0;
595 let mut entries: BTreeMap<_, _> = iter
596 .into_iter()
597 .map(|e| {
598 if e.tag().0 == 0x0000 && e.tag().1 != 0x0000 {
600 let l = e.value().length();
601 calculated_length += if l.is_defined() { even_len(l.0) } else { 0 } + 8;
602 }
603
604 (e.tag(), e)
605 })
606 .collect();
607
608 entries.insert(
609 Tag(0, 0),
610 InMemElement::new(Tag(0, 0), VR::UL, PrimitiveValue::from(calculated_length)),
611 );
612
613 InMemDicomObject {
614 entries,
615 dict,
616 len: Length::UNDEFINED,
617 charset_changed: false,
618 }
619 }
620
621 pub fn read_dataset_with_dict<S>(decoder: S, dict: D) -> Result<Self, ReadError>
625 where
626 S: StatefulDecode,
627 D: DataDictionary,
628 {
629 let mut dataset = DataSetReader::new(decoder, Default::default());
630 InMemDicomObject::build_object(&mut dataset, dict, false, Length::UNDEFINED, None)
631 }
632
633 #[inline]
636 pub fn read_dataset_with_dict_ts<S>(
637 from: S,
638 dict: D,
639 ts: &TransferSyntax,
640 ) -> Result<Self, ReadError>
641 where
642 S: Read,
643 D: DataDictionary,
644 {
645 Self::read_dataset_with_dict_ts_cs(from, dict, ts, SpecificCharacterSet::default())
646 }
647
648 pub fn read_dataset_with_dict_ts_cs<S>(
656 from: S,
657 dict: D,
658 ts: &TransferSyntax,
659 cs: SpecificCharacterSet,
660 ) -> Result<Self, ReadError>
661 where
662 S: Read,
663 D: DataDictionary,
664 {
665 let from = BufReader::new(from);
666 let mut dataset = DataSetReader::new_with_ts_cs(from, ts, cs).context(CreateParserSnafu)?;
667 InMemDicomObject::build_object(&mut dataset, dict, false, Length::UNDEFINED, None)
668 }
669
670 pub fn element(&self, tag: Tag) -> Result<&InMemElement<D>> {
680 self.entries
681 .get(&tag)
682 .context(NoSuchDataElementTagSnafu { tag })
683 }
684
685 pub fn element_by_name(&self, name: &str) -> Result<&InMemElement<D>, AccessByNameError> {
697 let tag = self.lookup_name(name)?;
698 self.entries
699 .get(&tag)
700 .with_context(|| NoSuchDataElementAliasSnafu {
701 tag,
702 alias: name.to_string(),
703 })
704 }
705
706 pub fn element_opt(&self, tag: Tag) -> Result<Option<&InMemElement<D>>, AccessError> {
711 match self.element(tag) {
712 Ok(e) => Ok(Some(e)),
713 Err(super::AccessError::NoSuchDataElementTag { .. }) => Ok(None),
714 }
715 }
716
717 pub fn get(&self, tag: Tag) -> Option<&InMemElement<D>> {
722 self.entries.get(&tag)
723 }
724
725 fn get_mut(&mut self, tag: Tag) -> Option<&mut InMemElement<D>> {
730 self.entries.get_mut(&tag)
731 }
732
733 pub fn element_by_name_opt(
744 &self,
745 name: &str,
746 ) -> Result<Option<&InMemElement<D>>, AccessByNameError> {
747 match self.element_by_name(name) {
748 Ok(e) => Ok(Some(e)),
749 Err(AccessByNameError::NoSuchDataElementAlias { .. }) => Ok(None),
750 Err(e) => Err(e),
751 }
752 }
753
754 fn find_private_creator(&self, group: GroupNumber, creator: &str) -> Option<&Tag> {
755 let range = Tag(group, 0)..Tag(group, 0xFF);
756 for (tag, elem) in self.entries.range(range) {
757 if elem.header().vr() == VR::LO && elem.to_str().unwrap_or_default() == creator {
760 return Some(tag);
761 }
762 }
763 None
764 }
765
766 pub fn private_element(
799 &self,
800 group: GroupNumber,
801 creator: &str,
802 element: u8,
803 ) -> Result<&InMemElement<D>, PrivateElementError> {
804 let tag = self.find_private_creator(group, creator).ok_or_else(|| {
805 PrivateCreatorNotFoundSnafu {
806 group,
807 creator: creator.to_string(),
808 }
809 .build()
810 })?;
811
812 let element_num = (tag.element() << 8) | (element as u16);
813 self.get(Tag(group, element_num)).ok_or_else(|| {
814 ElementNotFoundSnafu {
815 group,
816 creator: creator.to_string(),
817 elem: element,
818 }
819 .build()
820 })
821 }
822
823 pub fn put(&mut self, elt: InMemElement<D>) -> Option<InMemElement<D>> {
828 self.put_element(elt)
829 }
830
831 pub fn put_element(&mut self, elt: InMemElement<D>) -> Option<InMemElement<D>> {
836 self.len = Length::UNDEFINED;
837 self.invalidate_if_charset_changed(elt.tag());
838 self.entries.insert(elt.tag(), elt)
839 }
840
841 pub fn put_private_element(
882 &mut self,
883 group: GroupNumber,
884 creator: &str,
885 element: u8,
886 vr: VR,
887 value: PrimitiveValue,
888 ) -> Result<Option<InMemElement<D>>, PrivateElementError> {
889 ensure!(group % 2 == 1, InvalidGroupSnafu { group });
890 let private_creator = self.find_private_creator(group, creator);
891 if let Some(tag) = private_creator {
892 let tag = Tag(group, tag.element() << 8 | (element as u16));
894 Ok(self.put_element(DataElement::new(tag, vr, value)))
895 } else {
896 let range = Tag(group, 0)..Tag(group, 0xFF);
898 let last_entry = self.entries.range(range).next_back();
899 let next_available = match last_entry {
900 Some((tag, _)) => tag.element() + 1,
901 None => 0x01,
902 };
903 if next_available < 0xFF {
904 let tag = Tag(group, next_available);
906 self.put_str(tag, VR::LO, creator);
907
908 let tag = Tag(group, next_available << 8 | (element as u16));
910 Ok(self.put_element(DataElement::new(tag, vr, value)))
911 } else {
912 NoSpaceSnafu { group }.fail()
913 }
914 }
915 }
916
917 pub fn put_str(
920 &mut self,
921 tag: Tag,
922 vr: VR,
923 string: impl Into<String>,
924 ) -> Option<InMemElement<D>> {
925 self.put_element(DataElement::new(tag, vr, string.into()))
926 }
927
928 pub fn remove_element(&mut self, tag: Tag) -> bool {
931 if self.entries.remove(&tag).is_some() {
932 self.len = Length::UNDEFINED;
933 true
934 } else {
935 false
936 }
937 }
938
939 pub fn remove_element_by_name(&mut self, name: &str) -> Result<bool, AccessByNameError> {
942 let tag = self.lookup_name(name)?;
943 Ok(self.entries.remove(&tag).is_some()).map(|removed| {
944 if removed {
945 self.len = Length::UNDEFINED;
946 }
947 removed
948 })
949 }
950
951 pub fn take_element(&mut self, tag: Tag) -> Result<InMemElement<D>> {
953 self.entries
954 .remove(&tag)
955 .map(|e| {
956 self.len = Length::UNDEFINED;
957 e
958 })
959 .context(NoSuchDataElementTagSnafu { tag })
960 }
961
962 pub fn take(&mut self, tag: Tag) -> Option<InMemElement<D>> {
966 self.entries.remove(&tag).map(|e| {
967 self.len = Length::UNDEFINED;
968 e
969 })
970 }
971
972 pub fn take_element_by_name(
974 &mut self,
975 name: &str,
976 ) -> Result<InMemElement<D>, AccessByNameError> {
977 let tag = self.lookup_name(name)?;
978 self.entries
979 .remove(&tag)
980 .map(|e| {
981 self.len = Length::UNDEFINED;
982 e
983 })
984 .with_context(|| NoSuchDataElementAliasSnafu {
985 tag,
986 alias: name.to_string(),
987 })
988 }
989
990 pub fn retain(&mut self, mut f: impl FnMut(&InMemElement<D>) -> bool) {
996 self.entries.retain(|_, elem| f(elem));
997 self.len = Length::UNDEFINED;
998 }
999
1000 pub fn update_value(
1028 &mut self,
1029 tag: Tag,
1030 f: impl FnMut(&mut Value<InMemDicomObject<D>, InMemFragment>),
1031 ) -> bool {
1032 self.invalidate_if_charset_changed(tag);
1033 if let Some(e) = self.entries.get_mut(&tag) {
1034 e.update_value(f);
1035 self.len = Length::UNDEFINED;
1036 true
1037 } else {
1038 false
1039 }
1040 }
1041
1042 pub fn update_value_at(
1092 &mut self,
1093 selector: impl Into<AttributeSelector>,
1094 f: impl FnMut(&mut Value<InMemDicomObject<D>, InMemFragment>),
1095 ) -> Result<(), AtAccessError> {
1096 self.entry_at_mut(selector)
1097 .map(|e| e.update_value(f))
1098 .map(|_| {
1099 self.len = Length::UNDEFINED;
1100 })
1101 }
1102
1103 pub fn value_at(
1130 &self,
1131 selector: impl Into<AttributeSelector>,
1132 ) -> Result<&Value<InMemDicomObject<D>, InMemFragment>, AtAccessError> {
1133 let selector: AttributeSelector = selector.into();
1134
1135 let mut obj = self;
1136 for (i, step) in selector.iter().enumerate() {
1137 match step {
1138 AttributeSelectorStep::Tag(tag) => {
1140 return obj.get(*tag).map(|e| e.value()).with_context(|| {
1141 MissingLeafElementSnafu {
1142 selector: selector.clone(),
1143 }
1144 });
1145 }
1146 AttributeSelectorStep::Nested { tag, item } => {
1148 let e = obj
1149 .entries
1150 .get(tag)
1151 .with_context(|| crate::MissingSequenceSnafu {
1152 selector: selector.clone(),
1153 step_index: i as u32,
1154 })?;
1155
1156 let items = e.items().with_context(|| NotASequenceSnafu {
1158 selector: selector.clone(),
1159 step_index: i as u32,
1160 })?;
1161
1162 obj =
1164 items
1165 .get(*item as usize)
1166 .with_context(|| crate::MissingSequenceSnafu {
1167 selector: selector.clone(),
1168 step_index: i as u32,
1169 })?;
1170 }
1171 }
1172 }
1173
1174 unreachable!()
1175 }
1176
1177 pub fn convert_to_utf8(&mut self) {
1179 self.put(DataElement::new(
1180 tags::SPECIFIC_CHARACTER_SET,
1181 VR::CS,
1182 "ISO_IR 192",
1183 ));
1184 }
1185
1186 pub fn entry_at(
1195 &self,
1196 selector: impl Into<AttributeSelector>,
1197 ) -> Result<&InMemElement<D>, AtAccessError> {
1198 let selector: AttributeSelector = selector.into();
1199
1200 let mut obj = self;
1201 for (i, step) in selector.iter().enumerate() {
1202 match step {
1203 AttributeSelectorStep::Tag(tag) => {
1205 return obj.get(*tag).with_context(|| MissingLeafElementSnafu {
1206 selector: selector.clone(),
1207 })
1208 }
1209 AttributeSelectorStep::Nested { tag, item } => {
1211 let e = obj
1212 .entries
1213 .get(tag)
1214 .with_context(|| crate::MissingSequenceSnafu {
1215 selector: selector.clone(),
1216 step_index: i as u32,
1217 })?;
1218
1219 let items = e.items().with_context(|| NotASequenceSnafu {
1221 selector: selector.clone(),
1222 step_index: i as u32,
1223 })?;
1224
1225 obj =
1227 items
1228 .get(*item as usize)
1229 .with_context(|| crate::MissingSequenceSnafu {
1230 selector: selector.clone(),
1231 step_index: i as u32,
1232 })?;
1233 }
1234 }
1235 }
1236
1237 unreachable!()
1238 }
1239
1240 fn entry_at_mut(
1244 &mut self,
1245 selector: impl Into<AttributeSelector>,
1246 ) -> Result<&mut InMemElement<D>, AtAccessError> {
1247 let selector: AttributeSelector = selector.into();
1248
1249 let mut obj = self;
1250 for (i, step) in selector.iter().enumerate() {
1251 match step {
1252 AttributeSelectorStep::Tag(tag) => {
1254 return obj.get_mut(*tag).with_context(|| MissingLeafElementSnafu {
1255 selector: selector.clone(),
1256 })
1257 }
1258 AttributeSelectorStep::Nested { tag, item } => {
1260 let e =
1261 obj.entries
1262 .get_mut(tag)
1263 .with_context(|| crate::MissingSequenceSnafu {
1264 selector: selector.clone(),
1265 step_index: i as u32,
1266 })?;
1267
1268 let items = e.items_mut().with_context(|| NotASequenceSnafu {
1270 selector: selector.clone(),
1271 step_index: i as u32,
1272 })?;
1273
1274 obj = items.get_mut(*item as usize).with_context(|| {
1276 crate::MissingSequenceSnafu {
1277 selector: selector.clone(),
1278 step_index: i as u32,
1279 }
1280 })?;
1281 }
1282 }
1283 }
1284
1285 unreachable!()
1286 }
1287
1288 fn apply(&mut self, op: AttributeOp) -> ApplyResult {
1328 let AttributeOp { selector, action } = op;
1329 let dict = self.dict.clone();
1330
1331 let mut obj = self;
1332 for (i, step) in selector.iter().enumerate() {
1333 match step {
1334 AttributeSelectorStep::Tag(tag) => return obj.apply_leaf(*tag, action),
1336 AttributeSelectorStep::Nested { tag, item } => {
1338 if !obj.entries.contains_key(tag) {
1339 if action.is_constructive() {
1341 let vr = dict
1342 .by_tag(*tag)
1343 .and_then(|entry| entry.vr().exact())
1344 .unwrap_or(VR::UN);
1345
1346 if vr != VR::SQ && vr != VR::UN {
1347 return Err(ApplyError::NotASequence {
1348 selector: selector.clone(),
1349 step_index: i as u32,
1350 });
1351 }
1352
1353 obj.put(DataElement::new(*tag, vr, DataSetSequence::empty()));
1354 } else {
1355 return Err(ApplyError::MissingSequence {
1356 selector: selector.clone(),
1357 step_index: i as u32,
1358 });
1359 }
1360 };
1361
1362 let items = obj
1364 .entries
1365 .get_mut(tag)
1366 .expect("sequence element should exist at this point")
1367 .items_mut()
1368 .ok_or_else(|| ApplyError::NotASequence {
1369 selector: selector.clone(),
1370 step_index: i as u32,
1371 })?;
1372
1373 obj = if items.len() == *item as usize && action.is_constructive() {
1375 items.push(InMemDicomObject::new_empty_with_dict(dict.clone()));
1376 items.last_mut().unwrap()
1377 } else {
1378 items.get_mut(*item as usize).ok_or_else(|| {
1379 ApplyError::MissingSequence {
1380 selector: selector.clone(),
1381 step_index: i as u32,
1382 }
1383 })?
1384 };
1385 }
1386 }
1387 }
1388 unreachable!()
1389 }
1390
1391 fn apply_leaf(&mut self, tag: Tag, action: AttributeAction) -> ApplyResult {
1392 self.invalidate_if_charset_changed(tag);
1393 match action {
1394 AttributeAction::Remove => {
1395 self.remove_element(tag);
1396 Ok(())
1397 }
1398 AttributeAction::Empty => {
1399 if let Some(e) = self.entries.get_mut(&tag) {
1400 let vr = e.vr();
1401 *e = DataElement::empty(tag, vr);
1403 self.len = Length::UNDEFINED;
1404 }
1405 Ok(())
1406 }
1407 AttributeAction::SetVr(new_vr) => {
1408 if let Some(e) = self.entries.remove(&tag) {
1409 let (header, value) = e.into_parts();
1410 let e = DataElement::new(header.tag, new_vr, value);
1411 self.put(e);
1412 } else {
1413 self.put(DataElement::empty(tag, new_vr));
1414 }
1415 Ok(())
1416 }
1417 AttributeAction::Set(new_value) => {
1418 self.apply_change_value_impl(tag, new_value);
1419 Ok(())
1420 }
1421 AttributeAction::SetStr(string) => {
1422 let new_value = PrimitiveValue::from(&*string);
1423 self.apply_change_value_impl(tag, new_value);
1424 Ok(())
1425 }
1426 AttributeAction::SetIfMissing(new_value) => {
1427 if self.get(tag).is_none() {
1428 self.apply_change_value_impl(tag, new_value);
1429 }
1430 Ok(())
1431 }
1432 AttributeAction::SetStrIfMissing(string) => {
1433 if self.get(tag).is_none() {
1434 let new_value = PrimitiveValue::from(&*string);
1435 self.apply_change_value_impl(tag, new_value);
1436 }
1437 Ok(())
1438 }
1439 AttributeAction::Replace(new_value) => {
1440 if self.get(tag).is_some() {
1441 self.apply_change_value_impl(tag, new_value);
1442 }
1443 Ok(())
1444 }
1445 AttributeAction::ReplaceStr(string) => {
1446 if self.get(tag).is_some() {
1447 let new_value = PrimitiveValue::from(&*string);
1448 self.apply_change_value_impl(tag, new_value);
1449 }
1450 Ok(())
1451 }
1452 AttributeAction::PushStr(string) => self.apply_push_str_impl(tag, string),
1453 AttributeAction::PushI32(integer) => self.apply_push_i32_impl(tag, integer),
1454 AttributeAction::PushU32(integer) => self.apply_push_u32_impl(tag, integer),
1455 AttributeAction::PushI16(integer) => self.apply_push_i16_impl(tag, integer),
1456 AttributeAction::PushU16(integer) => self.apply_push_u16_impl(tag, integer),
1457 AttributeAction::PushF32(number) => self.apply_push_f32_impl(tag, number),
1458 AttributeAction::PushF64(number) => self.apply_push_f64_impl(tag, number),
1459 AttributeAction::Truncate(limit) => {
1460 self.update_value(tag, |value| value.truncate(limit));
1461 Ok(())
1462 }
1463 _ => UnsupportedActionSnafu.fail(),
1464 }
1465 }
1466
1467 fn apply_change_value_impl(&mut self, tag: Tag, new_value: PrimitiveValue) {
1468 self.invalidate_if_charset_changed(tag);
1469
1470 if let Some(e) = self.entries.get_mut(&tag) {
1471 let vr = e.vr();
1472 let new_value = if vr == VR::SQ && new_value.is_empty() {
1475 DataSetSequence::empty().into()
1476 } else {
1477 Value::from(new_value)
1478 };
1479 *e = DataElement::new(tag, vr, new_value);
1480 self.len = Length::UNDEFINED;
1481 } else {
1482 let vr = dicom_dictionary_std::StandardDataDictionary
1484 .by_tag(tag)
1485 .and_then(|entry| entry.vr().exact())
1486 .unwrap_or(VR::UN);
1487 let new_value = if vr == VR::SQ && new_value.is_empty() {
1492 DataSetSequence::empty().into()
1493 } else {
1494 Value::from(new_value)
1495 };
1496
1497 self.put(DataElement::new(tag, vr, new_value));
1498 }
1499 }
1500
1501 fn invalidate_if_charset_changed(&mut self, tag: Tag) {
1502 if tag == tags::SPECIFIC_CHARACTER_SET {
1503 self.charset_changed = true;
1504 }
1505 }
1506
1507 fn apply_push_str_impl(&mut self, tag: Tag, string: Cow<'static, str>) -> ApplyResult {
1508 if let Some(e) = self.entries.remove(&tag) {
1509 let (header, value) = e.into_parts();
1510 match value {
1511 Value::Primitive(mut v) => {
1512 self.invalidate_if_charset_changed(tag);
1513 v.extend_str([string]).context(ModifySnafu)?;
1515 self.put(DataElement::new(tag, header.vr, v));
1517 Ok(())
1518 }
1519
1520 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1521 kind: ValueType::PixelSequence,
1522 }
1523 .fail(),
1524 Value::Sequence(..) => IncompatibleTypesSnafu {
1525 kind: ValueType::DataSetSequence,
1526 }
1527 .fail(),
1528 }
1529 } else {
1530 let vr = dicom_dictionary_std::StandardDataDictionary
1532 .by_tag(tag)
1533 .and_then(|entry| entry.vr().exact())
1534 .unwrap_or(VR::UN);
1535 self.put(DataElement::new(tag, vr, PrimitiveValue::from(&*string)));
1537 Ok(())
1538 }
1539 }
1540
1541 fn apply_push_i32_impl(&mut self, tag: Tag, integer: i32) -> ApplyResult {
1542 if let Some(e) = self.entries.remove(&tag) {
1543 let (header, value) = e.into_parts();
1544 match value {
1545 Value::Primitive(mut v) => {
1546 v.extend_i32([integer]).context(ModifySnafu)?;
1548 self.put(DataElement::new(tag, header.vr, v));
1550 Ok(())
1551 }
1552
1553 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1554 kind: ValueType::PixelSequence,
1555 }
1556 .fail(),
1557 Value::Sequence(..) => IncompatibleTypesSnafu {
1558 kind: ValueType::DataSetSequence,
1559 }
1560 .fail(),
1561 }
1562 } else {
1563 let vr = dicom_dictionary_std::StandardDataDictionary
1565 .by_tag(tag)
1566 .and_then(|entry| entry.vr().exact())
1567 .unwrap_or(VR::SL);
1568 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1570 Ok(())
1571 }
1572 }
1573
1574 fn apply_push_u32_impl(&mut self, tag: Tag, integer: u32) -> ApplyResult {
1575 if let Some(e) = self.entries.remove(&tag) {
1576 let (header, value) = e.into_parts();
1577 match value {
1578 Value::Primitive(mut v) => {
1579 v.extend_u32([integer]).context(ModifySnafu)?;
1581 self.put(DataElement::new(tag, header.vr, v));
1583 Ok(())
1584 }
1585
1586 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1587 kind: ValueType::PixelSequence,
1588 }
1589 .fail(),
1590 Value::Sequence(..) => IncompatibleTypesSnafu {
1591 kind: ValueType::DataSetSequence,
1592 }
1593 .fail(),
1594 }
1595 } else {
1596 let vr = dicom_dictionary_std::StandardDataDictionary
1598 .by_tag(tag)
1599 .and_then(|entry| entry.vr().exact())
1600 .unwrap_or(VR::UL);
1601 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1603 Ok(())
1604 }
1605 }
1606
1607 fn apply_push_i16_impl(&mut self, tag: Tag, integer: i16) -> ApplyResult {
1608 if let Some(e) = self.entries.remove(&tag) {
1609 let (header, value) = e.into_parts();
1610 match value {
1611 Value::Primitive(mut v) => {
1612 v.extend_i16([integer]).context(ModifySnafu)?;
1614 self.put(DataElement::new(tag, header.vr, v));
1616 Ok(())
1617 }
1618
1619 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1620 kind: ValueType::PixelSequence,
1621 }
1622 .fail(),
1623 Value::Sequence(..) => IncompatibleTypesSnafu {
1624 kind: ValueType::DataSetSequence,
1625 }
1626 .fail(),
1627 }
1628 } else {
1629 let vr = dicom_dictionary_std::StandardDataDictionary
1631 .by_tag(tag)
1632 .and_then(|entry| entry.vr().exact())
1633 .unwrap_or(VR::SS);
1634 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1636 Ok(())
1637 }
1638 }
1639
1640 fn apply_push_u16_impl(&mut self, tag: Tag, integer: u16) -> ApplyResult {
1641 if let Some(e) = self.entries.remove(&tag) {
1642 let (header, value) = e.into_parts();
1643 match value {
1644 Value::Primitive(mut v) => {
1645 v.extend_u16([integer]).context(ModifySnafu)?;
1647 self.put(DataElement::new(tag, header.vr, v));
1649 Ok(())
1650 }
1651
1652 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1653 kind: ValueType::PixelSequence,
1654 }
1655 .fail(),
1656 Value::Sequence(..) => IncompatibleTypesSnafu {
1657 kind: ValueType::DataSetSequence,
1658 }
1659 .fail(),
1660 }
1661 } else {
1662 let vr = dicom_dictionary_std::StandardDataDictionary
1664 .by_tag(tag)
1665 .and_then(|entry| entry.vr().exact())
1666 .unwrap_or(VR::US);
1667 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1669 Ok(())
1670 }
1671 }
1672
1673 fn apply_push_f32_impl(&mut self, tag: Tag, number: f32) -> ApplyResult {
1674 if let Some(e) = self.entries.remove(&tag) {
1675 let (header, value) = e.into_parts();
1676 match value {
1677 Value::Primitive(mut v) => {
1678 v.extend_f32([number]).context(ModifySnafu)?;
1680 self.put(DataElement::new(tag, header.vr, v));
1682 Ok(())
1683 }
1684
1685 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1686 kind: ValueType::PixelSequence,
1687 }
1688 .fail(),
1689 Value::Sequence(..) => IncompatibleTypesSnafu {
1690 kind: ValueType::DataSetSequence,
1691 }
1692 .fail(),
1693 }
1694 } else {
1695 let vr = dicom_dictionary_std::StandardDataDictionary
1697 .by_tag(tag)
1698 .and_then(|entry| entry.vr().exact())
1699 .unwrap_or(VR::FL);
1700 self.put(DataElement::new(tag, vr, PrimitiveValue::from(number)));
1702 Ok(())
1703 }
1704 }
1705
1706 fn apply_push_f64_impl(&mut self, tag: Tag, number: f64) -> ApplyResult {
1707 if let Some(e) = self.entries.remove(&tag) {
1708 let (header, value) = e.into_parts();
1709 match value {
1710 Value::Primitive(mut v) => {
1711 v.extend_f64([number]).context(ModifySnafu)?;
1713 self.put(DataElement::new(tag, header.vr, v));
1715 Ok(())
1716 }
1717
1718 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1719 kind: ValueType::PixelSequence,
1720 }
1721 .fail(),
1722 Value::Sequence(..) => IncompatibleTypesSnafu {
1723 kind: ValueType::DataSetSequence,
1724 }
1725 .fail(),
1726 }
1727 } else {
1728 let vr = dicom_dictionary_std::StandardDataDictionary
1730 .by_tag(tag)
1731 .and_then(|entry| entry.vr().exact())
1732 .unwrap_or(VR::FD);
1733 self.put(DataElement::new(tag, vr, PrimitiveValue::from(number)));
1735 Ok(())
1736 }
1737 }
1738
1739 pub fn write_dataset<W, E>(&self, to: W, encoder: E) -> Result<(), WriteError>
1753 where
1754 W: Write,
1755 E: EncodeTo<W>,
1756 {
1757 let mut dset_writer = DataSetWriter::new(to, encoder);
1759 let required_options = IntoTokensOptions::new(self.charset_changed);
1760 dset_writer
1762 .write_sequence(self.into_tokens_with_options(required_options))
1763 .context(PrintDataSetSnafu)?;
1764
1765 Ok(())
1766 }
1767
1768 pub fn write_dataset_with_ts_cs<W>(
1776 &self,
1777 to: W,
1778 ts: &TransferSyntax,
1779 cs: SpecificCharacterSet,
1780 ) -> Result<(), WriteError>
1781 where
1782 W: Write,
1783 {
1784 let mut dset_writer = DataSetWriter::with_ts_cs(to, ts, cs).context(CreatePrinterSnafu)?;
1786 let required_options = IntoTokensOptions::new(self.charset_changed);
1787
1788 dset_writer
1790 .write_sequence(self.into_tokens_with_options(required_options))
1791 .context(PrintDataSetSnafu)?;
1792
1793 Ok(())
1794 }
1795
1796 pub fn write_dataset_with_ts<W>(&self, to: W, ts: &TransferSyntax) -> Result<(), WriteError>
1804 where
1805 W: Write,
1806 {
1807 self.write_dataset_with_ts_cs(to, ts, SpecificCharacterSet::default())
1808 }
1809
1810 pub fn with_exact_meta(self, meta: FileMetaTable) -> FileDicomObject<Self> {
1819 FileDicomObject { meta, obj: self }
1820 }
1821
1822 pub fn with_meta(
1855 self,
1856 mut meta: FileMetaTableBuilder,
1857 ) -> Result<FileDicomObject<Self>, WithMetaError> {
1858 if let Some(elem) = self.get(tags::SOP_INSTANCE_UID) {
1859 meta = meta.media_storage_sop_instance_uid(
1860 elem.value().to_str().context(PrepareMetaTableSnafu)?,
1861 );
1862 }
1863 if let Some(elem) = self.get(tags::SOP_CLASS_UID) {
1864 meta = meta
1865 .media_storage_sop_class_uid(elem.value().to_str().context(PrepareMetaTableSnafu)?);
1866 }
1867 Ok(FileDicomObject {
1868 meta: meta.build().context(BuildMetaTableSnafu)?,
1869 obj: self,
1870 })
1871 }
1872
1873 pub fn iter(&self) -> impl Iterator<Item = &InMemElement<D>> + '_ {
1875 self.into_iter()
1876 }
1877
1878 pub fn tags(&self) -> impl Iterator<Item = Tag> + '_ {
1880 self.entries.keys().copied()
1881 }
1882
1883 fn build_object<I>(
1887 dataset: &mut I,
1888 dict: D,
1889 in_item: bool,
1890 len: Length,
1891 read_until: Option<Tag>,
1892 ) -> Result<Self, ReadError>
1893 where
1894 I: ?Sized + Iterator<Item = ParserResult<DataToken>>,
1895 {
1896 let mut entries: BTreeMap<Tag, InMemElement<D>> = BTreeMap::new();
1897 while let Some(token) = dataset.next() {
1899 let elem = match token.context(ReadTokenSnafu)? {
1900 DataToken::PixelSequenceStart => {
1901 if read_until
1903 .map(|t| t <= Tag(0x7fe0, 0x0010))
1904 .unwrap_or(false)
1905 {
1906 break;
1907 }
1908 let value = InMemDicomObject::build_encapsulated_data(&mut *dataset)?;
1909 DataElement::new(Tag(0x7fe0, 0x0010), VR::OB, value)
1910 }
1911 DataToken::ElementHeader(header) => {
1912 if read_until.map(|t| t <= header.tag).unwrap_or(false) {
1914 break;
1915 }
1916
1917 let next_token = dataset.next().context(MissingElementValueSnafu)?;
1919 match next_token.context(ReadTokenSnafu)? {
1920 DataToken::PrimitiveValue(v) => InMemElement::new_with_len(
1921 header.tag,
1922 header.vr,
1923 header.len,
1924 Value::Primitive(v),
1925 ),
1926 token => {
1927 return UnexpectedTokenSnafu { token }.fail();
1928 }
1929 }
1930 }
1931 DataToken::SequenceStart { tag, len } => {
1932 if read_until.map(|t| t <= tag).unwrap_or(false) {
1934 break;
1935 }
1936
1937 let items = Self::build_sequence(tag, len, &mut *dataset, &dict)?;
1939 DataElement::new_with_len(
1940 tag,
1941 VR::SQ,
1942 len,
1943 Value::Sequence(DataSetSequence::new(items, len)),
1944 )
1945 }
1946 DataToken::ItemEnd if in_item => {
1947 return Ok(InMemDicomObject {
1949 entries,
1950 dict,
1951 len,
1952 charset_changed: false,
1953 });
1954 }
1955 token => return UnexpectedTokenSnafu { token }.fail(),
1956 };
1957 entries.insert(elem.tag(), elem);
1958 }
1959
1960 Ok(InMemDicomObject {
1961 entries,
1962 dict,
1963 len,
1964 charset_changed: false,
1965 })
1966 }
1967
1968 fn build_encapsulated_data<I>(
1971 dataset: I,
1972 ) -> Result<Value<InMemDicomObject<D>, InMemFragment>, ReadError>
1973 where
1974 I: Iterator<Item = ParserResult<DataToken>>,
1975 {
1976 let mut offset_table = None;
1985
1986 let mut fragments = C::new();
1987
1988 for token in dataset {
1989 match token.context(ReadTokenSnafu)? {
1990 DataToken::OffsetTable(table) => {
1991 offset_table = Some(table);
1992 }
1993 DataToken::ItemValue(data) => {
1994 fragments.push(data);
1995 }
1996 DataToken::ItemEnd => {
1997 if offset_table.is_none() {
2001 offset_table = Some(Vec::new())
2002 }
2003 }
2004 DataToken::ItemStart { len: _ } => { }
2005 DataToken::SequenceEnd => {
2006 break;
2008 }
2009 token @ DataToken::ElementHeader(_)
2011 | token @ DataToken::PixelSequenceStart
2012 | token @ DataToken::SequenceStart { .. }
2013 | token @ DataToken::PrimitiveValue(_) => {
2014 return UnexpectedTokenSnafu { token }.fail();
2015 }
2016 }
2017 }
2018
2019 Ok(Value::PixelSequence(PixelFragmentSequence::new(
2020 offset_table.unwrap_or_default(),
2021 fragments,
2022 )))
2023 }
2024
2025 fn build_sequence<I>(
2027 _tag: Tag,
2028 _len: Length,
2029 dataset: &mut I,
2030 dict: &D,
2031 ) -> Result<C<InMemDicomObject<D>>, ReadError>
2032 where
2033 I: ?Sized + Iterator<Item = ParserResult<DataToken>>,
2034 {
2035 let mut items: C<_> = SmallVec::new();
2036 while let Some(token) = dataset.next() {
2037 match token.context(ReadTokenSnafu)? {
2038 DataToken::ItemStart { len } => {
2039 items.push(Self::build_object(
2040 &mut *dataset,
2041 dict.clone(),
2042 true,
2043 len,
2044 None,
2045 )?);
2046 }
2047 DataToken::SequenceEnd => {
2048 return Ok(items);
2049 }
2050 token => return UnexpectedTokenSnafu { token }.fail(),
2051 };
2052 }
2053
2054 PrematureEndSnafu.fail()
2056 }
2057
2058 fn lookup_name(&self, name: &str) -> Result<Tag, AccessByNameError> {
2059 self.dict
2060 .by_name(name)
2061 .context(NoSuchAttributeNameSnafu { name })
2062 .map(|e| e.tag())
2063 }
2064}
2065
2066impl<D> ApplyOp for InMemDicomObject<D>
2067where
2068 D: DataDictionary,
2069 D: Clone,
2070{
2071 type Err = ApplyError;
2072
2073 #[inline]
2074 fn apply(&mut self, op: AttributeOp) -> ApplyResult {
2075 self.apply(op)
2076 }
2077}
2078
2079impl<'a, D> IntoIterator for &'a InMemDicomObject<D> {
2080 type Item = &'a InMemElement<D>;
2081 type IntoIter = ::std::collections::btree_map::Values<'a, Tag, InMemElement<D>>;
2082
2083 fn into_iter(self) -> Self::IntoIter {
2084 self.entries.values()
2085 }
2086}
2087
2088impl<D> IntoIterator for InMemDicomObject<D> {
2089 type Item = InMemElement<D>;
2090 type IntoIter = Iter<D>;
2091
2092 fn into_iter(self) -> Self::IntoIter {
2093 Iter {
2094 inner: self.entries.into_iter(),
2095 }
2096 }
2097}
2098
2099#[derive(Debug)]
2101pub struct Iter<D> {
2102 inner: ::std::collections::btree_map::IntoIter<Tag, InMemElement<D>>,
2103}
2104
2105impl<D> Iterator for Iter<D> {
2106 type Item = InMemElement<D>;
2107
2108 fn next(&mut self) -> Option<Self::Item> {
2109 self.inner.next().map(|x| x.1)
2110 }
2111
2112 fn size_hint(&self) -> (usize, Option<usize>) {
2113 self.inner.size_hint()
2114 }
2115
2116 fn count(self) -> usize {
2117 self.inner.count()
2118 }
2119}
2120
2121impl<D> Extend<InMemElement<D>> for InMemDicomObject<D> {
2122 fn extend<I>(&mut self, iter: I)
2123 where
2124 I: IntoIterator<Item = InMemElement<D>>,
2125 {
2126 self.len = Length::UNDEFINED;
2127 self.entries.extend(iter.into_iter().map(|e| (e.tag(), e)))
2128 }
2129}
2130
2131fn even_len(l: u32) -> u32 {
2132 (l + 1) & !1
2133}
2134
2135#[cfg(test)]
2136mod tests {
2137 use super::*;
2138 use crate::open_file;
2139 use byteordered::Endianness;
2140 use dicom_core::chrono::FixedOffset;
2141 use dicom_core::value::{DicomDate, DicomDateTime, DicomTime};
2142 use dicom_core::{dicom_value, header::DataElementHeader};
2143 use dicom_encoding::{
2144 decode::{basic::BasicDecoder, implicit_le::ImplicitVRLittleEndianDecoder},
2145 encode::{implicit_le::ImplicitVRLittleEndianEncoder, EncoderFor},
2146 };
2147 use dicom_parser::StatefulDecoder;
2148
2149 fn assert_obj_eq<D>(obj1: &InMemDicomObject<D>, obj2: &InMemDicomObject<D>)
2150 where
2151 D: std::fmt::Debug,
2152 {
2153 assert_eq!(format!("{:?}", obj1), format!("{:?}", obj2))
2156 }
2157
2158 #[test]
2159 fn inmem_object_compare() {
2160 let mut obj1 = InMemDicomObject::new_empty();
2161 let mut obj2 = InMemDicomObject::new_empty();
2162 assert_eq!(obj1, obj2);
2163 let empty_patient_name = DataElement::empty(Tag(0x0010, 0x0010), VR::PN);
2164 obj1.put(empty_patient_name.clone());
2165 assert_ne!(obj1, obj2);
2166 obj2.put(empty_patient_name.clone());
2167 assert_obj_eq(&obj1, &obj2);
2168 }
2169
2170 #[test]
2171 fn inmem_object_read_dataset() {
2172 let data_in = [
2173 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2176 ];
2177
2178 let decoder = ImplicitVRLittleEndianDecoder::default();
2179 let text = SpecificCharacterSet::default();
2180 let mut cursor = &data_in[..];
2181 let parser = StatefulDecoder::new(
2182 &mut cursor,
2183 decoder,
2184 BasicDecoder::new(Endianness::Little),
2185 text,
2186 );
2187
2188 let obj = InMemDicomObject::read_dataset(parser).unwrap();
2189
2190 let mut gt = InMemDicomObject::new_empty();
2191
2192 let patient_name = DataElement::new(
2193 Tag(0x0010, 0x0010),
2194 VR::PN,
2195 dicom_value!(Strs, ["Doe^John"]),
2196 );
2197 gt.put(patient_name);
2198
2199 assert_eq!(obj, gt);
2200 }
2201
2202 #[test]
2203 fn inmem_object_read_dataset_with_ts_cs() {
2204 let data_in = [
2205 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2208 ];
2209
2210 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2").unwrap();
2211 let cs = SpecificCharacterSet::default();
2212 let mut cursor = &data_in[..];
2213
2214 let obj = InMemDicomObject::read_dataset_with_dict_ts_cs(
2215 &mut cursor,
2216 StandardDataDictionary,
2217 &ts,
2218 cs,
2219 )
2220 .unwrap();
2221
2222 let mut gt = InMemDicomObject::new_empty();
2223
2224 let patient_name = DataElement::new(
2225 Tag(0x0010, 0x0010),
2226 VR::PN,
2227 dicom_value!(Strs, ["Doe^John"]),
2228 );
2229 gt.put(patient_name);
2230
2231 assert_eq!(obj, gt);
2232 }
2233
2234 #[test]
2237 fn inmem_object_read_dataset_saves_len() {
2238 let data_in = [
2239 0x08, 0x00, 0x05, 0x00, 0x0a, 0x00, 0x00, 0x00, b'I', b'S', b'O', b'_', b'I', b'R', b' ', b'1', b'0', b'0',
2244 0x08, 0x00, 0x90, 0x00, 0x0c, 0x00, 0x00, 0x00, b'S', b'i', b'm', 0xF5, b'e', b's', b'^', b'J', b'o', 0xE3,
2248 b'o', b' ',
2249 ];
2250
2251 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2").unwrap();
2252 let mut cursor = &data_in[..];
2253
2254 let obj =
2255 InMemDicomObject::read_dataset_with_dict_ts(&mut cursor, StandardDataDictionary, &ts)
2256 .unwrap();
2257
2258 let physician_name = obj.element(Tag(0x0008, 0x0090)).unwrap();
2259 assert_eq!(physician_name.header().len, Length(12));
2260 assert_eq!(physician_name.value().to_str().unwrap(), "Simões^João");
2261 }
2262
2263 #[test]
2264 fn inmem_object_write_dataset() {
2265 let mut obj = InMemDicomObject::new_empty();
2266
2267 let patient_name =
2268 DataElement::new(Tag(0x0010, 0x0010), VR::PN, dicom_value!(Str, "Doe^John"));
2269 obj.put(patient_name);
2270
2271 let mut out = Vec::new();
2272
2273 let printer = EncoderFor::new(ImplicitVRLittleEndianEncoder::default());
2274
2275 obj.write_dataset(&mut out, printer).unwrap();
2276
2277 assert_eq!(
2278 out,
2279 &[
2280 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2283 ][..],
2284 );
2285 }
2286
2287 #[test]
2288 fn inmem_object_write_dataset_with_ts() {
2289 let mut obj = InMemDicomObject::new_empty();
2290
2291 let patient_name =
2292 DataElement::new(Tag(0x0010, 0x0010), VR::PN, dicom_value!(Str, "Doe^John"));
2293 obj.put(patient_name);
2294
2295 let mut out = Vec::new();
2296
2297 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2.1").unwrap();
2298
2299 obj.write_dataset_with_ts(&mut out, &ts).unwrap();
2300
2301 assert_eq!(
2302 out,
2303 &[
2304 0x10, 0x00, 0x10, 0x00, b'P', b'N', 0x08, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2308 ][..],
2309 );
2310 }
2311
2312 #[test]
2313 fn inmem_object_write_dataset_with_ts_cs() {
2314 let mut obj = InMemDicomObject::new_empty();
2315
2316 let patient_name =
2317 DataElement::new(Tag(0x0010, 0x0010), VR::PN, dicom_value!(Str, "Doe^John"));
2318 obj.put(patient_name);
2319
2320 let mut out = Vec::new();
2321
2322 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2").unwrap();
2323 let cs = SpecificCharacterSet::default();
2324
2325 obj.write_dataset_with_ts_cs(&mut out, &ts, cs).unwrap();
2326
2327 assert_eq!(
2328 out,
2329 &[
2330 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2333 ][..],
2334 );
2335 }
2336
2337 #[test]
2340 fn inmem_object_write_datetime_odd() {
2341 let mut obj = InMemDicomObject::new_empty();
2342
2343 let instance_number =
2345 DataElement::new(Tag(0x0020, 0x0013), VR::IS, PrimitiveValue::from(1_i32));
2346 obj.put(instance_number);
2347
2348 let dt = DicomDateTime::from_date_and_time_with_time_zone(
2350 DicomDate::from_ymd(2022, 11, 22).unwrap(),
2351 DicomTime::from_hms(18, 09, 35).unwrap(),
2352 FixedOffset::east_opt(3600).unwrap(),
2353 )
2354 .unwrap();
2355 let instance_coercion_date_time =
2356 DataElement::new(Tag(0x0008, 0x0015), VR::DT, dicom_value!(DateTime, dt));
2357 obj.put(instance_coercion_date_time);
2358
2359 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2.1").unwrap();
2361
2362 let mut out = Vec::new();
2363 obj.write_dataset_with_ts(&mut out, &ts)
2364 .expect("should write DICOM data without errors");
2365
2366 assert_eq!(
2367 out,
2368 &[
2369 0x08, 0x00, 0x15, 0x00, b'D', b'T', 0x14, 0x00, b'2', b'0', b'2', b'2', b'1', b'1', b'2', b'2', b'1', b'8', b'0', b'9', b'3', b'5', b'+', b'0', b'1', b'0', b'0', b' ', 0x20, 0x00, 0x13, 0x00, b'I', b'S', 0x02, 0x00, b'1', b' ' ][..],
2383 );
2384 }
2385
2386 #[test]
2389 fn inmem_write_to_file_with_meta() {
2390 let sop_uid = "1.4.645.212121";
2391 let mut obj = InMemDicomObject::new_empty();
2392
2393 obj.put(DataElement::new(
2394 Tag(0x0010, 0x0010),
2395 VR::PN,
2396 dicom_value!(Strs, ["Doe^John"]),
2397 ));
2398 obj.put(DataElement::new(
2399 Tag(0x0008, 0x0060),
2400 VR::CS,
2401 dicom_value!(Strs, ["CR"]),
2402 ));
2403 obj.put(DataElement::new(
2404 Tag(0x0008, 0x0018),
2405 VR::UI,
2406 dicom_value!(Strs, [sop_uid]),
2407 ));
2408
2409 let file_object = obj
2410 .with_meta(
2411 FileMetaTableBuilder::default()
2412 .transfer_syntax("1.2.840.10008.1.2.1")
2414 .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.1")
2416 .media_storage_sop_instance_uid(sop_uid),
2417 )
2418 .unwrap();
2419
2420 let dir = tempfile::tempdir().unwrap();
2422 let mut file_path = dir.into_path();
2423 file_path.push(format!("{}.dcm", sop_uid));
2424
2425 file_object.write_to_file(&file_path).unwrap();
2426
2427 let saved_object = open_file(file_path).unwrap();
2429 assert_eq!(file_object, saved_object);
2430 }
2431
2432 #[test]
2435 fn inmem_with_meta_infers_sop_instance_uid() {
2436 let sop_uid = "1.4.645.252521";
2437 let mut obj = InMemDicomObject::new_empty();
2438
2439 obj.put(DataElement::new(
2440 tags::SOP_INSTANCE_UID,
2441 VR::UI,
2442 PrimitiveValue::from(sop_uid),
2443 ));
2444
2445 let file_object = obj
2446 .with_meta(
2447 FileMetaTableBuilder::default()
2449 .transfer_syntax("1.2.840.10008.1.2.1")
2451 .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.1"),
2453 )
2454 .unwrap();
2455
2456 let meta = file_object.meta();
2457
2458 assert_eq!(
2459 meta.media_storage_sop_instance_uid
2460 .trim_end_matches(|c| c == '\0'),
2461 sop_uid.trim_end_matches(|c| c == '\0'),
2462 );
2463 }
2464
2465 #[test]
2467 fn inmem_write_to_file_with_exact_meta() {
2468 let sop_uid = "1.4.645.212121";
2469 let mut obj = InMemDicomObject::new_empty();
2470
2471 obj.put(DataElement::new(
2472 Tag(0x0010, 0x0010),
2473 VR::PN,
2474 dicom_value!(Strs, ["Doe^John"]),
2475 ));
2476 obj.put(DataElement::new(
2477 Tag(0x0008, 0x0060),
2478 VR::CS,
2479 dicom_value!(Strs, ["CR"]),
2480 ));
2481 obj.put(DataElement::new(
2482 Tag(0x0008, 0x0018),
2483 VR::UI,
2484 dicom_value!(Strs, [sop_uid]),
2485 ));
2486
2487 let file_object = obj.with_exact_meta(
2488 FileMetaTableBuilder::default()
2489 .transfer_syntax("1.2.840.10008.1.2.1")
2491 .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.1")
2493 .media_storage_sop_instance_uid(sop_uid)
2494 .build()
2495 .unwrap(),
2496 );
2497
2498 let dir = tempfile::tempdir().unwrap();
2500 let mut file_path = dir.into_path();
2501 file_path.push(format!("{}.dcm", sop_uid));
2502
2503 file_object.write_to_file(&file_path).unwrap();
2504
2505 let saved_object = open_file(file_path).unwrap();
2507 assert_eq!(file_object, saved_object);
2508 }
2509
2510 #[test]
2511 fn inmem_object_get() {
2512 let another_patient_name = DataElement::new(
2513 Tag(0x0010, 0x0010),
2514 VR::PN,
2515 PrimitiveValue::Str("Doe^John".to_string()),
2516 );
2517 let mut obj = InMemDicomObject::new_empty();
2518 obj.put(another_patient_name.clone());
2519 let elem1 = (&obj).element(Tag(0x0010, 0x0010)).unwrap();
2520 assert_eq!(elem1, &another_patient_name);
2521 }
2522
2523 #[test]
2524 fn infer_media_sop_from_dataset_sop_elements() {
2525 let sop_instance_uid = "1.4.645.313131";
2526 let sop_class_uid = "1.2.840.10008.5.1.4.1.1.2";
2527 let mut obj = InMemDicomObject::new_empty();
2528
2529 obj.put(DataElement::new(
2530 Tag(0x0008, 0x0018),
2531 VR::UI,
2532 dicom_value!(Strs, [sop_instance_uid]),
2533 ));
2534 obj.put(DataElement::new(
2535 Tag(0x0008, 0x0016),
2536 VR::UI,
2537 dicom_value!(Strs, [sop_class_uid]),
2538 ));
2539
2540 let file_object = obj.with_exact_meta(
2541 FileMetaTableBuilder::default()
2542 .transfer_syntax("1.2.840.10008.1.2.1")
2543 .media_storage_sop_class_uid("")
2545 .media_storage_sop_instance_uid("")
2546 .build()
2547 .unwrap(),
2548 );
2549
2550 let dir = tempfile::tempdir().unwrap();
2552 let mut file_path = dir.into_path();
2553 file_path.push(format!("{}.dcm", sop_instance_uid));
2554
2555 file_object.write_to_file(&file_path).unwrap();
2556
2557 let saved_object = open_file(file_path).unwrap();
2559
2560 assert_eq!(
2562 saved_object.meta().media_storage_sop_instance_uid(),
2563 sop_instance_uid
2564 );
2565 assert_eq!(
2566 saved_object.meta().media_storage_sop_class_uid(),
2567 sop_class_uid
2568 );
2569 }
2570
2571 #[test]
2572 fn inmem_object_get_opt() {
2573 let another_patient_name = DataElement::new(
2574 Tag(0x0010, 0x0010),
2575 VR::PN,
2576 PrimitiveValue::Str("Doe^John".to_string()),
2577 );
2578 let mut obj = InMemDicomObject::new_empty();
2579 obj.put(another_patient_name.clone());
2580 let elem1 = obj.element_opt(Tag(0x0010, 0x0010)).unwrap();
2581 assert_eq!(elem1, Some(&another_patient_name));
2582
2583 assert_eq!(obj.element_opt(Tag(0x0010, 0x0020)).unwrap(), None);
2585 }
2586
2587 #[test]
2588 fn inmem_object_get_by_name() {
2589 let another_patient_name = DataElement::new(
2590 Tag(0x0010, 0x0010),
2591 VR::PN,
2592 PrimitiveValue::Str("Doe^John".to_string()),
2593 );
2594 let mut obj = InMemDicomObject::new_empty();
2595 obj.put(another_patient_name.clone());
2596 let elem1 = (&obj).element_by_name("PatientName").unwrap();
2597 assert_eq!(elem1, &another_patient_name);
2598 }
2599
2600 #[test]
2601 fn inmem_object_get_by_name_opt() {
2602 let another_patient_name = DataElement::new(
2603 Tag(0x0010, 0x0010),
2604 VR::PN,
2605 PrimitiveValue::Str("Doe^John".to_string()),
2606 );
2607 let mut obj = InMemDicomObject::new_empty();
2608 obj.put(another_patient_name.clone());
2609 let elem1 = obj.element_by_name_opt("PatientName").unwrap();
2610 assert_eq!(elem1, Some(&another_patient_name));
2611
2612 assert_eq!(obj.element_by_name_opt("PatientID").unwrap(), None);
2614 }
2615
2616 #[test]
2617 fn inmem_object_take_element() {
2618 let another_patient_name = DataElement::new(
2619 Tag(0x0010, 0x0010),
2620 VR::PN,
2621 PrimitiveValue::Str("Doe^John".to_string()),
2622 );
2623 let mut obj = InMemDicomObject::new_empty();
2624 obj.put(another_patient_name.clone());
2625 let elem1 = obj.take_element(Tag(0x0010, 0x0010)).unwrap();
2626 assert_eq!(elem1, another_patient_name);
2627 assert!(matches!(
2628 obj.take_element(Tag(0x0010, 0x0010)),
2629 Err(AccessError::NoSuchDataElementTag {
2630 tag: Tag(0x0010, 0x0010),
2631 ..
2632 })
2633 ));
2634 }
2635
2636 #[test]
2637 fn inmem_object_take_element_by_name() {
2638 let another_patient_name = DataElement::new(
2639 Tag(0x0010, 0x0010),
2640 VR::PN,
2641 PrimitiveValue::Str("Doe^John".to_string()),
2642 );
2643 let mut obj = InMemDicomObject::new_empty();
2644 obj.put(another_patient_name.clone());
2645 let elem1 = obj.take_element_by_name("PatientName").unwrap();
2646 assert_eq!(elem1, another_patient_name);
2647 assert!(matches!(
2648 obj.take_element_by_name("PatientName"),
2649 Err(AccessByNameError::NoSuchDataElementAlias {
2650 tag: Tag(0x0010, 0x0010),
2651 alias,
2652 ..
2653 }) if alias == "PatientName"));
2654 }
2655
2656 #[test]
2657 fn inmem_object_remove_element() {
2658 let another_patient_name = DataElement::new(
2659 Tag(0x0010, 0x0010),
2660 VR::PN,
2661 PrimitiveValue::Str("Doe^John".to_string()),
2662 );
2663 let mut obj = InMemDicomObject::new_empty();
2664 obj.put(another_patient_name.clone());
2665 assert!(obj.remove_element(Tag(0x0010, 0x0010)));
2666 assert_eq!(obj.remove_element(Tag(0x0010, 0x0010)), false);
2667 }
2668
2669 #[test]
2670 fn inmem_object_remove_element_by_name() {
2671 let another_patient_name = DataElement::new(
2672 Tag(0x0010, 0x0010),
2673 VR::PN,
2674 PrimitiveValue::Str("Doe^John".to_string()),
2675 );
2676 let mut obj = InMemDicomObject::new_empty();
2677 obj.put(another_patient_name.clone());
2678 assert!(obj.remove_element_by_name("PatientName").unwrap());
2679 assert_eq!(obj.remove_element_by_name("PatientName").unwrap(), false);
2680 }
2681
2682 #[test]
2684 fn inmem_traverse_elements() {
2685 let sop_uid = "1.4.645.212121";
2686 let mut obj = InMemDicomObject::new_empty();
2687
2688 obj.put(DataElement::new(
2689 Tag(0x0010, 0x0010),
2690 VR::PN,
2691 dicom_value!(Strs, ["Doe^John"]),
2692 ));
2693 obj.put(DataElement::new(
2694 Tag(0x0008, 0x0060),
2695 VR::CS,
2696 dicom_value!(Strs, ["CR"]),
2697 ));
2698 obj.put(DataElement::new(
2699 Tag(0x0008, 0x0018),
2700 VR::UI,
2701 dicom_value!(Strs, [sop_uid]),
2702 ));
2703
2704 {
2705 let mut iter = obj.iter();
2706 assert_eq!(
2707 *iter.next().unwrap().header(),
2708 DataElementHeader::new(Tag(0x0008, 0x0018), VR::UI, Length(sop_uid.len() as u32)),
2709 );
2710 assert_eq!(
2711 *iter.next().unwrap().header(),
2712 DataElementHeader::new(Tag(0x0008, 0x0060), VR::CS, Length(2)),
2713 );
2714 assert_eq!(
2715 *iter.next().unwrap().header(),
2716 DataElementHeader::new(Tag(0x0010, 0x0010), VR::PN, Length(8)),
2717 );
2718 }
2719
2720 let tags: Vec<_> = obj.tags().collect();
2722 assert_eq!(
2723 tags,
2724 vec![
2725 Tag(0x0008, 0x0018),
2726 Tag(0x0008, 0x0060),
2727 Tag(0x0010, 0x0010),
2728 ]
2729 );
2730
2731 let mut iter = obj.into_iter();
2733 assert_eq!(
2734 iter.next(),
2735 Some(DataElement::new(
2736 Tag(0x0008, 0x0018),
2737 VR::UI,
2738 dicom_value!(Strs, [sop_uid]),
2739 )),
2740 );
2741 assert_eq!(
2742 iter.next(),
2743 Some(DataElement::new(
2744 Tag(0x0008, 0x0060),
2745 VR::CS,
2746 dicom_value!(Strs, ["CR"]),
2747 )),
2748 );
2749 assert_eq!(
2750 iter.next(),
2751 Some(DataElement::new(
2752 Tag(0x0010, 0x0010),
2753 VR::PN,
2754 PrimitiveValue::from("Doe^John"),
2755 )),
2756 );
2757 }
2758
2759 #[test]
2760 fn inmem_empty_object_into_tokens() {
2761 let obj = InMemDicomObject::new_empty();
2762 let tokens = obj.into_tokens();
2763 assert_eq!(tokens.count(), 0);
2764 }
2765
2766 #[test]
2767 fn inmem_shallow_object_from_tokens() {
2768 let tokens = vec![
2769 DataToken::ElementHeader(DataElementHeader {
2770 tag: Tag(0x0008, 0x0060),
2771 vr: VR::CS,
2772 len: Length(2),
2773 }),
2774 DataToken::PrimitiveValue(PrimitiveValue::Str("MG".to_owned())),
2775 DataToken::ElementHeader(DataElementHeader {
2776 tag: Tag(0x0010, 0x0010),
2777 vr: VR::PN,
2778 len: Length(8),
2779 }),
2780 DataToken::PrimitiveValue(PrimitiveValue::Str("Doe^John".to_owned())),
2781 ];
2782
2783 let gt_obj = InMemDicomObject::from_element_iter(vec![
2784 DataElement::new(
2785 Tag(0x0010, 0x0010),
2786 VR::PN,
2787 PrimitiveValue::Str("Doe^John".to_string()),
2788 ),
2789 DataElement::new(
2790 Tag(0x0008, 0x0060),
2791 VR::CS,
2792 PrimitiveValue::Str("MG".to_string()),
2793 ),
2794 ]);
2795
2796 let obj = InMemDicomObject::build_object(
2797 &mut tokens.into_iter().map(Result::Ok),
2798 StandardDataDictionary,
2799 false,
2800 Length::UNDEFINED,
2801 None,
2802 )
2803 .unwrap();
2804
2805 assert_obj_eq(&obj, >_obj);
2806 }
2807
2808 #[test]
2809 fn inmem_shallow_object_into_tokens() {
2810 let patient_name = DataElement::new(
2811 Tag(0x0010, 0x0010),
2812 VR::PN,
2813 PrimitiveValue::Str("Doe^John".to_string()),
2814 );
2815 let modality = DataElement::new(
2816 Tag(0x0008, 0x0060),
2817 VR::CS,
2818 PrimitiveValue::Str("MG".to_string()),
2819 );
2820 let mut obj = InMemDicomObject::new_empty();
2821 obj.put(patient_name);
2822 obj.put(modality);
2823
2824 let tokens: Vec<_> = obj.into_tokens().collect();
2825
2826 assert_eq!(
2827 tokens,
2828 vec![
2829 DataToken::ElementHeader(DataElementHeader {
2830 tag: Tag(0x0008, 0x0060),
2831 vr: VR::CS,
2832 len: Length(2),
2833 }),
2834 DataToken::PrimitiveValue(PrimitiveValue::Str("MG".to_owned())),
2835 DataToken::ElementHeader(DataElementHeader {
2836 tag: Tag(0x0010, 0x0010),
2837 vr: VR::PN,
2838 len: Length(8),
2839 }),
2840 DataToken::PrimitiveValue(PrimitiveValue::Str("Doe^John".to_owned())),
2841 ]
2842 );
2843 }
2844
2845 #[test]
2846 fn inmem_deep_object_from_tokens() {
2847 use smallvec::smallvec;
2848
2849 let obj_1 = InMemDicomObject::from_element_iter(vec![
2850 DataElement::new(Tag(0x0018, 0x6012), VR::US, Value::Primitive(1_u16.into())),
2851 DataElement::new(Tag(0x0018, 0x6014), VR::US, Value::Primitive(2_u16.into())),
2852 ]);
2853
2854 let obj_2 = InMemDicomObject::from_element_iter(vec![DataElement::new(
2855 Tag(0x0018, 0x6012),
2856 VR::US,
2857 Value::Primitive(4_u16.into()),
2858 )]);
2859
2860 let gt_obj = InMemDicomObject::from_element_iter(vec![
2861 DataElement::new(
2862 Tag(0x0018, 0x6011),
2863 VR::SQ,
2864 Value::from(DataSetSequence::new(
2865 smallvec![obj_1, obj_2],
2866 Length::UNDEFINED,
2867 )),
2868 ),
2869 DataElement::new(Tag(0x0020, 0x4000), VR::LT, Value::Primitive("TEST".into())),
2870 ]);
2871
2872 let tokens: Vec<_> = vec![
2873 DataToken::SequenceStart {
2874 tag: Tag(0x0018, 0x6011),
2875 len: Length::UNDEFINED,
2876 },
2877 DataToken::ItemStart {
2878 len: Length::UNDEFINED,
2879 },
2880 DataToken::ElementHeader(DataElementHeader {
2881 tag: Tag(0x0018, 0x6012),
2882 vr: VR::US,
2883 len: Length(2),
2884 }),
2885 DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
2886 DataToken::ElementHeader(DataElementHeader {
2887 tag: Tag(0x0018, 0x6014),
2888 vr: VR::US,
2889 len: Length(2),
2890 }),
2891 DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
2892 DataToken::ItemEnd,
2893 DataToken::ItemStart {
2894 len: Length::UNDEFINED,
2895 },
2896 DataToken::ElementHeader(DataElementHeader {
2897 tag: Tag(0x0018, 0x6012),
2898 vr: VR::US,
2899 len: Length(2),
2900 }),
2901 DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
2902 DataToken::ItemEnd,
2903 DataToken::SequenceEnd,
2904 DataToken::ElementHeader(DataElementHeader {
2905 tag: Tag(0x0020, 0x4000),
2906 vr: VR::LT,
2907 len: Length(4),
2908 }),
2909 DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
2910 ];
2911
2912 let obj = InMemDicomObject::build_object(
2913 &mut tokens.into_iter().map(Result::Ok),
2914 StandardDataDictionary,
2915 false,
2916 Length::UNDEFINED,
2917 None,
2918 )
2919 .unwrap();
2920
2921 assert_obj_eq(&obj, >_obj);
2922 }
2923
2924 #[test]
2925 fn inmem_deep_object_into_tokens() {
2926 use smallvec::smallvec;
2927
2928 let obj_1 = InMemDicomObject::from_element_iter(vec![
2929 DataElement::new(Tag(0x0018, 0x6012), VR::US, Value::Primitive(1_u16.into())),
2930 DataElement::new(Tag(0x0018, 0x6014), VR::US, Value::Primitive(2_u16.into())),
2931 ]);
2932
2933 let obj_2 = InMemDicomObject::from_element_iter(vec![DataElement::new(
2934 Tag(0x0018, 0x6012),
2935 VR::US,
2936 Value::Primitive(4_u16.into()),
2937 )]);
2938
2939 let main_obj = InMemDicomObject::from_element_iter(vec![
2940 DataElement::new(
2941 Tag(0x0018, 0x6011),
2942 VR::SQ,
2943 Value::from(DataSetSequence::new(
2944 smallvec![obj_1, obj_2],
2945 Length::UNDEFINED,
2946 )),
2947 ),
2948 DataElement::new(Tag(0x0020, 0x4000), VR::LT, Value::Primitive("TEST".into())),
2949 ]);
2950
2951 let tokens: Vec<_> = main_obj.into_tokens().collect();
2952
2953 assert_eq!(
2954 tokens,
2955 vec![
2956 DataToken::SequenceStart {
2957 tag: Tag(0x0018, 0x6011),
2958 len: Length::UNDEFINED,
2959 },
2960 DataToken::ItemStart {
2961 len: Length::UNDEFINED,
2962 },
2963 DataToken::ElementHeader(DataElementHeader {
2964 tag: Tag(0x0018, 0x6012),
2965 vr: VR::US,
2966 len: Length(2),
2967 }),
2968 DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
2969 DataToken::ElementHeader(DataElementHeader {
2970 tag: Tag(0x0018, 0x6014),
2971 vr: VR::US,
2972 len: Length(2),
2973 }),
2974 DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
2975 DataToken::ItemEnd,
2976 DataToken::ItemStart {
2977 len: Length::UNDEFINED,
2978 },
2979 DataToken::ElementHeader(DataElementHeader {
2980 tag: Tag(0x0018, 0x6012),
2981 vr: VR::US,
2982 len: Length(2),
2983 }),
2984 DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
2985 DataToken::ItemEnd,
2986 DataToken::SequenceEnd,
2987 DataToken::ElementHeader(DataElementHeader {
2988 tag: Tag(0x0020, 0x4000),
2989 vr: VR::LT,
2990 len: Length(4),
2991 }),
2992 DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
2993 ]
2994 );
2995 }
2996
2997 #[test]
2998 fn inmem_encapsulated_pixel_data_from_tokens() {
2999 use smallvec::smallvec;
3000
3001 let gt_obj = InMemDicomObject::from_element_iter(vec![DataElement::new(
3002 Tag(0x7fe0, 0x0010),
3003 VR::OB,
3004 Value::from(PixelFragmentSequence::new_fragments(smallvec![vec![
3005 0x33;
3006 32
3007 ]])),
3008 )]);
3009
3010 let tokens: Vec<_> = vec![
3011 DataToken::PixelSequenceStart,
3012 DataToken::ItemStart { len: Length(0) },
3013 DataToken::ItemEnd,
3014 DataToken::ItemStart { len: Length(32) },
3015 DataToken::ItemValue(vec![0x33; 32]),
3016 DataToken::ItemEnd,
3017 DataToken::SequenceEnd,
3018 ];
3019
3020 let obj = InMemDicomObject::build_object(
3021 &mut tokens.into_iter().map(Result::Ok),
3022 StandardDataDictionary,
3023 false,
3024 Length::UNDEFINED,
3025 None,
3026 )
3027 .unwrap();
3028
3029 assert_obj_eq(&obj, >_obj);
3030 }
3031
3032 #[test]
3033 fn inmem_encapsulated_pixel_data_into_tokens() {
3034 use smallvec::smallvec;
3035
3036 let main_obj = InMemDicomObject::from_element_iter(vec![DataElement::new(
3037 Tag(0x7fe0, 0x0010),
3038 VR::OB,
3039 Value::from(PixelFragmentSequence::new_fragments(smallvec![vec![
3040 0x33;
3041 32
3042 ]])),
3043 )]);
3044
3045 let tokens: Vec<_> = main_obj.into_tokens().collect();
3046
3047 assert_eq!(
3048 tokens,
3049 vec![
3050 DataToken::PixelSequenceStart,
3051 DataToken::ItemStart { len: Length(0) },
3052 DataToken::ItemEnd,
3053 DataToken::ItemStart { len: Length(32) },
3054 DataToken::ItemValue(vec![0x33; 32]),
3055 DataToken::ItemEnd,
3056 DataToken::SequenceEnd,
3057 ]
3058 );
3059 }
3060
3061 #[test]
3063 fn inmem_ops() {
3064 let base_obj = InMemDicomObject::from_element_iter([
3066 DataElement::new(
3067 tags::SERIES_INSTANCE_UID,
3068 VR::UI,
3069 PrimitiveValue::from("2.25.137041794342168732369025909031346220736.1"),
3070 ),
3071 DataElement::new(
3072 tags::SERIES_INSTANCE_UID,
3073 VR::UI,
3074 PrimitiveValue::from("2.25.137041794342168732369025909031346220736.1"),
3075 ),
3076 DataElement::new(
3077 tags::SOP_INSTANCE_UID,
3078 VR::UI,
3079 PrimitiveValue::from("2.25.137041794342168732369025909031346220736.1.1"),
3080 ),
3081 DataElement::new(
3082 tags::STUDY_DESCRIPTION,
3083 VR::LO,
3084 PrimitiveValue::from("Test study"),
3085 ),
3086 DataElement::new(
3087 tags::INSTITUTION_NAME,
3088 VR::LO,
3089 PrimitiveValue::from("Test Hospital"),
3090 ),
3091 DataElement::new(tags::ROWS, VR::US, PrimitiveValue::from(768_u16)),
3092 DataElement::new(tags::COLUMNS, VR::US, PrimitiveValue::from(1024_u16)),
3093 DataElement::new(
3094 tags::LOSSY_IMAGE_COMPRESSION,
3095 VR::CS,
3096 PrimitiveValue::from("01"),
3097 ),
3098 DataElement::new(
3099 tags::LOSSY_IMAGE_COMPRESSION_RATIO,
3100 VR::DS,
3101 PrimitiveValue::from("5"),
3102 ),
3103 DataElement::new(
3104 tags::LOSSY_IMAGE_COMPRESSION_METHOD,
3105 VR::DS,
3106 PrimitiveValue::from("ISO_10918_1"),
3107 ),
3108 ]);
3109
3110 {
3111 let mut obj = base_obj.clone();
3113 let op = AttributeOp {
3114 selector: AttributeSelector::from(tags::STUDY_DESCRIPTION),
3115 action: AttributeAction::Remove,
3116 };
3117
3118 obj.apply(op).unwrap();
3119
3120 assert_eq!(obj.get(tags::STUDY_DESCRIPTION), None);
3121 }
3122 {
3123 let mut obj = base_obj.clone();
3124
3125 let op = AttributeOp {
3128 selector: tags::INSTITUTION_NAME.into(),
3129 action: AttributeAction::SetIfMissing("Nope Hospital".into()),
3130 };
3131
3132 obj.apply(op).unwrap();
3133
3134 assert_eq!(
3135 obj.get(tags::INSTITUTION_NAME),
3136 Some(&DataElement::new(
3137 tags::INSTITUTION_NAME,
3138 VR::LO,
3139 PrimitiveValue::from("Test Hospital"),
3140 ))
3141 );
3142
3143 let op = AttributeOp::new(
3145 tags::INSTITUTION_NAME,
3146 AttributeAction::ReplaceStr("REMOVED".into()),
3147 );
3148
3149 obj.apply(op).unwrap();
3150
3151 assert_eq!(
3152 obj.get(tags::INSTITUTION_NAME),
3153 Some(&DataElement::new(
3154 tags::INSTITUTION_NAME,
3155 VR::LO,
3156 PrimitiveValue::from("REMOVED"),
3157 ))
3158 );
3159
3160 let op = AttributeOp::new(
3163 tags::REQUESTING_PHYSICIAN,
3164 AttributeAction::ReplaceStr("Doctor^Anonymous".into()),
3165 );
3166
3167 obj.apply(op).unwrap();
3168
3169 assert_eq!(obj.get(tags::REQUESTING_PHYSICIAN), None);
3170
3171 let op = AttributeOp::new(
3173 tags::REQUESTING_PHYSICIAN,
3174 AttributeAction::SetStrIfMissing("Doctor^Anonymous".into()),
3175 );
3176
3177 obj.apply(op).unwrap();
3178
3179 assert_eq!(
3180 obj.get(tags::REQUESTING_PHYSICIAN),
3181 Some(&DataElement::new(
3182 tags::REQUESTING_PHYSICIAN,
3183 VR::PN,
3184 PrimitiveValue::from("Doctor^Anonymous"),
3185 ))
3186 );
3187 }
3188 {
3189 let mut obj = base_obj.clone();
3191 let op = AttributeOp::new(
3192 tags::REQUESTING_PHYSICIAN,
3193 AttributeAction::SetStr("Doctor^Anonymous".into()),
3194 );
3195
3196 obj.apply(op).unwrap();
3197
3198 assert_eq!(
3199 obj.get(tags::REQUESTING_PHYSICIAN),
3200 Some(&DataElement::new(
3201 tags::REQUESTING_PHYSICIAN,
3202 VR::PN,
3203 PrimitiveValue::from("Doctor^Anonymous"),
3204 ))
3205 );
3206 }
3207
3208 {
3209 let mut obj = base_obj.clone();
3211 let op = AttributeOp::new(
3212 tags::LOSSY_IMAGE_COMPRESSION_RATIO,
3213 AttributeAction::PushF64(1.25),
3214 );
3215
3216 obj.apply(op).unwrap();
3217
3218 assert_eq!(
3219 obj.get(tags::LOSSY_IMAGE_COMPRESSION_RATIO),
3220 Some(&DataElement::new(
3221 tags::LOSSY_IMAGE_COMPRESSION_RATIO,
3222 VR::DS,
3223 dicom_value!(Strs, ["5", "1.25"]),
3224 ))
3225 );
3226 }
3227 }
3228
3229 #[test]
3231 fn nested_inmem_ops() {
3232 let obj_1 = InMemDicomObject::from_element_iter([
3233 DataElement::new(Tag(0x0018, 0x6012), VR::US, PrimitiveValue::from(1_u16)),
3234 DataElement::new(Tag(0x0018, 0x6014), VR::US, PrimitiveValue::from(2_u16)),
3235 ]);
3236
3237 let obj_2 = InMemDicomObject::from_element_iter([DataElement::new(
3238 Tag(0x0018, 0x6012),
3239 VR::US,
3240 PrimitiveValue::from(4_u16),
3241 )]);
3242
3243 let mut main_obj = InMemDicomObject::from_element_iter(vec![
3244 DataElement::new(
3245 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3246 VR::SQ,
3247 DataSetSequence::from(vec![obj_1, obj_2]),
3248 ),
3249 DataElement::new(Tag(0x0020, 0x4000), VR::LT, Value::Primitive("TEST".into())),
3250 ]);
3251
3252 let selector: AttributeSelector =
3253 (tags::SEQUENCE_OF_ULTRASOUND_REGIONS, 0, Tag(0x0018, 0x6014)).into();
3254
3255 main_obj
3256 .apply(AttributeOp::new(selector, AttributeAction::Set(3.into())))
3257 .unwrap();
3258
3259 assert_eq!(
3260 main_obj
3261 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3262 .unwrap()
3263 .items()
3264 .unwrap()[0]
3265 .get(Tag(0x0018, 0x6014))
3266 .unwrap()
3267 .value(),
3268 &PrimitiveValue::from(3).into(),
3269 );
3270
3271 let selector: AttributeSelector =
3272 (tags::SEQUENCE_OF_ULTRASOUND_REGIONS, 1, Tag(0x0018, 0x6012)).into();
3273
3274 main_obj
3275 .apply(AttributeOp::new(selector, AttributeAction::Remove))
3276 .unwrap();
3277
3278 assert_eq!(
3280 main_obj
3281 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3282 .unwrap()
3283 .items()
3284 .unwrap()[1]
3285 .tags()
3286 .collect::<Vec<_>>(),
3287 Vec::<Tag>::new(),
3288 );
3289
3290 assert!(matches!(
3292 main_obj.value_at((tags::SEQUENCE_OF_ULTRASOUND_REGIONS, 1, Tag(0x0018, 0x6012),)),
3293 Err(AtAccessError::MissingLeafElement { .. })
3294 ))
3295 }
3296
3297 #[test]
3299 fn constructive_op() {
3300 let mut obj = InMemDicomObject::from_element_iter([DataElement::new(
3301 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3302 VR::SQ,
3303 DataSetSequence::empty(),
3304 )]);
3305
3306 let op = AttributeOp::new(
3307 (
3308 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3309 0,
3310 tags::REGION_SPATIAL_FORMAT,
3311 ),
3312 AttributeAction::Set(5_u16.into()),
3313 );
3314
3315 obj.apply(op).unwrap();
3316
3317 assert_eq!(
3319 obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3320 .unwrap()
3321 .items()
3322 .unwrap()
3323 .len(),
3324 1,
3325 );
3326
3327 assert_eq!(
3329 &obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3330 .unwrap()
3331 .items()
3332 .unwrap()[0],
3333 &InMemDicomObject::from_element_iter([DataElement::new(
3334 tags::REGION_SPATIAL_FORMAT,
3335 VR::US,
3336 PrimitiveValue::from(5_u16)
3337 )]),
3338 );
3339
3340 assert_eq!(
3342 obj.value_at((
3343 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3344 0,
3345 tags::REGION_SPATIAL_FORMAT
3346 ))
3347 .unwrap(),
3348 &Value::from(PrimitiveValue::from(5_u16)),
3349 )
3350 }
3351
3352 #[test]
3355 fn inmem_ops_can_create_seq() {
3356 let mut obj = InMemDicomObject::new_empty();
3357
3358 obj.apply(AttributeOp::new(
3359 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3360 AttributeAction::SetIfMissing(PrimitiveValue::Empty),
3361 ))
3362 .unwrap();
3363
3364 {
3365 let sequence_ultrasound = obj
3367 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3368 .expect("should have sequence element");
3369
3370 assert_eq!(sequence_ultrasound.vr(), VR::SQ);
3371
3372 assert_eq!(sequence_ultrasound.items().as_deref(), Some(&[][..]),);
3373 }
3374
3375 obj.apply(AttributeOp::new(
3376 (
3377 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3378 tags::REGION_SPATIAL_FORMAT,
3379 ),
3380 AttributeAction::Set(1_u16.into()),
3381 ))
3382 .unwrap();
3383
3384 {
3385 assert_eq!(
3387 obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3388 .unwrap()
3389 .items()
3390 .map(|items| items.len()),
3391 Some(1),
3392 );
3393 }
3394 }
3395
3396 #[test]
3399 fn inmem_ops_can_create_nested_attribute() {
3400 let mut obj = InMemDicomObject::new_empty();
3401
3402 obj.apply(AttributeOp::new(
3403 (
3404 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3405 tags::REGION_SPATIAL_FORMAT,
3406 ),
3407 AttributeAction::Set(1_u16.into()),
3408 ))
3409 .unwrap();
3410
3411 {
3412 assert_eq!(
3414 obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3415 .unwrap()
3416 .items()
3417 .map(|items| items.len()),
3418 Some(1),
3419 );
3420
3421 assert_eq!(
3423 obj.value_at((
3424 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3425 tags::REGION_SPATIAL_FORMAT
3426 ))
3427 .unwrap(),
3428 &PrimitiveValue::from(1_u16).into(),
3429 )
3430 }
3431 }
3432
3433 #[test]
3436 fn inmem_ops_can_truncate_seq() {
3437 let mut obj = InMemDicomObject::from_element_iter([
3438 DataElement::new(
3439 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3440 VR::SQ,
3441 DataSetSequence::from(vec![InMemDicomObject::new_empty()]),
3442 ),
3443 DataElement::new_with_len(
3444 tags::PIXEL_DATA,
3445 VR::OB,
3446 Length::UNDEFINED,
3447 PixelFragmentSequence::new(vec![], vec![vec![0xcc; 8192], vec![0x55; 1024]]),
3448 ),
3449 ]);
3450
3451 obj.apply(AttributeOp::new(
3453 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3454 AttributeAction::Truncate(0),
3455 ))
3456 .unwrap();
3457
3458 {
3459 let sequence_ultrasound = obj
3460 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3461 .expect("should have sequence element");
3462 assert_eq!(sequence_ultrasound.items().as_deref(), Some(&[][..]),);
3463 }
3464
3465 obj.apply(AttributeOp::new(
3467 tags::PIXEL_DATA,
3468 AttributeAction::Truncate(1),
3469 ))
3470 .unwrap();
3471
3472 {
3473 assert_eq!(
3475 obj.get(tags::PIXEL_DATA)
3476 .unwrap()
3477 .fragments()
3478 .map(|fragments| fragments.len()),
3479 Some(1),
3480 );
3481 }
3482 }
3483
3484 #[test]
3485 fn inmem_obj_reset_defined_length() {
3486 let mut entries: BTreeMap<Tag, InMemElement<StandardDataDictionary>> = BTreeMap::new();
3487
3488 let patient_name =
3489 DataElement::new(tags::PATIENT_NAME, VR::CS, PrimitiveValue::from("Doe^John"));
3490
3491 let study_description = DataElement::new(
3492 tags::STUDY_DESCRIPTION,
3493 VR::LO,
3494 PrimitiveValue::from("Test study"),
3495 );
3496
3497 entries.insert(tags::PATIENT_NAME, patient_name.clone());
3498
3499 let obj = InMemDicomObject::<StandardDataDictionary> {
3501 entries,
3502 dict: StandardDataDictionary,
3503 len: Length(1),
3504 charset_changed: false,
3505 };
3506
3507 assert!(obj.length().is_defined());
3508
3509 let mut o = obj.clone();
3510 o.put_element(study_description);
3511 assert!(o.length().is_undefined());
3512
3513 let mut o = obj.clone();
3514 o.remove_element(tags::PATIENT_NAME);
3515 assert!(o.length().is_undefined());
3516
3517 let mut o = obj.clone();
3518 o.remove_element_by_name("PatientName").unwrap();
3519 assert!(o.length().is_undefined());
3520
3521 let mut o = obj.clone();
3522 o.take_element(tags::PATIENT_NAME).unwrap();
3523 assert!(o.length().is_undefined());
3524
3525 let mut o = obj.clone();
3526 o.take_element_by_name("PatientName").unwrap();
3527 assert!(o.length().is_undefined());
3528
3529 let mut o = obj.clone();
3531 o.retain(|e| e.tag() == tags::PATIENT_NAME);
3532 assert!(o.length().is_undefined());
3533
3534 let mut o = obj.clone();
3535 o.apply(AttributeOp::new(
3536 tags::PATIENT_NAME,
3537 AttributeAction::Remove,
3538 ))
3539 .unwrap();
3540 assert!(o.length().is_undefined());
3541
3542 let mut o = obj.clone();
3543 o.apply(AttributeOp::new(tags::PATIENT_NAME, AttributeAction::Empty))
3544 .unwrap();
3545 assert!(o.length().is_undefined());
3546
3547 let mut o = obj.clone();
3548 o.apply(AttributeOp::new(
3549 tags::PATIENT_NAME,
3550 AttributeAction::SetVr(VR::IS),
3551 ))
3552 .unwrap();
3553 assert!(o.length().is_undefined());
3554
3555 let mut o = obj.clone();
3556 o.apply(AttributeOp::new(
3557 tags::PATIENT_NAME,
3558 AttributeAction::Set(dicom_value!(Str, "Unknown")),
3559 ))
3560 .unwrap();
3561 assert!(o.length().is_undefined());
3562
3563 let mut o = obj.clone();
3564 o.apply(AttributeOp::new(
3565 tags::PATIENT_NAME,
3566 AttributeAction::SetStr("Patient^Anonymous".into()),
3567 ))
3568 .unwrap();
3569 assert!(o.length().is_undefined());
3570
3571 let mut o = obj.clone();
3572 o.apply(AttributeOp::new(
3573 tags::PATIENT_AGE,
3574 AttributeAction::SetIfMissing(dicom_value!(75)),
3575 ))
3576 .unwrap();
3577 assert!(o.length().is_undefined());
3578
3579 let mut o = obj.clone();
3580 o.apply(AttributeOp::new(
3581 tags::PATIENT_ADDRESS,
3582 AttributeAction::SetStrIfMissing("Chicago".into()),
3583 ))
3584 .unwrap();
3585 assert!(o.length().is_undefined());
3586
3587 let mut o = obj.clone();
3588 o.apply(AttributeOp::new(
3589 tags::PATIENT_NAME,
3590 AttributeAction::Replace(dicom_value!(Str, "Unknown")),
3591 ))
3592 .unwrap();
3593 assert!(o.length().is_undefined());
3594
3595 let mut o = obj.clone();
3596 o.apply(AttributeOp::new(
3597 tags::PATIENT_NAME,
3598 AttributeAction::ReplaceStr("Unknown".into()),
3599 ))
3600 .unwrap();
3601 assert!(o.length().is_undefined());
3602
3603 let mut o = obj.clone();
3604 o.apply(AttributeOp::new(
3605 tags::PATIENT_NAME,
3606 AttributeAction::PushStr("^Prof".into()),
3607 ))
3608 .unwrap();
3609 assert!(o.length().is_undefined());
3610
3611 let mut o = obj.clone();
3612 o.apply(AttributeOp::new(
3613 tags::PATIENT_NAME,
3614 AttributeAction::PushI32(-16),
3615 ))
3616 .unwrap();
3617 assert!(o.length().is_undefined());
3618
3619 let mut o = obj.clone();
3620 o.apply(AttributeOp::new(
3621 tags::PATIENT_NAME,
3622 AttributeAction::PushU32(16),
3623 ))
3624 .unwrap();
3625 assert!(o.length().is_undefined());
3626
3627 let mut o = obj.clone();
3628 o.apply(AttributeOp::new(
3629 tags::PATIENT_NAME,
3630 AttributeAction::PushI16(-16),
3631 ))
3632 .unwrap();
3633 assert!(o.length().is_undefined());
3634
3635 let mut o = obj.clone();
3636 o.apply(AttributeOp::new(
3637 tags::PATIENT_NAME,
3638 AttributeAction::PushU16(16),
3639 ))
3640 .unwrap();
3641 assert!(o.length().is_undefined());
3642
3643 let mut o = obj.clone();
3644 o.apply(AttributeOp::new(
3645 tags::PATIENT_NAME,
3646 AttributeAction::PushF32(16.16),
3647 ))
3648 .unwrap();
3649 assert!(o.length().is_undefined());
3650
3651 let mut o = obj.clone();
3652 o.apply(AttributeOp::new(
3653 tags::PATIENT_NAME,
3654 AttributeAction::PushF64(16.1616),
3655 ))
3656 .unwrap();
3657 assert!(o.length().is_undefined());
3658 }
3659
3660 #[test]
3661 fn create_commands() {
3662 let obj = InMemDicomObject::command_from_element_iter([]);
3664 assert_eq!(
3665 obj.get(tags::COMMAND_GROUP_LENGTH)
3666 .map(|e| e.value().to_int::<u32>().unwrap()),
3667 Some(0)
3668 );
3669
3670 let obj = InMemDicomObject::command_from_element_iter([
3672 DataElement::new(
3674 tags::AFFECTED_SOP_CLASS_UID,
3675 VR::UI,
3676 PrimitiveValue::from("1.2.840.10008.5.1.4.1.2.1.1"),
3677 ),
3678 DataElement::new(
3680 tags::COMMAND_FIELD,
3681 VR::US,
3682 dicom_value!(U16, [0x0020]),
3684 ),
3685 DataElement::new(tags::MESSAGE_ID, VR::US, dicom_value!(U16, [0])),
3687 DataElement::new(
3689 tags::PRIORITY,
3690 VR::US,
3691 dicom_value!(U16, [0x0000]),
3693 ),
3694 DataElement::new(
3696 tags::COMMAND_DATA_SET_TYPE,
3697 VR::US,
3698 dicom_value!(U16, [0x0001]),
3699 ),
3700 ]);
3701 assert_eq!(
3702 obj.get(tags::COMMAND_GROUP_LENGTH)
3703 .map(|e| e.value().to_int::<u32>().unwrap()),
3704 Some(76)
3705 );
3706
3707 let storage_sop_class_uid = "1.2.840.10008.5.1.4.1.1.4";
3708 let storage_sop_instance_uid = "2.25.221314879990624101283043547144116927116";
3709
3710 let obj = InMemDicomObject::command_from_element_iter([
3712 DataElement::new(
3714 tags::COMMAND_GROUP_LENGTH,
3715 VR::UL,
3716 PrimitiveValue::from(9999_u32),
3717 ),
3718 DataElement::new(
3720 tags::AFFECTED_SOP_CLASS_UID,
3721 VR::UI,
3722 dicom_value!(Str, storage_sop_class_uid),
3723 ),
3724 DataElement::new(tags::COMMAND_FIELD, VR::US, dicom_value!(U16, [0x0001])),
3726 DataElement::new(tags::MESSAGE_ID, VR::US, dicom_value!(U16, [1])),
3728 DataElement::new(tags::PRIORITY, VR::US, dicom_value!(U16, [0x0000])),
3730 DataElement::new(
3732 tags::COMMAND_DATA_SET_TYPE,
3733 VR::US,
3734 dicom_value!(U16, [0x0000]),
3735 ),
3736 DataElement::new(
3738 tags::AFFECTED_SOP_INSTANCE_UID,
3739 VR::UI,
3740 dicom_value!(Str, storage_sop_instance_uid),
3741 ),
3742 ]);
3743
3744 assert_eq!(
3745 obj.get(tags::COMMAND_GROUP_LENGTH)
3746 .map(|e| e.value().to_int::<u32>().unwrap()),
3747 Some(126)
3748 );
3749 }
3750
3751 #[test]
3752 fn test_even_len() {
3753 assert_eq!(even_len(0), 0);
3754 assert_eq!(even_len(1), 2);
3755 assert_eq!(even_len(2), 2);
3756 assert_eq!(even_len(3), 4);
3757 assert_eq!(even_len(4), 4);
3758 assert_eq!(even_len(5), 6);
3759 }
3760
3761 #[test]
3762 fn can_update_value() {
3763 let mut obj = InMemDicomObject::from_element_iter([DataElement::new(
3764 tags::ANATOMIC_REGION_SEQUENCE,
3765 VR::SQ,
3766 DataSetSequence::empty(),
3767 )]);
3768 assert_eq!(
3769 obj.get(tags::ANATOMIC_REGION_SEQUENCE).map(|e| e.length()),
3770 Some(Length(0)),
3771 );
3772
3773 assert_eq!(
3774 obj.update_value(tags::BURNED_IN_ANNOTATION, |_value| {
3775 panic!("should not be called")
3776 }),
3777 false,
3778 );
3779
3780 let o = obj.update_value(tags::ANATOMIC_REGION_SEQUENCE, |value| {
3781 let items = value.items_mut().unwrap();
3783 items.push(InMemDicomObject::from_element_iter([DataElement::new(
3784 tags::INSTANCE_NUMBER,
3785 VR::IS,
3786 PrimitiveValue::from(1),
3787 )]));
3788 });
3789 assert_eq!(o, true);
3790
3791 assert!(obj
3792 .get(tags::ANATOMIC_REGION_SEQUENCE)
3793 .unwrap()
3794 .length()
3795 .is_undefined());
3796 }
3797
3798 #[test]
3799 fn deep_sequence_change_encoding_writes_undefined_sequence_length() {
3800 use smallvec::smallvec;
3801
3802 let obj_1 = InMemDicomObject::from_element_iter(vec![
3803 DataElement::new(
3805 tags::STUDY_DESCRIPTION,
3806 VR::SL,
3807 Value::Primitive("MORFOLOGÍA Y FUNCIÓN".into()),
3808 ),
3809 DataElement::new(
3811 tags::SERIES_DESCRIPTION,
3812 VR::SL,
3813 Value::Primitive("0123456789".into()),
3814 ),
3815 ]);
3816
3817 let some_tag = Tag(0x0018, 0x6011);
3818
3819 let inner_sequence = InMemDicomObject::from_element_iter(vec![DataElement::new(
3820 some_tag,
3821 VR::SQ,
3822 Value::from(DataSetSequence::new(
3823 smallvec![obj_1],
3824 Length(30), )),
3826 )]);
3827 let outer_sequence = DataElement::new(
3828 some_tag,
3829 VR::SQ,
3830 Value::from(DataSetSequence::new(
3831 smallvec![inner_sequence.clone(), inner_sequence],
3832 Length(60), )),
3834 );
3835
3836 let original_object = InMemDicomObject::from_element_iter(vec![
3837 DataElement::new(tags::SPECIFIC_CHARACTER_SET, VR::CS, "ISO_IR 100"),
3838 outer_sequence,
3839 ]);
3840
3841 assert_eq!(
3842 original_object
3843 .get(some_tag)
3844 .expect("object should be present")
3845 .length(),
3846 Length(60)
3847 );
3848
3849 let mut changed_charset = original_object.clone();
3850 changed_charset.convert_to_utf8();
3851 assert!(changed_charset.charset_changed);
3852
3853 use dicom_parser::dataset::DataToken as token;
3854 let options = IntoTokensOptions::new(true);
3855 let converted_tokens: Vec<_> = changed_charset.into_tokens_with_options(options).collect();
3856
3857 assert_eq!(
3858 vec![
3859 token::ElementHeader(DataElementHeader {
3860 tag: Tag(0x0008, 0x0005),
3861 vr: VR::CS,
3862 len: Length(10),
3863 }),
3864 token::PrimitiveValue("ISO_IR 192".into()),
3865 token::SequenceStart {
3866 tag: Tag(0x0018, 0x6011),
3867 len: Length::UNDEFINED,
3868 },
3869 token::ItemStart {
3870 len: Length::UNDEFINED
3871 },
3872 token::SequenceStart {
3873 tag: Tag(0x0018, 0x6011),
3874 len: Length::UNDEFINED,
3875 },
3876 token::ItemStart {
3877 len: Length::UNDEFINED
3878 },
3879 token::ElementHeader(DataElementHeader {
3880 tag: Tag(0x0008, 0x1030),
3881 vr: VR::SL,
3882 len: Length(22),
3883 }),
3884 token::PrimitiveValue("MORFOLOGÍA Y FUNCIÓN".into()),
3885 token::ElementHeader(DataElementHeader {
3886 tag: Tag(0x0008, 0x103E),
3887 vr: VR::SL,
3888 len: Length(10),
3889 }),
3890 token::PrimitiveValue("0123456789".into()),
3891 token::ItemEnd,
3892 token::SequenceEnd,
3893 token::ItemEnd,
3894 token::ItemStart {
3895 len: Length::UNDEFINED
3896 },
3897 token::SequenceStart {
3898 tag: Tag(0x0018, 0x6011),
3899 len: Length::UNDEFINED,
3900 },
3901 token::ItemStart {
3902 len: Length::UNDEFINED
3903 },
3904 token::ElementHeader(DataElementHeader {
3905 tag: Tag(0x0008, 0x1030),
3906 vr: VR::SL,
3907 len: Length(22),
3908 }),
3909 token::PrimitiveValue("MORFOLOGÍA Y FUNCIÓN".into()),
3910 token::ElementHeader(DataElementHeader {
3911 tag: Tag(0x0008, 0x103E),
3912 vr: VR::SL,
3913 len: Length(10),
3914 }),
3915 token::PrimitiveValue("0123456789".into()),
3916 token::ItemEnd,
3917 token::SequenceEnd,
3918 token::ItemEnd,
3919 token::SequenceEnd,
3920 ],
3921 converted_tokens
3922 );
3923 }
3924
3925 #[test]
3926 fn private_elements() {
3927 let mut ds = InMemDicomObject::from_element_iter(vec![
3928 DataElement::new(
3929 Tag(0x0009, 0x0010),
3930 VR::LO,
3931 PrimitiveValue::from("CREATOR 1"),
3932 ),
3933 DataElement::new(
3934 Tag(0x0009, 0x0011),
3935 VR::LO,
3936 PrimitiveValue::from("CREATOR 2"),
3937 ),
3938 DataElement::new(
3939 Tag(0x0011, 0x0010),
3940 VR::LO,
3941 PrimitiveValue::from("CREATOR 3"),
3942 ),
3943 ]);
3944 ds.put_private_element(
3945 0x0009,
3946 "CREATOR 1",
3947 0x01,
3948 VR::DS,
3949 PrimitiveValue::Str("1.0".to_string()),
3950 )
3951 .unwrap();
3952 ds.put_private_element(
3953 0x0009,
3954 "CREATOR 4",
3955 0x02,
3956 VR::DS,
3957 PrimitiveValue::Str("1.0".to_string()),
3958 )
3959 .unwrap();
3960
3961 let res = ds.put_private_element(
3962 0x0012,
3963 "CREATOR 4",
3964 0x02,
3965 VR::DS,
3966 PrimitiveValue::Str("1.0".to_string()),
3967 );
3968 assert_eq!(
3969 &res.err().unwrap().to_string(),
3970 "Group number must be odd, found 0x0012"
3971 );
3972
3973 assert_eq!(
3974 ds.private_element(0x0009, "CREATOR 1", 0x01)
3975 .unwrap()
3976 .value()
3977 .to_str()
3978 .unwrap(),
3979 "1.0"
3980 );
3981 assert_eq!(
3982 ds.private_element(0x0009, "CREATOR 4", 0x02)
3983 .unwrap()
3984 .value()
3985 .to_str()
3986 .unwrap(),
3987 "1.0"
3988 );
3989 assert_eq!(
3990 ds.private_element(0x0009, "CREATOR 4", 0x02)
3991 .unwrap()
3992 .header()
3993 .tag(),
3994 Tag(0x0009, 0x1202)
3995 );
3996 }
3997
3998 #[test]
3999 fn private_element_group_full() {
4000 let mut ds = InMemDicomObject::from_element_iter(
4001 (0..=0x00FFu16)
4002 .into_iter()
4003 .map(|i| {
4004 DataElement::new(Tag(0x0009, i), VR::LO, PrimitiveValue::from("CREATOR 1"))
4005 })
4006 .collect::<Vec<DataElement<_>>>(),
4007 );
4008 let res = ds.put_private_element(0x0009, "TEST", 0x01, VR::DS, PrimitiveValue::from("1.0"));
4009 assert_eq!(
4010 res.err().unwrap().to_string(),
4011 "No space available in group 0x0009"
4012 );
4013 }
4014}