1use dicom_core::ops::{
40 ApplyOp, AttributeAction, AttributeOp, AttributeSelector, AttributeSelectorStep,
41};
42use itertools::Itertools;
43use smallvec::SmallVec;
44use snafu::{ensure, OptionExt, ResultExt};
45use std::borrow::Cow;
46use std::fs::File;
47use std::io::{BufRead, BufReader, Read};
48use std::path::Path;
49use std::{collections::BTreeMap, io::Write};
50
51use crate::file::ReadPreamble;
52use crate::ops::{
53 ApplyError, ApplyResult, IncompatibleTypesSnafu, ModifySnafu, UnsupportedActionSnafu,
54};
55use crate::{meta::FileMetaTable, FileMetaTableBuilder};
56use crate::{
57 AccessByNameError, AccessError, AtAccessError, BuildMetaTableSnafu, CreateParserSnafu,
58 CreatePrinterSnafu, DicomObject, ElementNotFoundSnafu, FileDicomObject, InvalidGroupSnafu,
59 MissingElementValueSnafu, MissingLeafElementSnafu, NoSpaceSnafu, NoSuchAttributeNameSnafu,
60 NoSuchDataElementAliasSnafu, NoSuchDataElementTagSnafu, NotASequenceSnafu, OpenFileSnafu,
61 ParseMetaDataSetSnafu, ParseSopAttributeSnafu, PrematureEndSnafu, PrepareMetaTableSnafu,
62 PrintDataSetSnafu, PrivateCreatorNotFoundSnafu, PrivateElementError, ReadError, ReadFileSnafu,
63 ReadPreambleBytesSnafu, ReadTokenSnafu, ReadUnsupportedTransferSyntaxSnafu,
64 UnexpectedTokenSnafu, WithMetaError, WriteError,
65};
66use dicom_core::dictionary::{DataDictionary, DataDictionaryEntry};
67use dicom_core::header::{GroupNumber, HasLength, Header};
68use dicom_core::value::{DataSetSequence, PixelFragmentSequence, Value, ValueType, C};
69use dicom_core::{DataElement, Length, PrimitiveValue, Tag, VR};
70use dicom_dictionary_std::{tags, StandardDataDictionary};
71use dicom_encoding::transfer_syntax::TransferSyntaxIndex;
72use dicom_encoding::{encode::EncodeTo, text::SpecificCharacterSet, TransferSyntax};
73use dicom_parser::dataset::{DataSetReader, DataToken, IntoTokensOptions};
74use dicom_parser::{
75 dataset::{read::Error as ParserError, DataSetWriter, IntoTokens},
76 StatefulDecode,
77};
78use dicom_transfer_syntax_registry::TransferSyntaxRegistry;
79
80pub type InMemElement<D = StandardDataDictionary> = DataElement<InMemDicomObject<D>, InMemFragment>;
82
83pub type InMemFragment = dicom_core::value::InMemFragment;
85
86type Result<T, E = AccessError> = std::result::Result<T, E>;
87
88type ParserResult<T> = std::result::Result<T, ParserError>;
89
90#[derive(Debug, Clone)]
95pub struct InMemDicomObject<D = StandardDataDictionary> {
96 entries: BTreeMap<Tag, InMemElement<D>>,
98 dict: D,
100 len: Length,
104 pub(crate) charset_changed: bool,
108}
109
110impl<D> PartialEq for InMemDicomObject<D> {
111 fn eq(&self, other: &Self) -> bool {
113 self.entries == other.entries
114 }
115}
116
117impl<D> HasLength for InMemDicomObject<D> {
118 fn length(&self) -> Length {
119 self.len
120 }
121}
122
123impl<'s, D: 's> DicomObject for &'s InMemDicomObject<D>
124where
125 D: DataDictionary,
126 D: Clone,
127{
128 type Element = &'s InMemElement<D>;
129
130 fn element(&self, tag: Tag) -> Result<Self::Element> {
131 self.entries
132 .get(&tag)
133 .context(NoSuchDataElementTagSnafu { tag })
134 }
135
136 fn element_by_name(&self, name: &str) -> Result<Self::Element, AccessByNameError> {
137 let tag = self.lookup_name(name)?;
138 self.element(tag).map_err(|e| e.into_access_by_name(name))
139 }
140}
141
142impl FileDicomObject<InMemDicomObject<StandardDataDictionary>> {
143 pub fn open_file<P: AsRef<Path>>(path: P) -> Result<Self, ReadError> {
151 Self::open_file_with_dict(path, StandardDataDictionary)
152 }
153
154 pub fn from_reader<S>(src: S) -> Result<Self, ReadError>
162 where
163 S: Read,
164 {
165 Self::from_reader_with_dict(src, StandardDataDictionary)
166 }
167}
168
169impl InMemDicomObject<StandardDataDictionary> {
170 pub fn new_empty() -> Self {
172 InMemDicomObject {
173 entries: BTreeMap::new(),
174 dict: StandardDataDictionary,
175 len: Length::UNDEFINED,
176 charset_changed: false,
177 }
178 }
179
180 #[inline]
182 pub fn from_element_source<I>(iter: I) -> Result<Self>
183 where
184 I: IntoIterator<Item = Result<InMemElement<StandardDataDictionary>>>,
185 {
186 Self::from_element_source_with_dict(iter, StandardDataDictionary)
187 }
188
189 #[inline]
191 pub fn from_element_iter<I>(iter: I) -> Self
192 where
193 I: IntoIterator<Item = InMemElement<StandardDataDictionary>>,
194 {
195 Self::from_iter_with_dict(iter, StandardDataDictionary)
196 }
197
198 #[inline]
205 pub fn command_from_element_iter<I>(iter: I) -> Self
206 where
207 I: IntoIterator<Item = InMemElement<StandardDataDictionary>>,
208 {
209 Self::command_from_iter_with_dict(iter, StandardDataDictionary)
210 }
211
212 #[inline]
220 pub fn read_dataset<S>(decoder: S) -> Result<Self, ReadError>
221 where
222 S: StatefulDecode,
223 {
224 Self::read_dataset_with_dict(decoder, StandardDataDictionary)
225 }
226
227 #[inline]
233 pub fn read_dataset_with_ts_cs<S>(
234 from: S,
235 ts: &TransferSyntax,
236 cs: SpecificCharacterSet,
237 ) -> Result<Self, ReadError>
238 where
239 S: Read,
240 {
241 Self::read_dataset_with_dict_ts_cs(from, StandardDataDictionary, ts, cs)
242 }
243
244 #[inline]
251 pub fn read_dataset_with_ts<S>(from: S, ts: &TransferSyntax) -> Result<Self, ReadError>
252 where
253 S: Read,
254 {
255 Self::read_dataset_with_dict_ts_cs(
256 from,
257 StandardDataDictionary,
258 ts,
259 SpecificCharacterSet::default(),
260 )
261 }
262}
263
264impl<D> FileDicomObject<InMemDicomObject<D>>
265where
266 D: DataDictionary,
267 D: Clone,
268{
269 pub fn new_empty_with_dict_and_meta(dict: D, meta: FileMetaTable) -> Self {
272 FileDicomObject {
273 meta,
274 obj: InMemDicomObject {
275 entries: BTreeMap::new(),
276 dict,
277 len: Length::UNDEFINED,
278 charset_changed: false,
279 },
280 }
281 }
282
283 pub fn open_file_with_dict<P: AsRef<Path>>(path: P, dict: D) -> Result<Self, ReadError> {
291 Self::open_file_with(path, dict, TransferSyntaxRegistry)
292 }
293
294 pub fn open_file_with<P, R>(path: P, dict: D, ts_index: R) -> Result<Self, ReadError>
308 where
309 P: AsRef<Path>,
310 R: TransferSyntaxIndex,
311 {
312 Self::open_file_with_all_options(path, dict, ts_index, None, ReadPreamble::Auto)
313 }
314
315 fn detect_preamble<S>(reader: &mut BufReader<S>) -> std::io::Result<ReadPreamble>
318 where
319 S: Read,
320 {
321 let buf = reader.fill_buf()?;
322 let buflen = buf.len();
323
324 if buflen < 4 {
325 return Err(std::io::ErrorKind::UnexpectedEof.into());
326 }
327
328 if buflen >= 132 && &buf[128..132] == b"DICM" {
329 return Ok(ReadPreamble::Always);
330 }
331
332 if &buf[0..4] == b"DICM" {
333 return Ok(ReadPreamble::Never);
334 }
335
336 Ok(ReadPreamble::Auto)
338 }
339
340 pub(crate) fn open_file_with_all_options<P, R>(
341 path: P,
342 dict: D,
343 ts_index: R,
344 read_until: Option<Tag>,
345 mut read_preamble: ReadPreamble,
346 ) -> Result<Self, ReadError>
347 where
348 P: AsRef<Path>,
349 R: TransferSyntaxIndex,
350 {
351 let path = path.as_ref();
352 let mut file =
353 BufReader::new(File::open(path).with_context(|_| OpenFileSnafu { filename: path })?);
354
355 if read_preamble == ReadPreamble::Auto {
356 read_preamble = Self::detect_preamble(&mut file)
357 .with_context(|_| ReadFileSnafu { filename: path })?;
358 }
359
360 if read_preamble == ReadPreamble::Auto || read_preamble == ReadPreamble::Always {
361 let mut buf = [0u8; 128];
362 file.read_exact(&mut buf)
364 .with_context(|_| ReadFileSnafu { filename: path })?;
365 }
366
367 let mut meta = FileMetaTable::from_reader(&mut file).context(ParseMetaDataSetSnafu)?;
369
370 if let Some(ts) = ts_index.get(&meta.transfer_syntax) {
372 let mut dataset = DataSetReader::new_with_ts(file, ts).context(CreateParserSnafu)?;
373 let obj = InMemDicomObject::build_object(
374 &mut dataset,
375 dict,
376 false,
377 Length::UNDEFINED,
378 read_until,
379 )?;
380
381 if meta.media_storage_sop_class_uid().is_empty() {
383 if let Some(elem) = obj.get(tags::SOP_CLASS_UID) {
384 meta.media_storage_sop_class_uid = elem
385 .value()
386 .to_str()
387 .context(ParseSopAttributeSnafu)?
388 .to_string();
389 }
390 }
391
392 if meta.media_storage_sop_instance_uid().is_empty() {
394 if let Some(elem) = obj.get(tags::SOP_INSTANCE_UID) {
395 meta.media_storage_sop_instance_uid = elem
396 .value()
397 .to_str()
398 .context(ParseSopAttributeSnafu)?
399 .to_string();
400 }
401 }
402
403 Ok(FileDicomObject { meta, obj })
404 } else {
405 ReadUnsupportedTransferSyntaxSnafu {
406 uid: meta.transfer_syntax,
407 }
408 .fail()
409 }
410 }
411
412 pub fn from_reader_with_dict<S>(src: S, dict: D) -> Result<Self, ReadError>
420 where
421 S: Read,
422 {
423 Self::from_reader_with(src, dict, TransferSyntaxRegistry)
424 }
425
426 pub fn from_reader_with<'s, S, R>(src: S, dict: D, ts_index: R) -> Result<Self, ReadError>
440 where
441 S: Read + 's,
442 R: TransferSyntaxIndex,
443 {
444 Self::from_reader_with_all_options(src, dict, ts_index, None, ReadPreamble::Auto)
445 }
446
447 pub(crate) fn from_reader_with_all_options<'s, S, R>(
448 src: S,
449 dict: D,
450 ts_index: R,
451 read_until: Option<Tag>,
452 mut read_preamble: ReadPreamble,
453 ) -> Result<Self, ReadError>
454 where
455 S: Read + 's,
456 R: TransferSyntaxIndex,
457 {
458 let mut file = BufReader::new(src);
459
460 if read_preamble == ReadPreamble::Auto {
461 read_preamble = Self::detect_preamble(&mut file).context(ReadPreambleBytesSnafu)?;
462 }
463
464 if read_preamble == ReadPreamble::Always {
465 let mut buf = [0u8; 128];
467 file.read_exact(&mut buf).context(ReadPreambleBytesSnafu)?;
469 }
470
471 let meta = FileMetaTable::from_reader(&mut file).context(ParseMetaDataSetSnafu)?;
473
474 if let Some(ts) = ts_index.get(&meta.transfer_syntax) {
476 let mut dataset = DataSetReader::new_with_ts(file, ts).context(CreateParserSnafu)?;
477 let obj = InMemDicomObject::build_object(
478 &mut dataset,
479 dict,
480 false,
481 Length::UNDEFINED,
482 read_until,
483 )?;
484 Ok(FileDicomObject { meta, obj })
485 } else {
486 ReadUnsupportedTransferSyntaxSnafu {
487 uid: meta.transfer_syntax,
488 }
489 .fail()
490 }
491 }
492}
493
494impl FileDicomObject<InMemDicomObject<StandardDataDictionary>> {
495 pub fn new_empty_with_meta(meta: FileMetaTable) -> Self {
497 FileDicomObject {
498 meta,
499 obj: InMemDicomObject {
500 entries: BTreeMap::new(),
501 dict: StandardDataDictionary,
502 len: Length::UNDEFINED,
503 charset_changed: false,
504 },
505 }
506 }
507}
508
509impl<D> InMemDicomObject<D>
510where
511 D: DataDictionary,
512 D: Clone,
513{
514 pub fn new_empty_with_dict(dict: D) -> Self {
516 InMemDicomObject {
517 entries: BTreeMap::new(),
518 dict,
519 len: Length::UNDEFINED,
520 charset_changed: false,
521 }
522 }
523
524 pub fn from_element_source_with_dict<I>(iter: I, dict: D) -> Result<Self>
526 where
527 I: IntoIterator<Item = Result<InMemElement<D>>>,
528 {
529 let entries: Result<_> = iter.into_iter().map_ok(|e| (e.tag(), e)).collect();
530 Ok(InMemDicomObject {
531 entries: entries?,
532 dict,
533 len: Length::UNDEFINED,
534 charset_changed: false,
535 })
536 }
537
538 pub fn from_iter_with_dict<I>(iter: I, dict: D) -> Self
540 where
541 I: IntoIterator<Item = InMemElement<D>>,
542 {
543 let entries = iter.into_iter().map(|e| (e.tag(), e)).collect();
544 InMemDicomObject {
545 entries,
546 dict,
547 len: Length::UNDEFINED,
548 charset_changed: false,
549 }
550 }
551
552 pub fn command_from_iter_with_dict<I>(iter: I, dict: D) -> Self
559 where
560 I: IntoIterator<Item = InMemElement<D>>,
561 {
562 let mut calculated_length: u32 = 0;
563 let mut entries: BTreeMap<_, _> = iter
564 .into_iter()
565 .map(|e| {
566 if e.tag().0 == 0x0000 && e.tag().1 != 0x0000 {
568 let l = e.value().length();
569 calculated_length += if l.is_defined() { even_len(l.0) } else { 0 } + 8;
570 }
571
572 (e.tag(), e)
573 })
574 .collect();
575
576 entries.insert(
577 Tag(0, 0),
578 InMemElement::new(Tag(0, 0), VR::UL, PrimitiveValue::from(calculated_length)),
579 );
580
581 InMemDicomObject {
582 entries,
583 dict,
584 len: Length::UNDEFINED,
585 charset_changed: false,
586 }
587 }
588
589 pub fn read_dataset_with_dict<S>(decoder: S, dict: D) -> Result<Self, ReadError>
593 where
594 S: StatefulDecode,
595 D: DataDictionary,
596 {
597 let mut dataset = DataSetReader::new(decoder, Default::default());
598 InMemDicomObject::build_object(&mut dataset, dict, false, Length::UNDEFINED, None)
599 }
600
601 #[inline]
604 pub fn read_dataset_with_dict_ts<S>(
605 from: S,
606 dict: D,
607 ts: &TransferSyntax,
608 ) -> Result<Self, ReadError>
609 where
610 S: Read,
611 D: DataDictionary,
612 {
613 Self::read_dataset_with_dict_ts_cs(from, dict, ts, SpecificCharacterSet::default())
614 }
615
616 pub fn read_dataset_with_dict_ts_cs<S>(
624 from: S,
625 dict: D,
626 ts: &TransferSyntax,
627 cs: SpecificCharacterSet,
628 ) -> Result<Self, ReadError>
629 where
630 S: Read,
631 D: DataDictionary,
632 {
633 let from = BufReader::new(from);
634 let mut dataset = DataSetReader::new_with_ts_cs(from, ts, cs).context(CreateParserSnafu)?;
635 InMemDicomObject::build_object(&mut dataset, dict, false, Length::UNDEFINED, None)
636 }
637
638 pub fn element(&self, tag: Tag) -> Result<&InMemElement<D>> {
648 self.entries
649 .get(&tag)
650 .context(NoSuchDataElementTagSnafu { tag })
651 }
652
653 pub fn element_by_name(&self, name: &str) -> Result<&InMemElement<D>, AccessByNameError> {
665 let tag = self.lookup_name(name)?;
666 self.entries
667 .get(&tag)
668 .with_context(|| NoSuchDataElementAliasSnafu {
669 tag,
670 alias: name.to_string(),
671 })
672 }
673
674 pub fn element_opt(&self, tag: Tag) -> Result<Option<&InMemElement<D>>, AccessError> {
679 match self.element(tag) {
680 Ok(e) => Ok(Some(e)),
681 Err(super::AccessError::NoSuchDataElementTag { .. }) => Ok(None),
682 }
683 }
684
685 pub fn get(&self, tag: Tag) -> Option<&InMemElement<D>> {
690 self.entries.get(&tag)
691 }
692
693 fn get_mut(&mut self, tag: Tag) -> Option<&mut InMemElement<D>> {
698 self.entries.get_mut(&tag)
699 }
700
701 pub fn element_by_name_opt(
712 &self,
713 name: &str,
714 ) -> Result<Option<&InMemElement<D>>, AccessByNameError> {
715 match self.element_by_name(name) {
716 Ok(e) => Ok(Some(e)),
717 Err(AccessByNameError::NoSuchDataElementAlias { .. }) => Ok(None),
718 Err(e) => Err(e),
719 }
720 }
721
722 fn find_private_creator(&self, group: GroupNumber, creator: &str) -> Option<&Tag> {
723 let range = Tag(group, 0)..Tag(group, 0xFF);
724 for (tag, elem) in self.entries.range(range) {
725 if elem.header().vr() == VR::LO && elem.to_str().unwrap_or_default() == creator {
728 return Some(tag);
729 }
730 }
731 None
732 }
733
734 pub fn private_element(
767 &self,
768 group: GroupNumber,
769 creator: &str,
770 element: u8,
771 ) -> Result<&InMemElement<D>, PrivateElementError> {
772 let tag = self.find_private_creator(group, creator).ok_or_else(|| {
773 PrivateCreatorNotFoundSnafu {
774 group,
775 creator: creator.to_string(),
776 }
777 .build()
778 })?;
779
780 let element_num = (tag.element() << 8) | (element as u16);
781 self.get(Tag(group, element_num)).ok_or_else(|| {
782 ElementNotFoundSnafu {
783 group,
784 creator: creator.to_string(),
785 elem: element,
786 }
787 .build()
788 })
789 }
790
791 pub fn put(&mut self, elt: InMemElement<D>) -> Option<InMemElement<D>> {
796 self.put_element(elt)
797 }
798
799 pub fn put_element(&mut self, elt: InMemElement<D>) -> Option<InMemElement<D>> {
804 self.len = Length::UNDEFINED;
805 self.invalidate_if_charset_changed(elt.tag());
806 self.entries.insert(elt.tag(), elt)
807 }
808
809 pub fn put_private_element(
850 &mut self,
851 group: GroupNumber,
852 creator: &str,
853 element: u8,
854 vr: VR,
855 value: PrimitiveValue,
856 ) -> Result<Option<InMemElement<D>>, PrivateElementError> {
857 ensure!(group % 2 == 1, InvalidGroupSnafu { group });
858 let private_creator = self.find_private_creator(group, creator);
859 if let Some(tag) = private_creator {
860 let tag = Tag(group, tag.element() << 8 | (element as u16));
862 Ok(self.put_element(DataElement::new(tag, vr, value)))
863 } else {
864 let range = Tag(group, 0)..Tag(group, 0xFF);
866 let last_entry = self.entries.range(range).next_back();
867 let next_available = match last_entry {
868 Some((tag, _)) => tag.element() + 1,
869 None => 0x01,
870 };
871 if next_available < 0xFF {
872 let tag = Tag(group, next_available);
874 self.put_str(tag, VR::LO, creator);
875
876 let tag = Tag(group, next_available << 8 | (element as u16));
878 Ok(self.put_element(DataElement::new(tag, vr, value)))
879 } else {
880 NoSpaceSnafu { group }.fail()
881 }
882 }
883 }
884
885 pub fn put_str(
888 &mut self,
889 tag: Tag,
890 vr: VR,
891 string: impl Into<String>,
892 ) -> Option<InMemElement<D>> {
893 self.put_element(DataElement::new(tag, vr, string.into()))
894 }
895
896 pub fn remove_element(&mut self, tag: Tag) -> bool {
899 if self.entries.remove(&tag).is_some() {
900 self.len = Length::UNDEFINED;
901 true
902 } else {
903 false
904 }
905 }
906
907 pub fn remove_element_by_name(&mut self, name: &str) -> Result<bool, AccessByNameError> {
910 let tag = self.lookup_name(name)?;
911 Ok(self.entries.remove(&tag).is_some()).map(|removed| {
912 if removed {
913 self.len = Length::UNDEFINED;
914 }
915 removed
916 })
917 }
918
919 pub fn take_element(&mut self, tag: Tag) -> Result<InMemElement<D>> {
921 self.entries
922 .remove(&tag)
923 .map(|e| {
924 self.len = Length::UNDEFINED;
925 e
926 })
927 .context(NoSuchDataElementTagSnafu { tag })
928 }
929
930 pub fn take(&mut self, tag: Tag) -> Option<InMemElement<D>> {
934 self.entries.remove(&tag).map(|e| {
935 self.len = Length::UNDEFINED;
936 e
937 })
938 }
939
940 pub fn take_element_by_name(
942 &mut self,
943 name: &str,
944 ) -> Result<InMemElement<D>, AccessByNameError> {
945 let tag = self.lookup_name(name)?;
946 self.entries
947 .remove(&tag)
948 .map(|e| {
949 self.len = Length::UNDEFINED;
950 e
951 })
952 .with_context(|| NoSuchDataElementAliasSnafu {
953 tag,
954 alias: name.to_string(),
955 })
956 }
957
958 pub fn retain(&mut self, mut f: impl FnMut(&InMemElement<D>) -> bool) {
964 self.entries.retain(|_, elem| f(elem));
965 self.len = Length::UNDEFINED;
966 }
967
968 pub fn update_value(
996 &mut self,
997 tag: Tag,
998 f: impl FnMut(&mut Value<InMemDicomObject<D>, InMemFragment>),
999 ) -> bool {
1000 self.invalidate_if_charset_changed(tag);
1001 if let Some(e) = self.entries.get_mut(&tag) {
1002 e.update_value(f);
1003 self.len = Length::UNDEFINED;
1004 true
1005 } else {
1006 false
1007 }
1008 }
1009
1010 pub fn update_value_at(
1060 &mut self,
1061 selector: impl Into<AttributeSelector>,
1062 f: impl FnMut(&mut Value<InMemDicomObject<D>, InMemFragment>),
1063 ) -> Result<(), AtAccessError> {
1064 self.entry_at_mut(selector)
1065 .map(|e| e.update_value(f))
1066 .map(|_| {
1067 self.len = Length::UNDEFINED;
1068 })
1069 }
1070
1071 pub fn value_at(
1098 &self,
1099 selector: impl Into<AttributeSelector>,
1100 ) -> Result<&Value<InMemDicomObject<D>, InMemFragment>, AtAccessError> {
1101 let selector: AttributeSelector = selector.into();
1102
1103 let mut obj = self;
1104 for (i, step) in selector.iter().enumerate() {
1105 match step {
1106 AttributeSelectorStep::Tag(tag) => {
1108 return obj.get(*tag).map(|e| e.value()).with_context(|| {
1109 MissingLeafElementSnafu {
1110 selector: selector.clone(),
1111 }
1112 });
1113 }
1114 AttributeSelectorStep::Nested { tag, item } => {
1116 let e = obj
1117 .entries
1118 .get(tag)
1119 .with_context(|| crate::MissingSequenceSnafu {
1120 selector: selector.clone(),
1121 step_index: i as u32,
1122 })?;
1123
1124 let items = e.items().with_context(|| NotASequenceSnafu {
1126 selector: selector.clone(),
1127 step_index: i as u32,
1128 })?;
1129
1130 obj =
1132 items
1133 .get(*item as usize)
1134 .with_context(|| crate::MissingSequenceSnafu {
1135 selector: selector.clone(),
1136 step_index: i as u32,
1137 })?;
1138 }
1139 }
1140 }
1141
1142 unreachable!()
1143 }
1144
1145 pub fn convert_to_utf8(&mut self) {
1147 self.put(DataElement::new(
1148 tags::SPECIFIC_CHARACTER_SET,
1149 VR::CS,
1150 "ISO_IR 192",
1151 ));
1152 }
1153
1154 pub fn entry_at(
1163 &self,
1164 selector: impl Into<AttributeSelector>,
1165 ) -> Result<&InMemElement<D>, AtAccessError> {
1166 let selector: AttributeSelector = selector.into();
1167
1168 let mut obj = self;
1169 for (i, step) in selector.iter().enumerate() {
1170 match step {
1171 AttributeSelectorStep::Tag(tag) => {
1173 return obj.get(*tag).with_context(|| MissingLeafElementSnafu {
1174 selector: selector.clone(),
1175 })
1176 }
1177 AttributeSelectorStep::Nested { tag, item } => {
1179 let e = obj
1180 .entries
1181 .get(tag)
1182 .with_context(|| crate::MissingSequenceSnafu {
1183 selector: selector.clone(),
1184 step_index: i as u32,
1185 })?;
1186
1187 let items = e.items().with_context(|| NotASequenceSnafu {
1189 selector: selector.clone(),
1190 step_index: i as u32,
1191 })?;
1192
1193 obj =
1195 items
1196 .get(*item as usize)
1197 .with_context(|| crate::MissingSequenceSnafu {
1198 selector: selector.clone(),
1199 step_index: i as u32,
1200 })?;
1201 }
1202 }
1203 }
1204
1205 unreachable!()
1206 }
1207
1208 fn entry_at_mut(
1212 &mut self,
1213 selector: impl Into<AttributeSelector>,
1214 ) -> Result<&mut InMemElement<D>, AtAccessError> {
1215 let selector: AttributeSelector = selector.into();
1216
1217 let mut obj = self;
1218 for (i, step) in selector.iter().enumerate() {
1219 match step {
1220 AttributeSelectorStep::Tag(tag) => {
1222 return obj.get_mut(*tag).with_context(|| MissingLeafElementSnafu {
1223 selector: selector.clone(),
1224 })
1225 }
1226 AttributeSelectorStep::Nested { tag, item } => {
1228 let e =
1229 obj.entries
1230 .get_mut(tag)
1231 .with_context(|| crate::MissingSequenceSnafu {
1232 selector: selector.clone(),
1233 step_index: i as u32,
1234 })?;
1235
1236 let items = e.items_mut().with_context(|| NotASequenceSnafu {
1238 selector: selector.clone(),
1239 step_index: i as u32,
1240 })?;
1241
1242 obj = items.get_mut(*item as usize).with_context(|| {
1244 crate::MissingSequenceSnafu {
1245 selector: selector.clone(),
1246 step_index: i as u32,
1247 }
1248 })?;
1249 }
1250 }
1251 }
1252
1253 unreachable!()
1254 }
1255
1256 fn apply(&mut self, op: AttributeOp) -> ApplyResult {
1296 let AttributeOp { selector, action } = op;
1297 let dict = self.dict.clone();
1298
1299 let mut obj = self;
1300 for (i, step) in selector.iter().enumerate() {
1301 match step {
1302 AttributeSelectorStep::Tag(tag) => return obj.apply_leaf(*tag, action),
1304 AttributeSelectorStep::Nested { tag, item } => {
1306 let e =
1307 obj.entries
1308 .get_mut(tag)
1309 .ok_or_else(|| ApplyError::MissingSequence {
1310 selector: selector.clone(),
1311 step_index: i as u32,
1312 })?;
1313
1314 let items = e.items_mut().ok_or_else(|| ApplyError::NotASequence {
1316 selector: selector.clone(),
1317 step_index: i as u32,
1318 })?;
1319
1320 obj = if items.len() == *item as usize && action.is_constructive() {
1322 items.push(InMemDicomObject::new_empty_with_dict(dict.clone()));
1323 items.last_mut().unwrap()
1324 } else {
1325 items.get_mut(*item as usize).ok_or_else(|| {
1326 ApplyError::MissingSequence {
1327 selector: selector.clone(),
1328 step_index: i as u32,
1329 }
1330 })?
1331 };
1332 }
1333 }
1334 }
1335 unreachable!()
1336 }
1337
1338 fn apply_leaf(&mut self, tag: Tag, action: AttributeAction) -> ApplyResult {
1339 self.invalidate_if_charset_changed(tag);
1340 match action {
1341 AttributeAction::Remove => {
1342 self.remove_element(tag);
1343 Ok(())
1344 }
1345 AttributeAction::Empty => {
1346 if let Some(e) = self.entries.get_mut(&tag) {
1347 let vr = e.vr();
1348 *e = DataElement::empty(tag, vr);
1350 self.len = Length::UNDEFINED;
1351 }
1352 Ok(())
1353 }
1354 AttributeAction::SetVr(new_vr) => {
1355 if let Some(e) = self.entries.remove(&tag) {
1356 let (header, value) = e.into_parts();
1357 let e = DataElement::new(header.tag, new_vr, value);
1358 self.put(e);
1359 } else {
1360 self.put(DataElement::empty(tag, new_vr));
1361 }
1362 Ok(())
1363 }
1364 AttributeAction::Set(new_value) => {
1365 self.apply_change_value_impl(tag, new_value);
1366 Ok(())
1367 }
1368 AttributeAction::SetStr(string) => {
1369 let new_value = PrimitiveValue::from(&*string);
1370 self.apply_change_value_impl(tag, new_value);
1371 Ok(())
1372 }
1373 AttributeAction::SetIfMissing(new_value) => {
1374 if self.get(tag).is_none() {
1375 self.apply_change_value_impl(tag, new_value);
1376 }
1377 Ok(())
1378 }
1379 AttributeAction::SetStrIfMissing(string) => {
1380 if self.get(tag).is_none() {
1381 let new_value = PrimitiveValue::from(&*string);
1382 self.apply_change_value_impl(tag, new_value);
1383 }
1384 Ok(())
1385 }
1386 AttributeAction::Replace(new_value) => {
1387 if self.get(tag).is_some() {
1388 self.apply_change_value_impl(tag, new_value);
1389 }
1390 Ok(())
1391 }
1392 AttributeAction::ReplaceStr(string) => {
1393 if self.get(tag).is_some() {
1394 let new_value = PrimitiveValue::from(&*string);
1395 self.apply_change_value_impl(tag, new_value);
1396 }
1397 Ok(())
1398 }
1399 AttributeAction::PushStr(string) => self.apply_push_str_impl(tag, string),
1400 AttributeAction::PushI32(integer) => self.apply_push_i32_impl(tag, integer),
1401 AttributeAction::PushU32(integer) => self.apply_push_u32_impl(tag, integer),
1402 AttributeAction::PushI16(integer) => self.apply_push_i16_impl(tag, integer),
1403 AttributeAction::PushU16(integer) => self.apply_push_u16_impl(tag, integer),
1404 AttributeAction::PushF32(number) => self.apply_push_f32_impl(tag, number),
1405 AttributeAction::PushF64(number) => self.apply_push_f64_impl(tag, number),
1406 AttributeAction::Truncate(limit) => {
1407 self.update_value(tag, |value| value.truncate(limit));
1408 Ok(())
1409 }
1410 _ => UnsupportedActionSnafu.fail(),
1411 }
1412 }
1413
1414 fn apply_change_value_impl(&mut self, tag: Tag, new_value: PrimitiveValue) {
1415 self.invalidate_if_charset_changed(tag);
1416
1417 if let Some(e) = self.entries.get_mut(&tag) {
1418 let vr = e.vr();
1419 let new_value = if vr == VR::SQ && new_value.is_empty() {
1422 DataSetSequence::empty().into()
1423 } else {
1424 Value::from(new_value)
1425 };
1426 *e = DataElement::new(tag, vr, new_value);
1427 self.len = Length::UNDEFINED;
1428 } else {
1429 let vr = dicom_dictionary_std::StandardDataDictionary
1431 .by_tag(tag)
1432 .and_then(|entry| entry.vr().exact())
1433 .unwrap_or(VR::UN);
1434 let new_value = if vr == VR::SQ && new_value.is_empty() {
1439 DataSetSequence::empty().into()
1440 } else {
1441 Value::from(new_value)
1442 };
1443
1444 self.put(DataElement::new(tag, vr, new_value));
1445 }
1446 }
1447
1448 fn invalidate_if_charset_changed(&mut self, tag: Tag) {
1449 if tag == tags::SPECIFIC_CHARACTER_SET {
1450 self.charset_changed = true;
1451 }
1452 }
1453
1454 fn apply_push_str_impl(&mut self, tag: Tag, string: Cow<'static, str>) -> ApplyResult {
1455 if let Some(e) = self.entries.remove(&tag) {
1456 let (header, value) = e.into_parts();
1457 match value {
1458 Value::Primitive(mut v) => {
1459 self.invalidate_if_charset_changed(tag);
1460 v.extend_str([string]).context(ModifySnafu)?;
1462 self.put(DataElement::new(tag, header.vr, v));
1464 Ok(())
1465 }
1466
1467 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1468 kind: ValueType::PixelSequence,
1469 }
1470 .fail(),
1471 Value::Sequence(..) => IncompatibleTypesSnafu {
1472 kind: ValueType::DataSetSequence,
1473 }
1474 .fail(),
1475 }
1476 } else {
1477 let vr = dicom_dictionary_std::StandardDataDictionary
1479 .by_tag(tag)
1480 .and_then(|entry| entry.vr().exact())
1481 .unwrap_or(VR::UN);
1482 self.put(DataElement::new(tag, vr, PrimitiveValue::from(&*string)));
1484 Ok(())
1485 }
1486 }
1487
1488 fn apply_push_i32_impl(&mut self, tag: Tag, integer: i32) -> ApplyResult {
1489 if let Some(e) = self.entries.remove(&tag) {
1490 let (header, value) = e.into_parts();
1491 match value {
1492 Value::Primitive(mut v) => {
1493 v.extend_i32([integer]).context(ModifySnafu)?;
1495 self.put(DataElement::new(tag, header.vr, v));
1497 Ok(())
1498 }
1499
1500 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1501 kind: ValueType::PixelSequence,
1502 }
1503 .fail(),
1504 Value::Sequence(..) => IncompatibleTypesSnafu {
1505 kind: ValueType::DataSetSequence,
1506 }
1507 .fail(),
1508 }
1509 } else {
1510 let vr = dicom_dictionary_std::StandardDataDictionary
1512 .by_tag(tag)
1513 .and_then(|entry| entry.vr().exact())
1514 .unwrap_or(VR::SL);
1515 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1517 Ok(())
1518 }
1519 }
1520
1521 fn apply_push_u32_impl(&mut self, tag: Tag, integer: u32) -> ApplyResult {
1522 if let Some(e) = self.entries.remove(&tag) {
1523 let (header, value) = e.into_parts();
1524 match value {
1525 Value::Primitive(mut v) => {
1526 v.extend_u32([integer]).context(ModifySnafu)?;
1528 self.put(DataElement::new(tag, header.vr, v));
1530 Ok(())
1531 }
1532
1533 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1534 kind: ValueType::PixelSequence,
1535 }
1536 .fail(),
1537 Value::Sequence(..) => IncompatibleTypesSnafu {
1538 kind: ValueType::DataSetSequence,
1539 }
1540 .fail(),
1541 }
1542 } else {
1543 let vr = dicom_dictionary_std::StandardDataDictionary
1545 .by_tag(tag)
1546 .and_then(|entry| entry.vr().exact())
1547 .unwrap_or(VR::UL);
1548 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1550 Ok(())
1551 }
1552 }
1553
1554 fn apply_push_i16_impl(&mut self, tag: Tag, integer: i16) -> ApplyResult {
1555 if let Some(e) = self.entries.remove(&tag) {
1556 let (header, value) = e.into_parts();
1557 match value {
1558 Value::Primitive(mut v) => {
1559 v.extend_i16([integer]).context(ModifySnafu)?;
1561 self.put(DataElement::new(tag, header.vr, v));
1563 Ok(())
1564 }
1565
1566 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1567 kind: ValueType::PixelSequence,
1568 }
1569 .fail(),
1570 Value::Sequence(..) => IncompatibleTypesSnafu {
1571 kind: ValueType::DataSetSequence,
1572 }
1573 .fail(),
1574 }
1575 } else {
1576 let vr = dicom_dictionary_std::StandardDataDictionary
1578 .by_tag(tag)
1579 .and_then(|entry| entry.vr().exact())
1580 .unwrap_or(VR::SS);
1581 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1583 Ok(())
1584 }
1585 }
1586
1587 fn apply_push_u16_impl(&mut self, tag: Tag, integer: u16) -> ApplyResult {
1588 if let Some(e) = self.entries.remove(&tag) {
1589 let (header, value) = e.into_parts();
1590 match value {
1591 Value::Primitive(mut v) => {
1592 v.extend_u16([integer]).context(ModifySnafu)?;
1594 self.put(DataElement::new(tag, header.vr, v));
1596 Ok(())
1597 }
1598
1599 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1600 kind: ValueType::PixelSequence,
1601 }
1602 .fail(),
1603 Value::Sequence(..) => IncompatibleTypesSnafu {
1604 kind: ValueType::DataSetSequence,
1605 }
1606 .fail(),
1607 }
1608 } else {
1609 let vr = dicom_dictionary_std::StandardDataDictionary
1611 .by_tag(tag)
1612 .and_then(|entry| entry.vr().exact())
1613 .unwrap_or(VR::US);
1614 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1616 Ok(())
1617 }
1618 }
1619
1620 fn apply_push_f32_impl(&mut self, tag: Tag, number: f32) -> ApplyResult {
1621 if let Some(e) = self.entries.remove(&tag) {
1622 let (header, value) = e.into_parts();
1623 match value {
1624 Value::Primitive(mut v) => {
1625 v.extend_f32([number]).context(ModifySnafu)?;
1627 self.put(DataElement::new(tag, header.vr, v));
1629 Ok(())
1630 }
1631
1632 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1633 kind: ValueType::PixelSequence,
1634 }
1635 .fail(),
1636 Value::Sequence(..) => IncompatibleTypesSnafu {
1637 kind: ValueType::DataSetSequence,
1638 }
1639 .fail(),
1640 }
1641 } else {
1642 let vr = dicom_dictionary_std::StandardDataDictionary
1644 .by_tag(tag)
1645 .and_then(|entry| entry.vr().exact())
1646 .unwrap_or(VR::FL);
1647 self.put(DataElement::new(tag, vr, PrimitiveValue::from(number)));
1649 Ok(())
1650 }
1651 }
1652
1653 fn apply_push_f64_impl(&mut self, tag: Tag, number: f64) -> ApplyResult {
1654 if let Some(e) = self.entries.remove(&tag) {
1655 let (header, value) = e.into_parts();
1656 match value {
1657 Value::Primitive(mut v) => {
1658 v.extend_f64([number]).context(ModifySnafu)?;
1660 self.put(DataElement::new(tag, header.vr, v));
1662 Ok(())
1663 }
1664
1665 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1666 kind: ValueType::PixelSequence,
1667 }
1668 .fail(),
1669 Value::Sequence(..) => IncompatibleTypesSnafu {
1670 kind: ValueType::DataSetSequence,
1671 }
1672 .fail(),
1673 }
1674 } else {
1675 let vr = dicom_dictionary_std::StandardDataDictionary
1677 .by_tag(tag)
1678 .and_then(|entry| entry.vr().exact())
1679 .unwrap_or(VR::FD);
1680 self.put(DataElement::new(tag, vr, PrimitiveValue::from(number)));
1682 Ok(())
1683 }
1684 }
1685
1686 pub fn write_dataset<W, E>(&self, to: W, encoder: E) -> Result<(), WriteError>
1700 where
1701 W: Write,
1702 E: EncodeTo<W>,
1703 {
1704 let mut dset_writer = DataSetWriter::new(to, encoder);
1706 let required_options = IntoTokensOptions::new(self.charset_changed);
1707 dset_writer
1709 .write_sequence(self.into_tokens_with_options(required_options))
1710 .context(PrintDataSetSnafu)?;
1711
1712 Ok(())
1713 }
1714
1715 pub fn write_dataset_with_ts_cs<W>(
1723 &self,
1724 to: W,
1725 ts: &TransferSyntax,
1726 cs: SpecificCharacterSet,
1727 ) -> Result<(), WriteError>
1728 where
1729 W: Write,
1730 {
1731 let mut dset_writer = DataSetWriter::with_ts_cs(to, ts, cs).context(CreatePrinterSnafu)?;
1733 let required_options = IntoTokensOptions::new(self.charset_changed);
1734
1735 dset_writer
1737 .write_sequence(self.into_tokens_with_options(required_options))
1738 .context(PrintDataSetSnafu)?;
1739
1740 Ok(())
1741 }
1742
1743 pub fn write_dataset_with_ts<W>(&self, to: W, ts: &TransferSyntax) -> Result<(), WriteError>
1751 where
1752 W: Write,
1753 {
1754 self.write_dataset_with_ts_cs(to, ts, SpecificCharacterSet::default())
1755 }
1756
1757 pub fn with_exact_meta(self, meta: FileMetaTable) -> FileDicomObject<Self> {
1766 FileDicomObject { meta, obj: self }
1767 }
1768
1769 pub fn with_meta(
1802 self,
1803 mut meta: FileMetaTableBuilder,
1804 ) -> Result<FileDicomObject<Self>, WithMetaError> {
1805 if let Some(elem) = self.get(tags::SOP_INSTANCE_UID) {
1806 meta = meta.media_storage_sop_instance_uid(
1807 elem.value().to_str().context(PrepareMetaTableSnafu)?,
1808 );
1809 }
1810 if let Some(elem) = self.get(tags::SOP_CLASS_UID) {
1811 meta = meta
1812 .media_storage_sop_class_uid(elem.value().to_str().context(PrepareMetaTableSnafu)?);
1813 }
1814 Ok(FileDicomObject {
1815 meta: meta.build().context(BuildMetaTableSnafu)?,
1816 obj: self,
1817 })
1818 }
1819
1820 pub fn iter(&self) -> impl Iterator<Item = &InMemElement<D>> + '_ {
1822 self.into_iter()
1823 }
1824
1825 pub fn tags(&self) -> impl Iterator<Item = Tag> + '_ {
1827 self.entries.keys().copied()
1828 }
1829
1830 fn build_object<I>(
1834 dataset: &mut I,
1835 dict: D,
1836 in_item: bool,
1837 len: Length,
1838 read_until: Option<Tag>,
1839 ) -> Result<Self, ReadError>
1840 where
1841 I: ?Sized + Iterator<Item = ParserResult<DataToken>>,
1842 {
1843 let mut entries: BTreeMap<Tag, InMemElement<D>> = BTreeMap::new();
1844 while let Some(token) = dataset.next() {
1846 let elem = match token.context(ReadTokenSnafu)? {
1847 DataToken::PixelSequenceStart => {
1848 if read_until
1850 .map(|t| t <= Tag(0x7fe0, 0x0010))
1851 .unwrap_or(false)
1852 {
1853 break;
1854 }
1855 let value = InMemDicomObject::build_encapsulated_data(&mut *dataset)?;
1856 DataElement::new(Tag(0x7fe0, 0x0010), VR::OB, value)
1857 }
1858 DataToken::ElementHeader(header) => {
1859 if read_until.map(|t| t <= header.tag).unwrap_or(false) {
1861 break;
1862 }
1863
1864 let next_token = dataset.next().context(MissingElementValueSnafu)?;
1866 match next_token.context(ReadTokenSnafu)? {
1867 DataToken::PrimitiveValue(v) => InMemElement::new_with_len(
1868 header.tag,
1869 header.vr,
1870 header.len,
1871 Value::Primitive(v),
1872 ),
1873 token => {
1874 return UnexpectedTokenSnafu { token }.fail();
1875 }
1876 }
1877 }
1878 DataToken::SequenceStart { tag, len } => {
1879 if read_until.map(|t| t <= tag).unwrap_or(false) {
1881 break;
1882 }
1883
1884 let items = Self::build_sequence(tag, len, &mut *dataset, &dict)?;
1886 DataElement::new_with_len(
1887 tag,
1888 VR::SQ,
1889 len,
1890 Value::Sequence(DataSetSequence::new(items, len)),
1891 )
1892 }
1893 DataToken::ItemEnd if in_item => {
1894 return Ok(InMemDicomObject {
1896 entries,
1897 dict,
1898 len,
1899 charset_changed: false,
1900 });
1901 }
1902 token => return UnexpectedTokenSnafu { token }.fail(),
1903 };
1904 entries.insert(elem.tag(), elem);
1905 }
1906
1907 Ok(InMemDicomObject {
1908 entries,
1909 dict,
1910 len,
1911 charset_changed: false,
1912 })
1913 }
1914
1915 fn build_encapsulated_data<I>(
1918 dataset: I,
1919 ) -> Result<Value<InMemDicomObject<D>, InMemFragment>, ReadError>
1920 where
1921 I: Iterator<Item = ParserResult<DataToken>>,
1922 {
1923 let mut offset_table = None;
1932
1933 let mut fragments = C::new();
1934
1935 for token in dataset {
1936 match token.context(ReadTokenSnafu)? {
1937 DataToken::OffsetTable(table) => {
1938 offset_table = Some(table);
1939 }
1940 DataToken::ItemValue(data) => {
1941 fragments.push(data);
1942 }
1943 DataToken::ItemEnd => {
1944 if offset_table.is_none() {
1948 offset_table = Some(Vec::new())
1949 }
1950 }
1951 DataToken::ItemStart { len: _ } => { }
1952 DataToken::SequenceEnd => {
1953 break;
1955 }
1956 token @ DataToken::ElementHeader(_)
1958 | token @ DataToken::PixelSequenceStart
1959 | token @ DataToken::SequenceStart { .. }
1960 | token @ DataToken::PrimitiveValue(_) => {
1961 return UnexpectedTokenSnafu { token }.fail();
1962 }
1963 }
1964 }
1965
1966 Ok(Value::PixelSequence(PixelFragmentSequence::new(
1967 offset_table.unwrap_or_default(),
1968 fragments,
1969 )))
1970 }
1971
1972 fn build_sequence<I>(
1974 _tag: Tag,
1975 _len: Length,
1976 dataset: &mut I,
1977 dict: &D,
1978 ) -> Result<C<InMemDicomObject<D>>, ReadError>
1979 where
1980 I: ?Sized + Iterator<Item = ParserResult<DataToken>>,
1981 {
1982 let mut items: C<_> = SmallVec::new();
1983 while let Some(token) = dataset.next() {
1984 match token.context(ReadTokenSnafu)? {
1985 DataToken::ItemStart { len } => {
1986 items.push(Self::build_object(
1987 &mut *dataset,
1988 dict.clone(),
1989 true,
1990 len,
1991 None,
1992 )?);
1993 }
1994 DataToken::SequenceEnd => {
1995 return Ok(items);
1996 }
1997 token => return UnexpectedTokenSnafu { token }.fail(),
1998 };
1999 }
2000
2001 PrematureEndSnafu.fail()
2003 }
2004
2005 fn lookup_name(&self, name: &str) -> Result<Tag, AccessByNameError> {
2006 self.dict
2007 .by_name(name)
2008 .context(NoSuchAttributeNameSnafu { name })
2009 .map(|e| e.tag())
2010 }
2011}
2012
2013impl<D> ApplyOp for InMemDicomObject<D>
2014where
2015 D: DataDictionary,
2016 D: Clone,
2017{
2018 type Err = ApplyError;
2019
2020 #[inline]
2021 fn apply(&mut self, op: AttributeOp) -> ApplyResult {
2022 self.apply(op)
2023 }
2024}
2025
2026impl<'a, D> IntoIterator for &'a InMemDicomObject<D> {
2027 type Item = &'a InMemElement<D>;
2028 type IntoIter = ::std::collections::btree_map::Values<'a, Tag, InMemElement<D>>;
2029
2030 fn into_iter(self) -> Self::IntoIter {
2031 self.entries.values()
2032 }
2033}
2034
2035impl<D> IntoIterator for InMemDicomObject<D> {
2036 type Item = InMemElement<D>;
2037 type IntoIter = Iter<D>;
2038
2039 fn into_iter(self) -> Self::IntoIter {
2040 Iter {
2041 inner: self.entries.into_iter(),
2042 }
2043 }
2044}
2045
2046#[derive(Debug)]
2048pub struct Iter<D> {
2049 inner: ::std::collections::btree_map::IntoIter<Tag, InMemElement<D>>,
2050}
2051
2052impl<D> Iterator for Iter<D> {
2053 type Item = InMemElement<D>;
2054
2055 fn next(&mut self) -> Option<Self::Item> {
2056 self.inner.next().map(|x| x.1)
2057 }
2058
2059 fn size_hint(&self) -> (usize, Option<usize>) {
2060 self.inner.size_hint()
2061 }
2062
2063 fn count(self) -> usize {
2064 self.inner.count()
2065 }
2066}
2067
2068impl<D> Extend<InMemElement<D>> for InMemDicomObject<D> {
2069 fn extend<I>(&mut self, iter: I)
2070 where
2071 I: IntoIterator<Item = InMemElement<D>>,
2072 {
2073 self.len = Length::UNDEFINED;
2074 self.entries.extend(iter.into_iter().map(|e| (e.tag(), e)))
2075 }
2076}
2077
2078fn even_len(l: u32) -> u32 {
2079 (l + 1) & !1
2080}
2081
2082#[cfg(test)]
2083mod tests {
2084 use super::*;
2085 use crate::open_file;
2086 use byteordered::Endianness;
2087 use dicom_core::chrono::FixedOffset;
2088 use dicom_core::value::{DicomDate, DicomDateTime, DicomTime};
2089 use dicom_core::{dicom_value, header::DataElementHeader};
2090 use dicom_encoding::{
2091 decode::{basic::BasicDecoder, implicit_le::ImplicitVRLittleEndianDecoder},
2092 encode::{implicit_le::ImplicitVRLittleEndianEncoder, EncoderFor},
2093 };
2094 use dicom_parser::StatefulDecoder;
2095
2096 fn assert_obj_eq<D>(obj1: &InMemDicomObject<D>, obj2: &InMemDicomObject<D>)
2097 where
2098 D: std::fmt::Debug,
2099 {
2100 assert_eq!(format!("{:?}", obj1), format!("{:?}", obj2))
2103 }
2104
2105 #[test]
2106 fn inmem_object_compare() {
2107 let mut obj1 = InMemDicomObject::new_empty();
2108 let mut obj2 = InMemDicomObject::new_empty();
2109 assert_eq!(obj1, obj2);
2110 let empty_patient_name = DataElement::empty(Tag(0x0010, 0x0010), VR::PN);
2111 obj1.put(empty_patient_name.clone());
2112 assert_ne!(obj1, obj2);
2113 obj2.put(empty_patient_name.clone());
2114 assert_obj_eq(&obj1, &obj2);
2115 }
2116
2117 #[test]
2118 fn inmem_object_read_dataset() {
2119 let data_in = [
2120 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2123 ];
2124
2125 let decoder = ImplicitVRLittleEndianDecoder::default();
2126 let text = SpecificCharacterSet::default();
2127 let mut cursor = &data_in[..];
2128 let parser = StatefulDecoder::new(
2129 &mut cursor,
2130 decoder,
2131 BasicDecoder::new(Endianness::Little),
2132 text,
2133 );
2134
2135 let obj = InMemDicomObject::read_dataset(parser).unwrap();
2136
2137 let mut gt = InMemDicomObject::new_empty();
2138
2139 let patient_name = DataElement::new(
2140 Tag(0x0010, 0x0010),
2141 VR::PN,
2142 dicom_value!(Strs, ["Doe^John"]),
2143 );
2144 gt.put(patient_name);
2145
2146 assert_eq!(obj, gt);
2147 }
2148
2149 #[test]
2150 fn inmem_object_read_dataset_with_ts_cs() {
2151 let data_in = [
2152 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2155 ];
2156
2157 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2").unwrap();
2158 let cs = SpecificCharacterSet::default();
2159 let mut cursor = &data_in[..];
2160
2161 let obj = InMemDicomObject::read_dataset_with_dict_ts_cs(
2162 &mut cursor,
2163 StandardDataDictionary,
2164 &ts,
2165 cs,
2166 )
2167 .unwrap();
2168
2169 let mut gt = InMemDicomObject::new_empty();
2170
2171 let patient_name = DataElement::new(
2172 Tag(0x0010, 0x0010),
2173 VR::PN,
2174 dicom_value!(Strs, ["Doe^John"]),
2175 );
2176 gt.put(patient_name);
2177
2178 assert_eq!(obj, gt);
2179 }
2180
2181 #[test]
2184 fn inmem_object_read_dataset_saves_len() {
2185 let data_in = [
2186 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',
2191 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,
2195 b'o', b' ',
2196 ];
2197
2198 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2").unwrap();
2199 let mut cursor = &data_in[..];
2200
2201 let obj =
2202 InMemDicomObject::read_dataset_with_dict_ts(&mut cursor, StandardDataDictionary, &ts)
2203 .unwrap();
2204
2205 let physician_name = obj.element(Tag(0x0008, 0x0090)).unwrap();
2206 assert_eq!(physician_name.header().len, Length(12));
2207 assert_eq!(physician_name.value().to_str().unwrap(), "Simões^João");
2208 }
2209
2210 #[test]
2211 fn inmem_object_write_dataset() {
2212 let mut obj = InMemDicomObject::new_empty();
2213
2214 let patient_name =
2215 DataElement::new(Tag(0x0010, 0x0010), VR::PN, dicom_value!(Str, "Doe^John"));
2216 obj.put(patient_name);
2217
2218 let mut out = Vec::new();
2219
2220 let printer = EncoderFor::new(ImplicitVRLittleEndianEncoder::default());
2221
2222 obj.write_dataset(&mut out, printer).unwrap();
2223
2224 assert_eq!(
2225 out,
2226 &[
2227 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2230 ][..],
2231 );
2232 }
2233
2234 #[test]
2235 fn inmem_object_write_dataset_with_ts() {
2236 let mut obj = InMemDicomObject::new_empty();
2237
2238 let patient_name =
2239 DataElement::new(Tag(0x0010, 0x0010), VR::PN, dicom_value!(Str, "Doe^John"));
2240 obj.put(patient_name);
2241
2242 let mut out = Vec::new();
2243
2244 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2.1").unwrap();
2245
2246 obj.write_dataset_with_ts(&mut out, &ts).unwrap();
2247
2248 assert_eq!(
2249 out,
2250 &[
2251 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',
2255 ][..],
2256 );
2257 }
2258
2259 #[test]
2260 fn inmem_object_write_dataset_with_ts_cs() {
2261 let mut obj = InMemDicomObject::new_empty();
2262
2263 let patient_name =
2264 DataElement::new(Tag(0x0010, 0x0010), VR::PN, dicom_value!(Str, "Doe^John"));
2265 obj.put(patient_name);
2266
2267 let mut out = Vec::new();
2268
2269 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2").unwrap();
2270 let cs = SpecificCharacterSet::default();
2271
2272 obj.write_dataset_with_ts_cs(&mut out, &ts, cs).unwrap();
2273
2274 assert_eq!(
2275 out,
2276 &[
2277 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2280 ][..],
2281 );
2282 }
2283
2284 #[test]
2287 fn inmem_object_write_datetime_odd() {
2288 let mut obj = InMemDicomObject::new_empty();
2289
2290 let instance_number =
2292 DataElement::new(Tag(0x0020, 0x0013), VR::IS, PrimitiveValue::from(1_i32));
2293 obj.put(instance_number);
2294
2295 let dt = DicomDateTime::from_date_and_time_with_time_zone(
2297 DicomDate::from_ymd(2022, 11, 22).unwrap(),
2298 DicomTime::from_hms(18, 09, 35).unwrap(),
2299 FixedOffset::east_opt(3600).unwrap(),
2300 )
2301 .unwrap();
2302 let instance_coercion_date_time =
2303 DataElement::new(Tag(0x0008, 0x0015), VR::DT, dicom_value!(DateTime, dt));
2304 obj.put(instance_coercion_date_time);
2305
2306 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2.1").unwrap();
2308
2309 let mut out = Vec::new();
2310 obj.write_dataset_with_ts(&mut out, &ts)
2311 .expect("should write DICOM data without errors");
2312
2313 assert_eq!(
2314 out,
2315 &[
2316 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' ' ][..],
2330 );
2331 }
2332
2333 #[test]
2336 fn inmem_write_to_file_with_meta() {
2337 let sop_uid = "1.4.645.212121";
2338 let mut obj = InMemDicomObject::new_empty();
2339
2340 obj.put(DataElement::new(
2341 Tag(0x0010, 0x0010),
2342 VR::PN,
2343 dicom_value!(Strs, ["Doe^John"]),
2344 ));
2345 obj.put(DataElement::new(
2346 Tag(0x0008, 0x0060),
2347 VR::CS,
2348 dicom_value!(Strs, ["CR"]),
2349 ));
2350 obj.put(DataElement::new(
2351 Tag(0x0008, 0x0018),
2352 VR::UI,
2353 dicom_value!(Strs, [sop_uid]),
2354 ));
2355
2356 let file_object = obj
2357 .with_meta(
2358 FileMetaTableBuilder::default()
2359 .transfer_syntax("1.2.840.10008.1.2.1")
2361 .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.1")
2363 .media_storage_sop_instance_uid(sop_uid),
2364 )
2365 .unwrap();
2366
2367 let dir = tempfile::tempdir().unwrap();
2369 let mut file_path = dir.into_path();
2370 file_path.push(format!("{}.dcm", sop_uid));
2371
2372 file_object.write_to_file(&file_path).unwrap();
2373
2374 let saved_object = open_file(file_path).unwrap();
2376 assert_eq!(file_object, saved_object);
2377 }
2378
2379 #[test]
2382 fn inmem_with_meta_infers_sop_instance_uid() {
2383 let sop_uid = "1.4.645.252521";
2384 let mut obj = InMemDicomObject::new_empty();
2385
2386 obj.put(DataElement::new(
2387 tags::SOP_INSTANCE_UID,
2388 VR::UI,
2389 PrimitiveValue::from(sop_uid),
2390 ));
2391
2392 let file_object = obj
2393 .with_meta(
2394 FileMetaTableBuilder::default()
2396 .transfer_syntax("1.2.840.10008.1.2.1")
2398 .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.1"),
2400 )
2401 .unwrap();
2402
2403 let meta = file_object.meta();
2404
2405 assert_eq!(
2406 meta.media_storage_sop_instance_uid
2407 .trim_end_matches(|c| c == '\0'),
2408 sop_uid.trim_end_matches(|c| c == '\0'),
2409 );
2410 }
2411
2412 #[test]
2414 fn inmem_write_to_file_with_exact_meta() {
2415 let sop_uid = "1.4.645.212121";
2416 let mut obj = InMemDicomObject::new_empty();
2417
2418 obj.put(DataElement::new(
2419 Tag(0x0010, 0x0010),
2420 VR::PN,
2421 dicom_value!(Strs, ["Doe^John"]),
2422 ));
2423 obj.put(DataElement::new(
2424 Tag(0x0008, 0x0060),
2425 VR::CS,
2426 dicom_value!(Strs, ["CR"]),
2427 ));
2428 obj.put(DataElement::new(
2429 Tag(0x0008, 0x0018),
2430 VR::UI,
2431 dicom_value!(Strs, [sop_uid]),
2432 ));
2433
2434 let file_object = obj.with_exact_meta(
2435 FileMetaTableBuilder::default()
2436 .transfer_syntax("1.2.840.10008.1.2.1")
2438 .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.1")
2440 .media_storage_sop_instance_uid(sop_uid)
2441 .build()
2442 .unwrap(),
2443 );
2444
2445 let dir = tempfile::tempdir().unwrap();
2447 let mut file_path = dir.into_path();
2448 file_path.push(format!("{}.dcm", sop_uid));
2449
2450 file_object.write_to_file(&file_path).unwrap();
2451
2452 let saved_object = open_file(file_path).unwrap();
2454 assert_eq!(file_object, saved_object);
2455 }
2456
2457 #[test]
2458 fn inmem_object_get() {
2459 let another_patient_name = DataElement::new(
2460 Tag(0x0010, 0x0010),
2461 VR::PN,
2462 PrimitiveValue::Str("Doe^John".to_string()),
2463 );
2464 let mut obj = InMemDicomObject::new_empty();
2465 obj.put(another_patient_name.clone());
2466 let elem1 = (&obj).element(Tag(0x0010, 0x0010)).unwrap();
2467 assert_eq!(elem1, &another_patient_name);
2468 }
2469
2470 #[test]
2471 fn infer_media_sop_from_dataset_sop_elements() {
2472 let sop_instance_uid = "1.4.645.313131";
2473 let sop_class_uid = "1.2.840.10008.5.1.4.1.1.2";
2474 let mut obj = InMemDicomObject::new_empty();
2475
2476 obj.put(DataElement::new(
2477 Tag(0x0008, 0x0018),
2478 VR::UI,
2479 dicom_value!(Strs, [sop_instance_uid]),
2480 ));
2481 obj.put(DataElement::new(
2482 Tag(0x0008, 0x0016),
2483 VR::UI,
2484 dicom_value!(Strs, [sop_class_uid]),
2485 ));
2486
2487 let file_object = obj.with_exact_meta(
2488 FileMetaTableBuilder::default()
2489 .transfer_syntax("1.2.840.10008.1.2.1")
2490 .media_storage_sop_class_uid("")
2492 .media_storage_sop_instance_uid("")
2493 .build()
2494 .unwrap(),
2495 );
2496
2497 let dir = tempfile::tempdir().unwrap();
2499 let mut file_path = dir.into_path();
2500 file_path.push(format!("{}.dcm", sop_instance_uid));
2501
2502 file_object.write_to_file(&file_path).unwrap();
2503
2504 let saved_object = open_file(file_path).unwrap();
2506
2507 assert_eq!(
2509 saved_object.meta().media_storage_sop_instance_uid(),
2510 sop_instance_uid
2511 );
2512 assert_eq!(
2513 saved_object.meta().media_storage_sop_class_uid(),
2514 sop_class_uid
2515 );
2516 }
2517
2518 #[test]
2519 fn inmem_object_get_opt() {
2520 let another_patient_name = DataElement::new(
2521 Tag(0x0010, 0x0010),
2522 VR::PN,
2523 PrimitiveValue::Str("Doe^John".to_string()),
2524 );
2525 let mut obj = InMemDicomObject::new_empty();
2526 obj.put(another_patient_name.clone());
2527 let elem1 = obj.element_opt(Tag(0x0010, 0x0010)).unwrap();
2528 assert_eq!(elem1, Some(&another_patient_name));
2529
2530 assert_eq!(obj.element_opt(Tag(0x0010, 0x0020)).unwrap(), None);
2532 }
2533
2534 #[test]
2535 fn inmem_object_get_by_name() {
2536 let another_patient_name = DataElement::new(
2537 Tag(0x0010, 0x0010),
2538 VR::PN,
2539 PrimitiveValue::Str("Doe^John".to_string()),
2540 );
2541 let mut obj = InMemDicomObject::new_empty();
2542 obj.put(another_patient_name.clone());
2543 let elem1 = (&obj).element_by_name("PatientName").unwrap();
2544 assert_eq!(elem1, &another_patient_name);
2545 }
2546
2547 #[test]
2548 fn inmem_object_get_by_name_opt() {
2549 let another_patient_name = DataElement::new(
2550 Tag(0x0010, 0x0010),
2551 VR::PN,
2552 PrimitiveValue::Str("Doe^John".to_string()),
2553 );
2554 let mut obj = InMemDicomObject::new_empty();
2555 obj.put(another_patient_name.clone());
2556 let elem1 = obj.element_by_name_opt("PatientName").unwrap();
2557 assert_eq!(elem1, Some(&another_patient_name));
2558
2559 assert_eq!(obj.element_by_name_opt("PatientID").unwrap(), None);
2561 }
2562
2563 #[test]
2564 fn inmem_object_take_element() {
2565 let another_patient_name = DataElement::new(
2566 Tag(0x0010, 0x0010),
2567 VR::PN,
2568 PrimitiveValue::Str("Doe^John".to_string()),
2569 );
2570 let mut obj = InMemDicomObject::new_empty();
2571 obj.put(another_patient_name.clone());
2572 let elem1 = obj.take_element(Tag(0x0010, 0x0010)).unwrap();
2573 assert_eq!(elem1, another_patient_name);
2574 assert!(matches!(
2575 obj.take_element(Tag(0x0010, 0x0010)),
2576 Err(AccessError::NoSuchDataElementTag {
2577 tag: Tag(0x0010, 0x0010),
2578 ..
2579 })
2580 ));
2581 }
2582
2583 #[test]
2584 fn inmem_object_take_element_by_name() {
2585 let another_patient_name = DataElement::new(
2586 Tag(0x0010, 0x0010),
2587 VR::PN,
2588 PrimitiveValue::Str("Doe^John".to_string()),
2589 );
2590 let mut obj = InMemDicomObject::new_empty();
2591 obj.put(another_patient_name.clone());
2592 let elem1 = obj.take_element_by_name("PatientName").unwrap();
2593 assert_eq!(elem1, another_patient_name);
2594 assert!(matches!(
2595 obj.take_element_by_name("PatientName"),
2596 Err(AccessByNameError::NoSuchDataElementAlias {
2597 tag: Tag(0x0010, 0x0010),
2598 alias,
2599 ..
2600 }) if alias == "PatientName"));
2601 }
2602
2603 #[test]
2604 fn inmem_object_remove_element() {
2605 let another_patient_name = DataElement::new(
2606 Tag(0x0010, 0x0010),
2607 VR::PN,
2608 PrimitiveValue::Str("Doe^John".to_string()),
2609 );
2610 let mut obj = InMemDicomObject::new_empty();
2611 obj.put(another_patient_name.clone());
2612 assert!(obj.remove_element(Tag(0x0010, 0x0010)));
2613 assert_eq!(obj.remove_element(Tag(0x0010, 0x0010)), false);
2614 }
2615
2616 #[test]
2617 fn inmem_object_remove_element_by_name() {
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 assert!(obj.remove_element_by_name("PatientName").unwrap());
2626 assert_eq!(obj.remove_element_by_name("PatientName").unwrap(), false);
2627 }
2628
2629 #[test]
2631 fn inmem_traverse_elements() {
2632 let sop_uid = "1.4.645.212121";
2633 let mut obj = InMemDicomObject::new_empty();
2634
2635 obj.put(DataElement::new(
2636 Tag(0x0010, 0x0010),
2637 VR::PN,
2638 dicom_value!(Strs, ["Doe^John"]),
2639 ));
2640 obj.put(DataElement::new(
2641 Tag(0x0008, 0x0060),
2642 VR::CS,
2643 dicom_value!(Strs, ["CR"]),
2644 ));
2645 obj.put(DataElement::new(
2646 Tag(0x0008, 0x0018),
2647 VR::UI,
2648 dicom_value!(Strs, [sop_uid]),
2649 ));
2650
2651 {
2652 let mut iter = obj.iter();
2653 assert_eq!(
2654 *iter.next().unwrap().header(),
2655 DataElementHeader::new(Tag(0x0008, 0x0018), VR::UI, Length(sop_uid.len() as u32)),
2656 );
2657 assert_eq!(
2658 *iter.next().unwrap().header(),
2659 DataElementHeader::new(Tag(0x0008, 0x0060), VR::CS, Length(2)),
2660 );
2661 assert_eq!(
2662 *iter.next().unwrap().header(),
2663 DataElementHeader::new(Tag(0x0010, 0x0010), VR::PN, Length(8)),
2664 );
2665 }
2666
2667 let tags: Vec<_> = obj.tags().collect();
2669 assert_eq!(
2670 tags,
2671 vec![
2672 Tag(0x0008, 0x0018),
2673 Tag(0x0008, 0x0060),
2674 Tag(0x0010, 0x0010),
2675 ]
2676 );
2677
2678 let mut iter = obj.into_iter();
2680 assert_eq!(
2681 iter.next(),
2682 Some(DataElement::new(
2683 Tag(0x0008, 0x0018),
2684 VR::UI,
2685 dicom_value!(Strs, [sop_uid]),
2686 )),
2687 );
2688 assert_eq!(
2689 iter.next(),
2690 Some(DataElement::new(
2691 Tag(0x0008, 0x0060),
2692 VR::CS,
2693 dicom_value!(Strs, ["CR"]),
2694 )),
2695 );
2696 assert_eq!(
2697 iter.next(),
2698 Some(DataElement::new(
2699 Tag(0x0010, 0x0010),
2700 VR::PN,
2701 PrimitiveValue::from("Doe^John"),
2702 )),
2703 );
2704 }
2705
2706 #[test]
2707 fn inmem_empty_object_into_tokens() {
2708 let obj = InMemDicomObject::new_empty();
2709 let tokens = obj.into_tokens();
2710 assert_eq!(tokens.count(), 0);
2711 }
2712
2713 #[test]
2714 fn inmem_shallow_object_from_tokens() {
2715 let tokens = vec![
2716 DataToken::ElementHeader(DataElementHeader {
2717 tag: Tag(0x0008, 0x0060),
2718 vr: VR::CS,
2719 len: Length(2),
2720 }),
2721 DataToken::PrimitiveValue(PrimitiveValue::Str("MG".to_owned())),
2722 DataToken::ElementHeader(DataElementHeader {
2723 tag: Tag(0x0010, 0x0010),
2724 vr: VR::PN,
2725 len: Length(8),
2726 }),
2727 DataToken::PrimitiveValue(PrimitiveValue::Str("Doe^John".to_owned())),
2728 ];
2729
2730 let gt_obj = InMemDicomObject::from_element_iter(vec![
2731 DataElement::new(
2732 Tag(0x0010, 0x0010),
2733 VR::PN,
2734 PrimitiveValue::Str("Doe^John".to_string()),
2735 ),
2736 DataElement::new(
2737 Tag(0x0008, 0x0060),
2738 VR::CS,
2739 PrimitiveValue::Str("MG".to_string()),
2740 ),
2741 ]);
2742
2743 let obj = InMemDicomObject::build_object(
2744 &mut tokens.into_iter().map(Result::Ok),
2745 StandardDataDictionary,
2746 false,
2747 Length::UNDEFINED,
2748 None,
2749 )
2750 .unwrap();
2751
2752 assert_obj_eq(&obj, >_obj);
2753 }
2754
2755 #[test]
2756 fn inmem_shallow_object_into_tokens() {
2757 let patient_name = DataElement::new(
2758 Tag(0x0010, 0x0010),
2759 VR::PN,
2760 PrimitiveValue::Str("Doe^John".to_string()),
2761 );
2762 let modality = DataElement::new(
2763 Tag(0x0008, 0x0060),
2764 VR::CS,
2765 PrimitiveValue::Str("MG".to_string()),
2766 );
2767 let mut obj = InMemDicomObject::new_empty();
2768 obj.put(patient_name);
2769 obj.put(modality);
2770
2771 let tokens: Vec<_> = obj.into_tokens().collect();
2772
2773 assert_eq!(
2774 tokens,
2775 vec![
2776 DataToken::ElementHeader(DataElementHeader {
2777 tag: Tag(0x0008, 0x0060),
2778 vr: VR::CS,
2779 len: Length(2),
2780 }),
2781 DataToken::PrimitiveValue(PrimitiveValue::Str("MG".to_owned())),
2782 DataToken::ElementHeader(DataElementHeader {
2783 tag: Tag(0x0010, 0x0010),
2784 vr: VR::PN,
2785 len: Length(8),
2786 }),
2787 DataToken::PrimitiveValue(PrimitiveValue::Str("Doe^John".to_owned())),
2788 ]
2789 );
2790 }
2791
2792 #[test]
2793 fn inmem_deep_object_from_tokens() {
2794 use smallvec::smallvec;
2795
2796 let obj_1 = InMemDicomObject::from_element_iter(vec![
2797 DataElement::new(Tag(0x0018, 0x6012), VR::US, Value::Primitive(1_u16.into())),
2798 DataElement::new(Tag(0x0018, 0x6014), VR::US, Value::Primitive(2_u16.into())),
2799 ]);
2800
2801 let obj_2 = InMemDicomObject::from_element_iter(vec![DataElement::new(
2802 Tag(0x0018, 0x6012),
2803 VR::US,
2804 Value::Primitive(4_u16.into()),
2805 )]);
2806
2807 let gt_obj = InMemDicomObject::from_element_iter(vec![
2808 DataElement::new(
2809 Tag(0x0018, 0x6011),
2810 VR::SQ,
2811 Value::from(DataSetSequence::new(
2812 smallvec![obj_1, obj_2],
2813 Length::UNDEFINED,
2814 )),
2815 ),
2816 DataElement::new(Tag(0x0020, 0x4000), VR::LT, Value::Primitive("TEST".into())),
2817 ]);
2818
2819 let tokens: Vec<_> = vec![
2820 DataToken::SequenceStart {
2821 tag: Tag(0x0018, 0x6011),
2822 len: Length::UNDEFINED,
2823 },
2824 DataToken::ItemStart {
2825 len: Length::UNDEFINED,
2826 },
2827 DataToken::ElementHeader(DataElementHeader {
2828 tag: Tag(0x0018, 0x6012),
2829 vr: VR::US,
2830 len: Length(2),
2831 }),
2832 DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
2833 DataToken::ElementHeader(DataElementHeader {
2834 tag: Tag(0x0018, 0x6014),
2835 vr: VR::US,
2836 len: Length(2),
2837 }),
2838 DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
2839 DataToken::ItemEnd,
2840 DataToken::ItemStart {
2841 len: Length::UNDEFINED,
2842 },
2843 DataToken::ElementHeader(DataElementHeader {
2844 tag: Tag(0x0018, 0x6012),
2845 vr: VR::US,
2846 len: Length(2),
2847 }),
2848 DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
2849 DataToken::ItemEnd,
2850 DataToken::SequenceEnd,
2851 DataToken::ElementHeader(DataElementHeader {
2852 tag: Tag(0x0020, 0x4000),
2853 vr: VR::LT,
2854 len: Length(4),
2855 }),
2856 DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
2857 ];
2858
2859 let obj = InMemDicomObject::build_object(
2860 &mut tokens.into_iter().map(Result::Ok),
2861 StandardDataDictionary,
2862 false,
2863 Length::UNDEFINED,
2864 None,
2865 )
2866 .unwrap();
2867
2868 assert_obj_eq(&obj, >_obj);
2869 }
2870
2871 #[test]
2872 fn inmem_deep_object_into_tokens() {
2873 use smallvec::smallvec;
2874
2875 let obj_1 = InMemDicomObject::from_element_iter(vec![
2876 DataElement::new(Tag(0x0018, 0x6012), VR::US, Value::Primitive(1_u16.into())),
2877 DataElement::new(Tag(0x0018, 0x6014), VR::US, Value::Primitive(2_u16.into())),
2878 ]);
2879
2880 let obj_2 = InMemDicomObject::from_element_iter(vec![DataElement::new(
2881 Tag(0x0018, 0x6012),
2882 VR::US,
2883 Value::Primitive(4_u16.into()),
2884 )]);
2885
2886 let main_obj = InMemDicomObject::from_element_iter(vec![
2887 DataElement::new(
2888 Tag(0x0018, 0x6011),
2889 VR::SQ,
2890 Value::from(DataSetSequence::new(
2891 smallvec![obj_1, obj_2],
2892 Length::UNDEFINED,
2893 )),
2894 ),
2895 DataElement::new(Tag(0x0020, 0x4000), VR::LT, Value::Primitive("TEST".into())),
2896 ]);
2897
2898 let tokens: Vec<_> = main_obj.into_tokens().collect();
2899
2900 assert_eq!(
2901 tokens,
2902 vec![
2903 DataToken::SequenceStart {
2904 tag: Tag(0x0018, 0x6011),
2905 len: Length::UNDEFINED,
2906 },
2907 DataToken::ItemStart {
2908 len: Length::UNDEFINED,
2909 },
2910 DataToken::ElementHeader(DataElementHeader {
2911 tag: Tag(0x0018, 0x6012),
2912 vr: VR::US,
2913 len: Length(2),
2914 }),
2915 DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
2916 DataToken::ElementHeader(DataElementHeader {
2917 tag: Tag(0x0018, 0x6014),
2918 vr: VR::US,
2919 len: Length(2),
2920 }),
2921 DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
2922 DataToken::ItemEnd,
2923 DataToken::ItemStart {
2924 len: Length::UNDEFINED,
2925 },
2926 DataToken::ElementHeader(DataElementHeader {
2927 tag: Tag(0x0018, 0x6012),
2928 vr: VR::US,
2929 len: Length(2),
2930 }),
2931 DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
2932 DataToken::ItemEnd,
2933 DataToken::SequenceEnd,
2934 DataToken::ElementHeader(DataElementHeader {
2935 tag: Tag(0x0020, 0x4000),
2936 vr: VR::LT,
2937 len: Length(4),
2938 }),
2939 DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
2940 ]
2941 );
2942 }
2943
2944 #[test]
2945 fn inmem_encapsulated_pixel_data_from_tokens() {
2946 use smallvec::smallvec;
2947
2948 let gt_obj = InMemDicomObject::from_element_iter(vec![DataElement::new(
2949 Tag(0x7fe0, 0x0010),
2950 VR::OB,
2951 Value::from(PixelFragmentSequence::new_fragments(smallvec![vec![
2952 0x33;
2953 32
2954 ]])),
2955 )]);
2956
2957 let tokens: Vec<_> = vec![
2958 DataToken::PixelSequenceStart,
2959 DataToken::ItemStart { len: Length(0) },
2960 DataToken::ItemEnd,
2961 DataToken::ItemStart { len: Length(32) },
2962 DataToken::ItemValue(vec![0x33; 32]),
2963 DataToken::ItemEnd,
2964 DataToken::SequenceEnd,
2965 ];
2966
2967 let obj = InMemDicomObject::build_object(
2968 &mut tokens.into_iter().map(Result::Ok),
2969 StandardDataDictionary,
2970 false,
2971 Length::UNDEFINED,
2972 None,
2973 )
2974 .unwrap();
2975
2976 assert_obj_eq(&obj, >_obj);
2977 }
2978
2979 #[test]
2980 fn inmem_encapsulated_pixel_data_into_tokens() {
2981 use smallvec::smallvec;
2982
2983 let main_obj = InMemDicomObject::from_element_iter(vec![DataElement::new(
2984 Tag(0x7fe0, 0x0010),
2985 VR::OB,
2986 Value::from(PixelFragmentSequence::new_fragments(smallvec![vec![
2987 0x33;
2988 32
2989 ]])),
2990 )]);
2991
2992 let tokens: Vec<_> = main_obj.into_tokens().collect();
2993
2994 assert_eq!(
2995 tokens,
2996 vec![
2997 DataToken::PixelSequenceStart,
2998 DataToken::ItemStart { len: Length(0) },
2999 DataToken::ItemEnd,
3000 DataToken::ItemStart { len: Length(32) },
3001 DataToken::ItemValue(vec![0x33; 32]),
3002 DataToken::ItemEnd,
3003 DataToken::SequenceEnd,
3004 ]
3005 );
3006 }
3007
3008 #[test]
3010 fn inmem_ops() {
3011 let base_obj = InMemDicomObject::from_element_iter([
3013 DataElement::new(
3014 tags::SERIES_INSTANCE_UID,
3015 VR::UI,
3016 PrimitiveValue::from("2.25.137041794342168732369025909031346220736.1"),
3017 ),
3018 DataElement::new(
3019 tags::SERIES_INSTANCE_UID,
3020 VR::UI,
3021 PrimitiveValue::from("2.25.137041794342168732369025909031346220736.1"),
3022 ),
3023 DataElement::new(
3024 tags::SOP_INSTANCE_UID,
3025 VR::UI,
3026 PrimitiveValue::from("2.25.137041794342168732369025909031346220736.1.1"),
3027 ),
3028 DataElement::new(
3029 tags::STUDY_DESCRIPTION,
3030 VR::LO,
3031 PrimitiveValue::from("Test study"),
3032 ),
3033 DataElement::new(
3034 tags::INSTITUTION_NAME,
3035 VR::LO,
3036 PrimitiveValue::from("Test Hospital"),
3037 ),
3038 DataElement::new(tags::ROWS, VR::US, PrimitiveValue::from(768_u16)),
3039 DataElement::new(tags::COLUMNS, VR::US, PrimitiveValue::from(1024_u16)),
3040 DataElement::new(
3041 tags::LOSSY_IMAGE_COMPRESSION,
3042 VR::CS,
3043 PrimitiveValue::from("01"),
3044 ),
3045 DataElement::new(
3046 tags::LOSSY_IMAGE_COMPRESSION_RATIO,
3047 VR::DS,
3048 PrimitiveValue::from("5"),
3049 ),
3050 DataElement::new(
3051 tags::LOSSY_IMAGE_COMPRESSION_METHOD,
3052 VR::DS,
3053 PrimitiveValue::from("ISO_10918_1"),
3054 ),
3055 ]);
3056
3057 {
3058 let mut obj = base_obj.clone();
3060 let op = AttributeOp {
3061 selector: AttributeSelector::from(tags::STUDY_DESCRIPTION),
3062 action: AttributeAction::Remove,
3063 };
3064
3065 obj.apply(op).unwrap();
3066
3067 assert_eq!(obj.get(tags::STUDY_DESCRIPTION), None);
3068 }
3069 {
3070 let mut obj = base_obj.clone();
3071
3072 let op = AttributeOp {
3075 selector: tags::INSTITUTION_NAME.into(),
3076 action: AttributeAction::SetIfMissing("Nope Hospital".into()),
3077 };
3078
3079 obj.apply(op).unwrap();
3080
3081 assert_eq!(
3082 obj.get(tags::INSTITUTION_NAME),
3083 Some(&DataElement::new(
3084 tags::INSTITUTION_NAME,
3085 VR::LO,
3086 PrimitiveValue::from("Test Hospital"),
3087 ))
3088 );
3089
3090 let op = AttributeOp::new(
3092 tags::INSTITUTION_NAME,
3093 AttributeAction::ReplaceStr("REMOVED".into()),
3094 );
3095
3096 obj.apply(op).unwrap();
3097
3098 assert_eq!(
3099 obj.get(tags::INSTITUTION_NAME),
3100 Some(&DataElement::new(
3101 tags::INSTITUTION_NAME,
3102 VR::LO,
3103 PrimitiveValue::from("REMOVED"),
3104 ))
3105 );
3106
3107 let op = AttributeOp::new(
3110 tags::REQUESTING_PHYSICIAN,
3111 AttributeAction::ReplaceStr("Doctor^Anonymous".into()),
3112 );
3113
3114 obj.apply(op).unwrap();
3115
3116 assert_eq!(obj.get(tags::REQUESTING_PHYSICIAN), None);
3117
3118 let op = AttributeOp::new(
3120 tags::REQUESTING_PHYSICIAN,
3121 AttributeAction::SetStrIfMissing("Doctor^Anonymous".into()),
3122 );
3123
3124 obj.apply(op).unwrap();
3125
3126 assert_eq!(
3127 obj.get(tags::REQUESTING_PHYSICIAN),
3128 Some(&DataElement::new(
3129 tags::REQUESTING_PHYSICIAN,
3130 VR::PN,
3131 PrimitiveValue::from("Doctor^Anonymous"),
3132 ))
3133 );
3134 }
3135 {
3136 let mut obj = base_obj.clone();
3138 let op = AttributeOp::new(
3139 tags::REQUESTING_PHYSICIAN,
3140 AttributeAction::SetStr("Doctor^Anonymous".into()),
3141 );
3142
3143 obj.apply(op).unwrap();
3144
3145 assert_eq!(
3146 obj.get(tags::REQUESTING_PHYSICIAN),
3147 Some(&DataElement::new(
3148 tags::REQUESTING_PHYSICIAN,
3149 VR::PN,
3150 PrimitiveValue::from("Doctor^Anonymous"),
3151 ))
3152 );
3153 }
3154
3155 {
3156 let mut obj = base_obj.clone();
3158 let op = AttributeOp::new(
3159 tags::LOSSY_IMAGE_COMPRESSION_RATIO,
3160 AttributeAction::PushF64(1.25),
3161 );
3162
3163 obj.apply(op).unwrap();
3164
3165 assert_eq!(
3166 obj.get(tags::LOSSY_IMAGE_COMPRESSION_RATIO),
3167 Some(&DataElement::new(
3168 tags::LOSSY_IMAGE_COMPRESSION_RATIO,
3169 VR::DS,
3170 dicom_value!(Strs, ["5", "1.25"]),
3171 ))
3172 );
3173 }
3174 }
3175
3176 #[test]
3178 fn nested_inmem_ops() {
3179 let obj_1 = InMemDicomObject::from_element_iter([
3180 DataElement::new(Tag(0x0018, 0x6012), VR::US, PrimitiveValue::from(1_u16)),
3181 DataElement::new(Tag(0x0018, 0x6014), VR::US, PrimitiveValue::from(2_u16)),
3182 ]);
3183
3184 let obj_2 = InMemDicomObject::from_element_iter([DataElement::new(
3185 Tag(0x0018, 0x6012),
3186 VR::US,
3187 PrimitiveValue::from(4_u16),
3188 )]);
3189
3190 let mut main_obj = InMemDicomObject::from_element_iter(vec![
3191 DataElement::new(
3192 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3193 VR::SQ,
3194 DataSetSequence::from(vec![obj_1, obj_2]),
3195 ),
3196 DataElement::new(Tag(0x0020, 0x4000), VR::LT, Value::Primitive("TEST".into())),
3197 ]);
3198
3199 let selector: AttributeSelector =
3200 (tags::SEQUENCE_OF_ULTRASOUND_REGIONS, 0, Tag(0x0018, 0x6014)).into();
3201
3202 main_obj
3203 .apply(AttributeOp::new(selector, AttributeAction::Set(3.into())))
3204 .unwrap();
3205
3206 assert_eq!(
3207 main_obj
3208 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3209 .unwrap()
3210 .items()
3211 .unwrap()[0]
3212 .get(Tag(0x0018, 0x6014))
3213 .unwrap()
3214 .value(),
3215 &PrimitiveValue::from(3).into(),
3216 );
3217
3218 let selector: AttributeSelector =
3219 (tags::SEQUENCE_OF_ULTRASOUND_REGIONS, 1, Tag(0x0018, 0x6012)).into();
3220
3221 main_obj
3222 .apply(AttributeOp::new(selector, AttributeAction::Remove))
3223 .unwrap();
3224
3225 assert_eq!(
3227 main_obj
3228 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3229 .unwrap()
3230 .items()
3231 .unwrap()[1]
3232 .tags()
3233 .collect::<Vec<_>>(),
3234 Vec::<Tag>::new(),
3235 );
3236
3237 assert!(matches!(
3239 main_obj.value_at((tags::SEQUENCE_OF_ULTRASOUND_REGIONS, 1, Tag(0x0018, 0x6012),)),
3240 Err(AtAccessError::MissingLeafElement { .. })
3241 ))
3242 }
3243
3244 #[test]
3246 fn constructive_op() {
3247 let mut obj = InMemDicomObject::from_element_iter([DataElement::new(
3248 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3249 VR::SQ,
3250 DataSetSequence::empty(),
3251 )]);
3252
3253 let op = AttributeOp::new(
3254 (
3255 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3256 0,
3257 tags::REGION_SPATIAL_FORMAT,
3258 ),
3259 AttributeAction::Set(5_u16.into()),
3260 );
3261
3262 obj.apply(op).unwrap();
3263
3264 assert_eq!(
3266 obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3267 .unwrap()
3268 .items()
3269 .unwrap()
3270 .len(),
3271 1,
3272 );
3273
3274 assert_eq!(
3276 &obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3277 .unwrap()
3278 .items()
3279 .unwrap()[0],
3280 &InMemDicomObject::from_element_iter([DataElement::new(
3281 tags::REGION_SPATIAL_FORMAT,
3282 VR::US,
3283 PrimitiveValue::from(5_u16)
3284 )]),
3285 );
3286
3287 assert_eq!(
3289 obj.value_at((
3290 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3291 0,
3292 tags::REGION_SPATIAL_FORMAT
3293 ))
3294 .unwrap(),
3295 &Value::from(PrimitiveValue::from(5_u16)),
3296 )
3297 }
3298
3299 #[test]
3302 fn inmem_ops_can_create_seq() {
3303 let mut obj = InMemDicomObject::new_empty();
3304
3305 obj.apply(AttributeOp::new(
3306 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3307 AttributeAction::SetIfMissing(PrimitiveValue::Empty),
3308 ))
3309 .unwrap();
3310
3311 {
3312 let sequence_ultrasound = obj
3314 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3315 .expect("should have sequence element");
3316
3317 assert_eq!(sequence_ultrasound.vr(), VR::SQ);
3318
3319 assert_eq!(sequence_ultrasound.items().as_deref(), Some(&[][..]),);
3320 }
3321
3322 obj.apply(AttributeOp::new(
3323 (
3324 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3325 tags::REGION_SPATIAL_FORMAT,
3326 ),
3327 AttributeAction::Set(1_u16.into()),
3328 ))
3329 .unwrap();
3330
3331 {
3332 assert_eq!(
3334 obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3335 .unwrap()
3336 .items()
3337 .map(|items| items.len()),
3338 Some(1),
3339 );
3340 }
3341 }
3342
3343 #[test]
3346 fn inmem_ops_can_truncate_seq() {
3347 let mut obj = InMemDicomObject::from_element_iter([
3348 DataElement::new(
3349 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3350 VR::SQ,
3351 DataSetSequence::from(vec![InMemDicomObject::new_empty()]),
3352 ),
3353 DataElement::new_with_len(
3354 tags::PIXEL_DATA,
3355 VR::OB,
3356 Length::UNDEFINED,
3357 PixelFragmentSequence::new(vec![], vec![vec![0xcc; 8192], vec![0x55; 1024]]),
3358 ),
3359 ]);
3360
3361 obj.apply(AttributeOp::new(
3363 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3364 AttributeAction::Truncate(0),
3365 ))
3366 .unwrap();
3367
3368 {
3369 let sequence_ultrasound = obj
3370 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3371 .expect("should have sequence element");
3372 assert_eq!(sequence_ultrasound.items().as_deref(), Some(&[][..]),);
3373 }
3374
3375 obj.apply(AttributeOp::new(
3377 tags::PIXEL_DATA,
3378 AttributeAction::Truncate(1),
3379 ))
3380 .unwrap();
3381
3382 {
3383 assert_eq!(
3385 obj.get(tags::PIXEL_DATA)
3386 .unwrap()
3387 .fragments()
3388 .map(|fragments| fragments.len()),
3389 Some(1),
3390 );
3391 }
3392 }
3393
3394 #[test]
3395 fn inmem_obj_reset_defined_length() {
3396 let mut entries: BTreeMap<Tag, InMemElement<StandardDataDictionary>> = BTreeMap::new();
3397
3398 let patient_name =
3399 DataElement::new(tags::PATIENT_NAME, VR::CS, PrimitiveValue::from("Doe^John"));
3400
3401 let study_description = DataElement::new(
3402 tags::STUDY_DESCRIPTION,
3403 VR::LO,
3404 PrimitiveValue::from("Test study"),
3405 );
3406
3407 entries.insert(tags::PATIENT_NAME, patient_name.clone());
3408
3409 let obj = InMemDicomObject::<StandardDataDictionary> {
3411 entries,
3412 dict: StandardDataDictionary,
3413 len: Length(1),
3414 charset_changed: false,
3415 };
3416
3417 assert!(obj.length().is_defined());
3418
3419 let mut o = obj.clone();
3420 o.put_element(study_description);
3421 assert!(o.length().is_undefined());
3422
3423 let mut o = obj.clone();
3424 o.remove_element(tags::PATIENT_NAME);
3425 assert!(o.length().is_undefined());
3426
3427 let mut o = obj.clone();
3428 o.remove_element_by_name("PatientName").unwrap();
3429 assert!(o.length().is_undefined());
3430
3431 let mut o = obj.clone();
3432 o.take_element(tags::PATIENT_NAME).unwrap();
3433 assert!(o.length().is_undefined());
3434
3435 let mut o = obj.clone();
3436 o.take_element_by_name("PatientName").unwrap();
3437 assert!(o.length().is_undefined());
3438
3439 let mut o = obj.clone();
3441 o.retain(|e| e.tag() == tags::PATIENT_NAME);
3442 assert!(o.length().is_undefined());
3443
3444 let mut o = obj.clone();
3445 o.apply(AttributeOp::new(
3446 tags::PATIENT_NAME,
3447 AttributeAction::Remove,
3448 ))
3449 .unwrap();
3450 assert!(o.length().is_undefined());
3451
3452 let mut o = obj.clone();
3453 o.apply(AttributeOp::new(tags::PATIENT_NAME, AttributeAction::Empty))
3454 .unwrap();
3455 assert!(o.length().is_undefined());
3456
3457 let mut o = obj.clone();
3458 o.apply(AttributeOp::new(
3459 tags::PATIENT_NAME,
3460 AttributeAction::SetVr(VR::IS),
3461 ))
3462 .unwrap();
3463 assert!(o.length().is_undefined());
3464
3465 let mut o = obj.clone();
3466 o.apply(AttributeOp::new(
3467 tags::PATIENT_NAME,
3468 AttributeAction::Set(dicom_value!(Str, "Unknown")),
3469 ))
3470 .unwrap();
3471 assert!(o.length().is_undefined());
3472
3473 let mut o = obj.clone();
3474 o.apply(AttributeOp::new(
3475 tags::PATIENT_NAME,
3476 AttributeAction::SetStr("Patient^Anonymous".into()),
3477 ))
3478 .unwrap();
3479 assert!(o.length().is_undefined());
3480
3481 let mut o = obj.clone();
3482 o.apply(AttributeOp::new(
3483 tags::PATIENT_AGE,
3484 AttributeAction::SetIfMissing(dicom_value!(75)),
3485 ))
3486 .unwrap();
3487 assert!(o.length().is_undefined());
3488
3489 let mut o = obj.clone();
3490 o.apply(AttributeOp::new(
3491 tags::PATIENT_ADDRESS,
3492 AttributeAction::SetStrIfMissing("Chicago".into()),
3493 ))
3494 .unwrap();
3495 assert!(o.length().is_undefined());
3496
3497 let mut o = obj.clone();
3498 o.apply(AttributeOp::new(
3499 tags::PATIENT_NAME,
3500 AttributeAction::Replace(dicom_value!(Str, "Unknown")),
3501 ))
3502 .unwrap();
3503 assert!(o.length().is_undefined());
3504
3505 let mut o = obj.clone();
3506 o.apply(AttributeOp::new(
3507 tags::PATIENT_NAME,
3508 AttributeAction::ReplaceStr("Unknown".into()),
3509 ))
3510 .unwrap();
3511 assert!(o.length().is_undefined());
3512
3513 let mut o = obj.clone();
3514 o.apply(AttributeOp::new(
3515 tags::PATIENT_NAME,
3516 AttributeAction::PushStr("^Prof".into()),
3517 ))
3518 .unwrap();
3519 assert!(o.length().is_undefined());
3520
3521 let mut o = obj.clone();
3522 o.apply(AttributeOp::new(
3523 tags::PATIENT_NAME,
3524 AttributeAction::PushI32(-16),
3525 ))
3526 .unwrap();
3527 assert!(o.length().is_undefined());
3528
3529 let mut o = obj.clone();
3530 o.apply(AttributeOp::new(
3531 tags::PATIENT_NAME,
3532 AttributeAction::PushU32(16),
3533 ))
3534 .unwrap();
3535 assert!(o.length().is_undefined());
3536
3537 let mut o = obj.clone();
3538 o.apply(AttributeOp::new(
3539 tags::PATIENT_NAME,
3540 AttributeAction::PushI16(-16),
3541 ))
3542 .unwrap();
3543 assert!(o.length().is_undefined());
3544
3545 let mut o = obj.clone();
3546 o.apply(AttributeOp::new(
3547 tags::PATIENT_NAME,
3548 AttributeAction::PushU16(16),
3549 ))
3550 .unwrap();
3551 assert!(o.length().is_undefined());
3552
3553 let mut o = obj.clone();
3554 o.apply(AttributeOp::new(
3555 tags::PATIENT_NAME,
3556 AttributeAction::PushF32(16.16),
3557 ))
3558 .unwrap();
3559 assert!(o.length().is_undefined());
3560
3561 let mut o = obj.clone();
3562 o.apply(AttributeOp::new(
3563 tags::PATIENT_NAME,
3564 AttributeAction::PushF64(16.1616),
3565 ))
3566 .unwrap();
3567 assert!(o.length().is_undefined());
3568 }
3569
3570 #[test]
3571 fn create_commands() {
3572 let obj = InMemDicomObject::command_from_element_iter([]);
3574 assert_eq!(
3575 obj.get(tags::COMMAND_GROUP_LENGTH)
3576 .map(|e| e.value().to_int::<u32>().unwrap()),
3577 Some(0)
3578 );
3579
3580 let obj = InMemDicomObject::command_from_element_iter([
3582 DataElement::new(
3584 tags::AFFECTED_SOP_CLASS_UID,
3585 VR::UI,
3586 PrimitiveValue::from("1.2.840.10008.5.1.4.1.2.1.1"),
3587 ),
3588 DataElement::new(
3590 tags::COMMAND_FIELD,
3591 VR::US,
3592 dicom_value!(U16, [0x0020]),
3594 ),
3595 DataElement::new(tags::MESSAGE_ID, VR::US, dicom_value!(U16, [0])),
3597 DataElement::new(
3599 tags::PRIORITY,
3600 VR::US,
3601 dicom_value!(U16, [0x0000]),
3603 ),
3604 DataElement::new(
3606 tags::COMMAND_DATA_SET_TYPE,
3607 VR::US,
3608 dicom_value!(U16, [0x0001]),
3609 ),
3610 ]);
3611 assert_eq!(
3612 obj.get(tags::COMMAND_GROUP_LENGTH)
3613 .map(|e| e.value().to_int::<u32>().unwrap()),
3614 Some(76)
3615 );
3616
3617 let storage_sop_class_uid = "1.2.840.10008.5.1.4.1.1.4";
3618 let storage_sop_instance_uid = "2.25.221314879990624101283043547144116927116";
3619
3620 let obj = InMemDicomObject::command_from_element_iter([
3622 DataElement::new(
3624 tags::COMMAND_GROUP_LENGTH,
3625 VR::UL,
3626 PrimitiveValue::from(9999_u32),
3627 ),
3628 DataElement::new(
3630 tags::AFFECTED_SOP_CLASS_UID,
3631 VR::UI,
3632 dicom_value!(Str, storage_sop_class_uid),
3633 ),
3634 DataElement::new(tags::COMMAND_FIELD, VR::US, dicom_value!(U16, [0x0001])),
3636 DataElement::new(tags::MESSAGE_ID, VR::US, dicom_value!(U16, [1])),
3638 DataElement::new(tags::PRIORITY, VR::US, dicom_value!(U16, [0x0000])),
3640 DataElement::new(
3642 tags::COMMAND_DATA_SET_TYPE,
3643 VR::US,
3644 dicom_value!(U16, [0x0000]),
3645 ),
3646 DataElement::new(
3648 tags::AFFECTED_SOP_INSTANCE_UID,
3649 VR::UI,
3650 dicom_value!(Str, storage_sop_instance_uid),
3651 ),
3652 ]);
3653
3654 assert_eq!(
3655 obj.get(tags::COMMAND_GROUP_LENGTH)
3656 .map(|e| e.value().to_int::<u32>().unwrap()),
3657 Some(126)
3658 );
3659 }
3660
3661 #[test]
3662 fn test_even_len() {
3663 assert_eq!(even_len(0), 0);
3664 assert_eq!(even_len(1), 2);
3665 assert_eq!(even_len(2), 2);
3666 assert_eq!(even_len(3), 4);
3667 assert_eq!(even_len(4), 4);
3668 assert_eq!(even_len(5), 6);
3669 }
3670
3671 #[test]
3672 fn can_update_value() {
3673 let mut obj = InMemDicomObject::from_element_iter([DataElement::new(
3674 tags::ANATOMIC_REGION_SEQUENCE,
3675 VR::SQ,
3676 DataSetSequence::empty(),
3677 )]);
3678 assert_eq!(
3679 obj.get(tags::ANATOMIC_REGION_SEQUENCE).map(|e| e.length()),
3680 Some(Length(0)),
3681 );
3682
3683 assert_eq!(
3684 obj.update_value(tags::BURNED_IN_ANNOTATION, |_value| {
3685 panic!("should not be called")
3686 }),
3687 false,
3688 );
3689
3690 let o = obj.update_value(tags::ANATOMIC_REGION_SEQUENCE, |value| {
3691 let items = value.items_mut().unwrap();
3693 items.push(InMemDicomObject::from_element_iter([DataElement::new(
3694 tags::INSTANCE_NUMBER,
3695 VR::IS,
3696 PrimitiveValue::from(1),
3697 )]));
3698 });
3699 assert_eq!(o, true);
3700
3701 assert!(obj
3702 .get(tags::ANATOMIC_REGION_SEQUENCE)
3703 .unwrap()
3704 .length()
3705 .is_undefined());
3706 }
3707
3708 #[test]
3709 fn deep_sequence_change_encoding_writes_undefined_sequence_length() {
3710 use smallvec::smallvec;
3711
3712 let obj_1 = InMemDicomObject::from_element_iter(vec![
3713 DataElement::new(
3715 tags::STUDY_DESCRIPTION,
3716 VR::SL,
3717 Value::Primitive("MORFOLOGÍA Y FUNCIÓN".into()),
3718 ),
3719 DataElement::new(
3721 tags::SERIES_DESCRIPTION,
3722 VR::SL,
3723 Value::Primitive("0123456789".into()),
3724 ),
3725 ]);
3726
3727 let some_tag = Tag(0x0018, 0x6011);
3728
3729 let inner_sequence = InMemDicomObject::from_element_iter(vec![DataElement::new(
3730 some_tag,
3731 VR::SQ,
3732 Value::from(DataSetSequence::new(
3733 smallvec![obj_1],
3734 Length(30), )),
3736 )]);
3737 let outer_sequence = DataElement::new(
3738 some_tag,
3739 VR::SQ,
3740 Value::from(DataSetSequence::new(
3741 smallvec![inner_sequence.clone(), inner_sequence],
3742 Length(60), )),
3744 );
3745
3746 let original_object = InMemDicomObject::from_element_iter(vec![
3747 DataElement::new(tags::SPECIFIC_CHARACTER_SET, VR::CS, "ISO_IR 100"),
3748 outer_sequence,
3749 ]);
3750
3751 assert_eq!(
3752 original_object
3753 .get(some_tag)
3754 .expect("object should be present")
3755 .length(),
3756 Length(60)
3757 );
3758
3759 let mut changed_charset = original_object.clone();
3760 changed_charset.convert_to_utf8();
3761 assert!(changed_charset.charset_changed);
3762
3763 use dicom_parser::dataset::DataToken as token;
3764 let options = IntoTokensOptions::new(true);
3765 let converted_tokens: Vec<_> = changed_charset.into_tokens_with_options(options).collect();
3766
3767 assert_eq!(
3768 vec![
3769 token::ElementHeader(DataElementHeader {
3770 tag: Tag(0x0008, 0x0005),
3771 vr: VR::CS,
3772 len: Length(10),
3773 }),
3774 token::PrimitiveValue("ISO_IR 192".into()),
3775 token::SequenceStart {
3776 tag: Tag(0x0018, 0x6011),
3777 len: Length::UNDEFINED,
3778 },
3779 token::ItemStart {
3780 len: Length::UNDEFINED
3781 },
3782 token::SequenceStart {
3783 tag: Tag(0x0018, 0x6011),
3784 len: Length::UNDEFINED,
3785 },
3786 token::ItemStart {
3787 len: Length::UNDEFINED
3788 },
3789 token::ElementHeader(DataElementHeader {
3790 tag: Tag(0x0008, 0x1030),
3791 vr: VR::SL,
3792 len: Length(22),
3793 }),
3794 token::PrimitiveValue("MORFOLOGÍA Y FUNCIÓN".into()),
3795 token::ElementHeader(DataElementHeader {
3796 tag: Tag(0x0008, 0x103E),
3797 vr: VR::SL,
3798 len: Length(10),
3799 }),
3800 token::PrimitiveValue("0123456789".into()),
3801 token::ItemEnd,
3802 token::SequenceEnd,
3803 token::ItemEnd,
3804 token::ItemStart {
3805 len: Length::UNDEFINED
3806 },
3807 token::SequenceStart {
3808 tag: Tag(0x0018, 0x6011),
3809 len: Length::UNDEFINED,
3810 },
3811 token::ItemStart {
3812 len: Length::UNDEFINED
3813 },
3814 token::ElementHeader(DataElementHeader {
3815 tag: Tag(0x0008, 0x1030),
3816 vr: VR::SL,
3817 len: Length(22),
3818 }),
3819 token::PrimitiveValue("MORFOLOGÍA Y FUNCIÓN".into()),
3820 token::ElementHeader(DataElementHeader {
3821 tag: Tag(0x0008, 0x103E),
3822 vr: VR::SL,
3823 len: Length(10),
3824 }),
3825 token::PrimitiveValue("0123456789".into()),
3826 token::ItemEnd,
3827 token::SequenceEnd,
3828 token::ItemEnd,
3829 token::SequenceEnd,
3830 ],
3831 converted_tokens
3832 );
3833 }
3834
3835 #[test]
3836 fn private_elements() {
3837 let mut ds = InMemDicomObject::from_element_iter(vec![
3838 DataElement::new(
3839 Tag(0x0009, 0x0010),
3840 VR::LO,
3841 PrimitiveValue::from("CREATOR 1"),
3842 ),
3843 DataElement::new(
3844 Tag(0x0009, 0x0011),
3845 VR::LO,
3846 PrimitiveValue::from("CREATOR 2"),
3847 ),
3848 DataElement::new(
3849 Tag(0x0011, 0x0010),
3850 VR::LO,
3851 PrimitiveValue::from("CREATOR 3"),
3852 ),
3853 ]);
3854 ds.put_private_element(
3855 0x0009,
3856 "CREATOR 1",
3857 0x01,
3858 VR::DS,
3859 PrimitiveValue::Str("1.0".to_string()),
3860 )
3861 .unwrap();
3862 ds.put_private_element(
3863 0x0009,
3864 "CREATOR 4",
3865 0x02,
3866 VR::DS,
3867 PrimitiveValue::Str("1.0".to_string()),
3868 )
3869 .unwrap();
3870
3871 let res = ds.put_private_element(
3872 0x0012,
3873 "CREATOR 4",
3874 0x02,
3875 VR::DS,
3876 PrimitiveValue::Str("1.0".to_string()),
3877 );
3878 assert_eq!(
3879 &res.err().unwrap().to_string(),
3880 "Group number must be odd, found 0x0012"
3881 );
3882
3883 assert_eq!(
3884 ds.private_element(0x0009, "CREATOR 1", 0x01)
3885 .unwrap()
3886 .value()
3887 .to_str()
3888 .unwrap(),
3889 "1.0"
3890 );
3891 assert_eq!(
3892 ds.private_element(0x0009, "CREATOR 4", 0x02)
3893 .unwrap()
3894 .value()
3895 .to_str()
3896 .unwrap(),
3897 "1.0"
3898 );
3899 assert_eq!(
3900 ds.private_element(0x0009, "CREATOR 4", 0x02)
3901 .unwrap()
3902 .header()
3903 .tag(),
3904 Tag(0x0009, 0x1202)
3905 );
3906 }
3907
3908 #[test]
3909 fn private_element_group_full() {
3910 let mut ds = InMemDicomObject::from_element_iter(
3911 (0..=0x00FFu16)
3912 .into_iter()
3913 .map(|i| {
3914 DataElement::new(Tag(0x0009, i), VR::LO, PrimitiveValue::from("CREATOR 1"))
3915 })
3916 .collect::<Vec<DataElement<_>>>(),
3917 );
3918 let res = ds.put_private_element(0x0009, "TEST", 0x01, VR::DS, PrimitiveValue::from("1.0"));
3919 assert_eq!(
3920 res.err().unwrap().to_string(),
3921 "No space available in group 0x0009"
3922 );
3923 }
3924}