1use dicom_core::ops::{
40 ApplyOp, AttributeAction, AttributeOp, AttributeSelector, AttributeSelectorStep,
41};
42use dicom_encoding::Codec;
43use dicom_parser::dataset::read::{DataSetReaderOptions, OddLengthStrategy};
44use dicom_parser::dataset::write::DataSetWriterOptions;
45use dicom_parser::stateful::decode::CharacterSetOverride;
46use itertools::Itertools;
47use smallvec::SmallVec;
48use snafu::{OptionExt, ResultExt, ensure};
49use std::borrow::Cow;
50use std::fs::File;
51use std::io::{BufRead, BufReader, Read};
52use std::path::Path;
53use std::{collections::BTreeMap, io::Write};
54
55use crate::file::ReadPreamble;
56use crate::ops::{
57 ApplyError, ApplyResult, IncompatibleTypesSnafu, ModifySnafu, UnsupportedActionSnafu,
58};
59use crate::{
60 AccessByNameError, AccessError, AtAccessError, BuildMetaTableSnafu, CreateParserSnafu,
61 CreatePrinterSnafu, DicomObject, ElementNotFoundSnafu, FileDicomObject, InvalidGroupSnafu,
62 MissingElementValueSnafu, MissingLeafElementSnafu, NoSpaceSnafu, NoSuchAttributeNameSnafu,
63 NoSuchDataElementAliasSnafu, NoSuchDataElementTagSnafu, NotASequenceSnafu, OpenFileSnafu,
64 ParseMetaDataSetSnafu, ParseSopAttributeSnafu, PrematureEndSnafu, PrepareMetaTableSnafu,
65 PrintDataSetSnafu, PrivateCreatorNotFoundSnafu, PrivateElementError, ReadError, ReadFileSnafu,
66 ReadPreambleBytesSnafu, ReadTokenSnafu, ReadUnrecognizedTransferSyntaxSnafu,
67 ReadUnsupportedTransferSyntaxSnafu, ReadUnsupportedTransferSyntaxWithSuggestionSnafu,
68 UnexpectedTokenSnafu, WithMetaError, WriteError,
69};
70use crate::{FileMetaTableBuilder, meta::FileMetaTable};
71use dicom_core::dictionary::{DataDictionary, DataDictionaryEntry};
72use dicom_core::header::{GroupNumber, HasLength, Header};
73use dicom_core::value::{C, DataSetSequence, PixelFragmentSequence, Value, ValueType};
74use dicom_core::{DataElement, Length, PrimitiveValue, Tag, VR};
75use dicom_dictionary_std::{StandardDataDictionary, tags, uids};
76use dicom_encoding::transfer_syntax::TransferSyntaxIndex;
77use dicom_encoding::{TransferSyntax, encode::EncodeTo, text::SpecificCharacterSet};
78use dicom_parser::dataset::{DataSetReader, DataToken, IntoTokensOptions};
79use dicom_parser::{
80 StatefulDecode,
81 dataset::{DataSetWriter, IntoTokens, read::Error as ParserError},
82};
83use dicom_transfer_syntax_registry::TransferSyntaxRegistry;
84
85pub type InMemElement<D = StandardDataDictionary> = DataElement<InMemDicomObject<D>, InMemFragment>;
87
88pub type InMemFragment = dicom_core::value::InMemFragment;
90
91type Result<T, E = AccessError> = std::result::Result<T, E>;
92
93type ParserResult<T> = std::result::Result<T, ParserError>;
94
95#[derive(Debug, Clone)]
100pub struct InMemDicomObject<D = StandardDataDictionary> {
101 entries: BTreeMap<Tag, InMemElement<D>>,
103 dict: D,
105 len: Length,
109 pub(crate) charset_changed: bool,
113}
114
115impl<D> PartialEq for InMemDicomObject<D> {
116 fn eq(&self, other: &Self) -> bool {
118 self.entries == other.entries
119 }
120}
121
122impl<D> HasLength for InMemDicomObject<D> {
123 fn length(&self) -> Length {
124 self.len
125 }
126}
127
128impl<D> HasLength for &InMemDicomObject<D> {
129 fn length(&self) -> Length {
130 self.len
131 }
132}
133
134impl<D> DicomObject for InMemDicomObject<D>
135where
136 D: DataDictionary,
137 D: Clone,
138{
139 type Attribute<'a>
140 = &'a Value<InMemDicomObject<D>, InMemFragment>
141 where
142 Self: 'a;
143
144 type LeafAttribute<'a>
145 = &'a Value<InMemDicomObject<D>, InMemFragment>
146 where
147 Self: 'a;
148
149 #[inline]
150 fn attr_opt(&self, tag: Tag) -> Result<Option<Self::Attribute<'_>>> {
151 let elem = InMemDicomObject::element_opt(self, tag)?;
152 Ok(elem.map(|e| e.value()))
153 }
154
155 #[inline]
156 fn attr_by_name_opt(
157 &self,
158 name: &str,
159 ) -> Result<Option<Self::Attribute<'_>>, AccessByNameError> {
160 let elem = InMemDicomObject::element_by_name_opt(self, name)?;
161 Ok(elem.map(|e| e.value()))
162 }
163
164 #[inline]
165 fn attr(&self, tag: Tag) -> Result<Self::Attribute<'_>> {
166 let elem = InMemDicomObject::element(self, tag)?;
167 Ok(elem.value())
168 }
169
170 #[inline]
171 fn attr_by_name(&self, name: &str) -> Result<Self::Attribute<'_>, AccessByNameError> {
172 let elem = InMemDicomObject::element_by_name(self, name)?;
173 Ok(elem.value())
174 }
175
176 #[inline]
177 fn at(
178 &self,
179 selector: impl Into<AttributeSelector>,
180 ) -> Result<Self::LeafAttribute<'_>, AtAccessError> {
181 self.value_at(selector)
182 }
183}
184
185impl<'s, D: 's> DicomObject for &'s InMemDicomObject<D>
186where
187 D: DataDictionary,
188 D: Clone,
189{
190 type Attribute<'a>
191 = &'a Value<InMemDicomObject<D>, InMemFragment>
192 where
193 Self: 'a,
194 's: 'a;
195
196 type LeafAttribute<'a>
197 = &'a Value<InMemDicomObject<D>, InMemFragment>
198 where
199 Self: 'a,
200 's: 'a;
201
202 #[inline]
203 fn attr_opt(&self, tag: Tag) -> Result<Option<Self::Attribute<'_>>> {
204 let elem = InMemDicomObject::element_opt(*self, tag)?;
205 Ok(elem.map(|e| e.value()))
206 }
207
208 #[inline]
209 fn attr_by_name_opt(
210 &self,
211 name: &str,
212 ) -> Result<Option<Self::Attribute<'_>>, AccessByNameError> {
213 let elem = InMemDicomObject::element_by_name_opt(*self, name)?;
214 Ok(elem.map(|e| e.value()))
215 }
216
217 #[inline]
218 fn attr(&self, tag: Tag) -> Result<Self::Attribute<'_>> {
219 let elem = InMemDicomObject::element(*self, tag)?;
220 Ok(elem.value())
221 }
222
223 #[inline]
224 fn attr_by_name(&self, name: &str) -> Result<Self::Attribute<'_>, AccessByNameError> {
225 let elem = InMemDicomObject::element_by_name(*self, name)?;
226 Ok(elem.value())
227 }
228
229 #[inline]
230 fn at(
231 &self,
232 selector: impl Into<AttributeSelector>,
233 ) -> Result<Self::LeafAttribute<'_>, AtAccessError> {
234 self.value_at(selector)
235 }
236}
237
238impl FileDicomObject<InMemDicomObject<StandardDataDictionary>> {
239 pub fn open_file<P: AsRef<Path>>(path: P) -> Result<Self, ReadError> {
247 Self::open_file_with_dict(path, StandardDataDictionary)
248 }
249
250 pub fn from_reader<S>(src: S) -> Result<Self, ReadError>
258 where
259 S: Read,
260 {
261 Self::from_reader_with_dict(src, StandardDataDictionary)
262 }
263}
264
265impl InMemDicomObject<StandardDataDictionary> {
266 pub fn new_empty() -> Self {
268 InMemDicomObject {
269 entries: BTreeMap::new(),
270 dict: StandardDataDictionary,
271 len: Length::UNDEFINED,
272 charset_changed: false,
273 }
274 }
275
276 #[inline]
278 pub fn from_element_source<I>(iter: I) -> Result<Self>
279 where
280 I: IntoIterator<Item = Result<InMemElement<StandardDataDictionary>>>,
281 {
282 Self::from_element_source_with_dict(iter, StandardDataDictionary)
283 }
284
285 #[inline]
287 pub fn from_element_iter<I>(iter: I) -> Self
288 where
289 I: IntoIterator<Item = InMemElement<StandardDataDictionary>>,
290 {
291 Self::from_iter_with_dict(iter, StandardDataDictionary)
292 }
293
294 #[inline]
301 pub fn command_from_element_iter<I>(iter: I) -> Self
302 where
303 I: IntoIterator<Item = InMemElement<StandardDataDictionary>>,
304 {
305 Self::command_from_iter_with_dict(iter, StandardDataDictionary)
306 }
307
308 #[inline]
316 pub fn read_dataset<S>(decoder: S) -> Result<Self, ReadError>
317 where
318 S: StatefulDecode,
319 {
320 Self::read_dataset_with_dict(decoder, StandardDataDictionary)
321 }
322
323 #[inline]
329 pub fn read_dataset_with_ts_cs<S>(
330 from: S,
331 ts: &TransferSyntax,
332 cs: SpecificCharacterSet,
333 ) -> Result<Self, ReadError>
334 where
335 S: Read,
336 {
337 Self::read_dataset_with_dict_ts_cs(from, StandardDataDictionary, ts, cs)
338 }
339
340 #[inline]
347 pub fn read_dataset_with_ts<S>(from: S, ts: &TransferSyntax) -> Result<Self, ReadError>
348 where
349 S: Read,
350 {
351 Self::read_dataset_with_dict_ts_cs(
352 from,
353 StandardDataDictionary,
354 ts,
355 SpecificCharacterSet::default(),
356 )
357 }
358}
359
360impl<D> FileDicomObject<InMemDicomObject<D>>
361where
362 D: DataDictionary,
363 D: Clone,
364{
365 pub fn new_empty_with_dict_and_meta(dict: D, meta: FileMetaTable) -> Self {
368 FileDicomObject {
369 meta,
370 obj: InMemDicomObject {
371 entries: BTreeMap::new(),
372 dict,
373 len: Length::UNDEFINED,
374 charset_changed: false,
375 },
376 }
377 }
378
379 pub fn open_file_with_dict<P: AsRef<Path>>(path: P, dict: D) -> Result<Self, ReadError> {
387 Self::open_file_with(path, dict, TransferSyntaxRegistry)
388 }
389
390 pub fn open_file_with<P, R>(path: P, dict: D, ts_index: R) -> Result<Self, ReadError>
404 where
405 P: AsRef<Path>,
406 R: TransferSyntaxIndex,
407 {
408 Self::open_file_with_all_options(
409 path,
410 dict,
411 ts_index,
412 None,
413 None,
414 ReadPreamble::Auto,
415 Default::default(),
416 Default::default(),
417 )
418 }
419
420 #[allow(clippy::too_many_arguments)]
421 pub(crate) fn open_file_with_all_options<P, R>(
422 path: P,
423 dict: D,
424 ts_index: R,
425 read_until: Option<Tag>,
426 read_to: Option<Tag>,
427 mut read_preamble: ReadPreamble,
428 odd_length: OddLengthStrategy,
429 charset_override: CharacterSetOverride,
430 ) -> Result<Self, ReadError>
431 where
432 P: AsRef<Path>,
433 R: TransferSyntaxIndex,
434 {
435 let path = path.as_ref();
436 let mut file =
437 BufReader::new(File::open(path).with_context(|_| OpenFileSnafu { filename: path })?);
438
439 if read_preamble == ReadPreamble::Auto {
440 read_preamble = Self::detect_preamble(&mut file)
441 .with_context(|_| ReadFileSnafu { filename: path })?;
442 }
443
444 if read_preamble == ReadPreamble::Auto || read_preamble == ReadPreamble::Always {
445 let mut buf = [0u8; 128];
446 file.read_exact(&mut buf)
448 .with_context(|_| ReadFileSnafu { filename: path })?;
449 }
450
451 Self::read_parts_with_all_options_impl(
452 file,
453 dict,
454 ts_index,
455 read_until,
456 read_to,
457 odd_length,
458 charset_override,
459 )
460 }
461
462 pub fn from_reader_with_dict<S>(src: S, dict: D) -> Result<Self, ReadError>
470 where
471 S: Read,
472 {
473 Self::from_reader_with(src, dict, TransferSyntaxRegistry)
474 }
475
476 pub fn from_reader_with<S, R>(src: S, dict: D, ts_index: R) -> Result<Self, ReadError>
490 where
491 S: Read,
492 R: TransferSyntaxIndex,
493 {
494 Self::from_reader_with_all_options(
495 src,
496 dict,
497 ts_index,
498 None,
499 None,
500 ReadPreamble::Auto,
501 Default::default(),
502 Default::default(),
503 )
504 }
505
506 #[allow(clippy::too_many_arguments)]
507 pub(crate) fn from_reader_with_all_options<S, R>(
508 src: S,
509 dict: D,
510 ts_index: R,
511 read_until: Option<Tag>,
512 read_to: Option<Tag>,
513 mut read_preamble: ReadPreamble,
514 odd_length: OddLengthStrategy,
515 charset_override: CharacterSetOverride,
516 ) -> Result<Self, ReadError>
517 where
518 S: Read,
519 R: TransferSyntaxIndex,
520 {
521 let mut file = BufReader::new(src);
522
523 if read_preamble == ReadPreamble::Auto {
524 read_preamble = Self::detect_preamble(&mut file).context(ReadPreambleBytesSnafu)?;
525 }
526
527 if read_preamble == ReadPreamble::Always {
528 let mut buf = [0u8; 128];
530 file.read_exact(&mut buf).context(ReadPreambleBytesSnafu)?;
532 }
533
534 Self::read_parts_with_all_options_impl(
535 file,
536 dict,
537 ts_index,
538 read_until,
539 read_to,
540 odd_length,
541 charset_override,
542 )
543 }
544
545 fn detect_preamble<S>(reader: &mut BufReader<S>) -> std::io::Result<ReadPreamble>
548 where
549 S: Read,
550 {
551 let buf = reader.fill_buf()?;
552 let buflen = buf.len();
553
554 if buflen < 4 {
555 return Err(std::io::ErrorKind::UnexpectedEof.into());
556 }
557
558 if buflen >= 132 && &buf[128..132] == b"DICM" {
559 return Ok(ReadPreamble::Always);
560 }
561
562 if &buf[0..4] == b"DICM" {
563 return Ok(ReadPreamble::Never);
564 }
565
566 Ok(ReadPreamble::Auto)
568 }
569
570 fn read_parts_with_all_options_impl<S, R>(
578 mut src: BufReader<S>,
579 dict: D,
580 ts_index: R,
581 read_until: Option<Tag>,
582 read_to: Option<Tag>,
583 odd_length: OddLengthStrategy,
584 charset_override: CharacterSetOverride,
585 ) -> Result<Self, ReadError>
586 where
587 S: Read,
588 R: TransferSyntaxIndex,
589 {
590 let mut meta = FileMetaTable::from_reader(&mut src).context(ParseMetaDataSetSnafu)?;
592
593 let ts_uid = meta.transfer_syntax();
594 if let Some(ts) = ts_index.get(ts_uid) {
596 let mut options = DataSetReaderOptions::default();
597 options.odd_length = odd_length;
598 options.charset_override = charset_override;
599
600 let obj = match ts.codec() {
601 Codec::Dataset(Some(adapter)) => {
602 let adapter = adapter.adapt_reader(Box::new(src));
603 let mut dataset = DataSetReader::new_with_ts_options(adapter, ts, options)
604 .context(CreateParserSnafu)?;
605 InMemDicomObject::build_object(
606 &mut dataset,
607 dict,
608 false,
609 Length::UNDEFINED,
610 read_until,
611 read_to,
612 )?
613 }
614 Codec::Dataset(None) => {
615 if ts_uid == uids::DEFLATED_EXPLICIT_VR_LITTLE_ENDIAN
616 || ts_uid == uids::JPIP_REFERENCED_DEFLATE
617 || ts_uid == uids::JPIPHTJ2K_REFERENCED_DEFLATE
618 {
619 return ReadUnsupportedTransferSyntaxWithSuggestionSnafu {
620 uid: ts.uid(),
621 name: ts.name(),
622 feature_name: "dicom-transfer-syntax-registry/deflate",
623 }
624 .fail();
625 }
626
627 return ReadUnsupportedTransferSyntaxSnafu {
628 uid: ts.uid(),
629 name: ts.name(),
630 }
631 .fail();
632 }
633 Codec::None | Codec::EncapsulatedPixelData(..) => {
634 let mut dataset = DataSetReader::new_with_ts_options(src, ts, options)
635 .context(CreateParserSnafu)?;
636 InMemDicomObject::build_object(
637 &mut dataset,
638 dict,
639 false,
640 Length::UNDEFINED,
641 read_until,
642 read_to,
643 )?
644 }
645 };
646
647 if meta.media_storage_sop_class_uid().is_empty() {
649 if let Some(elem) = obj.get(tags::SOP_CLASS_UID) {
650 meta.media_storage_sop_class_uid = elem
651 .value()
652 .to_str()
653 .context(ParseSopAttributeSnafu)?
654 .to_string();
655 }
656 }
657
658 if meta.media_storage_sop_instance_uid().is_empty() {
660 if let Some(elem) = obj.get(tags::SOP_INSTANCE_UID) {
661 meta.media_storage_sop_instance_uid = elem
662 .value()
663 .to_str()
664 .context(ParseSopAttributeSnafu)?
665 .to_string();
666 }
667 }
668
669 Ok(FileDicomObject { meta, obj })
670 } else {
671 ReadUnrecognizedTransferSyntaxSnafu {
672 uid: ts_uid.to_string(),
673 }
674 .fail()
675 }
676 }
677}
678
679impl FileDicomObject<InMemDicomObject<StandardDataDictionary>> {
680 pub fn new_empty_with_meta(meta: FileMetaTable) -> Self {
682 FileDicomObject {
683 meta,
684 obj: InMemDicomObject {
685 entries: BTreeMap::new(),
686 dict: StandardDataDictionary,
687 len: Length::UNDEFINED,
688 charset_changed: false,
689 },
690 }
691 }
692}
693
694impl<D> InMemDicomObject<D>
695where
696 D: DataDictionary,
697 D: Clone,
698{
699 pub fn new_empty_with_dict(dict: D) -> Self {
701 InMemDicomObject {
702 entries: BTreeMap::new(),
703 dict,
704 len: Length::UNDEFINED,
705 charset_changed: false,
706 }
707 }
708
709 pub fn from_element_source_with_dict<I>(iter: I, dict: D) -> Result<Self>
711 where
712 I: IntoIterator<Item = Result<InMemElement<D>>>,
713 {
714 let entries: Result<_> = iter.into_iter().map_ok(|e| (e.tag(), e)).collect();
715 Ok(InMemDicomObject {
716 entries: entries?,
717 dict,
718 len: Length::UNDEFINED,
719 charset_changed: false,
720 })
721 }
722
723 pub fn from_iter_with_dict<I>(iter: I, dict: D) -> Self
725 where
726 I: IntoIterator<Item = InMemElement<D>>,
727 {
728 let entries = iter.into_iter().map(|e| (e.tag(), e)).collect();
729 InMemDicomObject {
730 entries,
731 dict,
732 len: Length::UNDEFINED,
733 charset_changed: false,
734 }
735 }
736
737 pub fn command_from_iter_with_dict<I>(iter: I, dict: D) -> Self
744 where
745 I: IntoIterator<Item = InMemElement<D>>,
746 {
747 let mut calculated_length: u32 = 0;
748 let mut entries: BTreeMap<_, _> = iter
749 .into_iter()
750 .map(|e| {
751 if e.tag().0 == 0x0000 && e.tag().1 != 0x0000 {
753 let l = e.value().length();
754 calculated_length += if l.is_defined() { even_len(l.0) } else { 0 } + 8;
755 }
756
757 (e.tag(), e)
758 })
759 .collect();
760
761 entries.insert(
762 Tag(0, 0),
763 InMemElement::new(Tag(0, 0), VR::UL, PrimitiveValue::from(calculated_length)),
764 );
765
766 InMemDicomObject {
767 entries,
768 dict,
769 len: Length::UNDEFINED,
770 charset_changed: false,
771 }
772 }
773
774 pub fn read_dataset_with_dict<S>(decoder: S, dict: D) -> Result<Self, ReadError>
778 where
779 S: StatefulDecode,
780 D: DataDictionary,
781 {
782 let mut dataset = DataSetReader::new(decoder, Default::default());
783 InMemDicomObject::build_object(&mut dataset, dict, false, Length::UNDEFINED, None, None)
784 }
785
786 #[inline]
789 pub fn read_dataset_with_dict_ts<S>(
790 from: S,
791 dict: D,
792 ts: &TransferSyntax,
793 ) -> Result<Self, ReadError>
794 where
795 S: Read,
796 D: DataDictionary,
797 {
798 Self::read_dataset_with_dict_ts_cs(from, dict, ts, SpecificCharacterSet::default())
799 }
800
801 pub fn read_dataset_with_dict_ts_cs<S>(
809 from: S,
810 dict: D,
811 ts: &TransferSyntax,
812 cs: SpecificCharacterSet,
813 ) -> Result<Self, ReadError>
814 where
815 S: Read,
816 D: DataDictionary,
817 {
818 let from = BufReader::new(from);
819
820 match ts.codec() {
821 Codec::Dataset(Some(adapter)) => {
822 let adapter = adapter.adapt_reader(Box::new(from));
823 let mut dataset =
824 DataSetReader::new_with_ts_cs(adapter, ts, cs).context(CreateParserSnafu)?;
825 InMemDicomObject::build_object(
826 &mut dataset,
827 dict,
828 false,
829 Length::UNDEFINED,
830 None,
831 None,
832 )
833 }
834 Codec::Dataset(None) => {
835 let uid = ts.uid();
836 if uid == uids::DEFLATED_EXPLICIT_VR_LITTLE_ENDIAN
837 || uid == uids::JPIP_REFERENCED_DEFLATE
838 || uid == uids::JPIPHTJ2K_REFERENCED_DEFLATE
839 {
840 return ReadUnsupportedTransferSyntaxWithSuggestionSnafu {
841 uid,
842 name: ts.name(),
843 feature_name: "dicom-transfer-syntax-registry/deflate",
844 }
845 .fail();
846 }
847
848 ReadUnsupportedTransferSyntaxSnafu {
849 uid,
850 name: ts.name(),
851 }
852 .fail()
853 }
854 Codec::None | Codec::EncapsulatedPixelData(..) => {
855 let mut dataset =
856 DataSetReader::new_with_ts_cs(from, ts, cs).context(CreateParserSnafu)?;
857 InMemDicomObject::build_object(
858 &mut dataset,
859 dict,
860 false,
861 Length::UNDEFINED,
862 None,
863 None,
864 )
865 }
866 }
867 }
868
869 pub fn element(&self, tag: Tag) -> Result<&InMemElement<D>> {
879 self.entries
880 .get(&tag)
881 .context(NoSuchDataElementTagSnafu { tag })
882 }
883
884 pub fn element_by_name(&self, name: &str) -> Result<&InMemElement<D>, AccessByNameError> {
896 let tag = self.lookup_name(name)?;
897 self.entries
898 .get(&tag)
899 .with_context(|| NoSuchDataElementAliasSnafu {
900 tag,
901 alias: name.to_string(),
902 })
903 }
904
905 pub fn element_opt(&self, tag: Tag) -> Result<Option<&InMemElement<D>>, AccessError> {
910 match self.element(tag) {
911 Ok(e) => Ok(Some(e)),
912 Err(super::AccessError::NoSuchDataElementTag { .. }) => Ok(None),
913 }
914 }
915
916 pub fn get(&self, tag: Tag) -> Option<&InMemElement<D>> {
921 self.entries.get(&tag)
922 }
923
924 fn get_mut(&mut self, tag: Tag) -> Option<&mut InMemElement<D>> {
929 self.entries.get_mut(&tag)
930 }
931
932 pub fn element_by_name_opt(
943 &self,
944 name: &str,
945 ) -> Result<Option<&InMemElement<D>>, AccessByNameError> {
946 match self.element_by_name(name) {
947 Ok(e) => Ok(Some(e)),
948 Err(AccessByNameError::NoSuchDataElementAlias { .. }) => Ok(None),
949 Err(e) => Err(e),
950 }
951 }
952
953 fn find_private_creator(&self, group: GroupNumber, creator: &str) -> Option<&Tag> {
954 let range = Tag(group, 0)..Tag(group, 0xFF);
955 for (tag, elem) in self.entries.range(range) {
956 if elem.header().vr() == VR::LO && elem.to_str().unwrap_or_default() == creator {
959 return Some(tag);
960 }
961 }
962 None
963 }
964
965 pub fn private_element(
998 &self,
999 group: GroupNumber,
1000 creator: &str,
1001 element: u8,
1002 ) -> Result<&InMemElement<D>, PrivateElementError> {
1003 let tag = self.find_private_creator(group, creator).ok_or_else(|| {
1004 PrivateCreatorNotFoundSnafu {
1005 group,
1006 creator: creator.to_string(),
1007 }
1008 .build()
1009 })?;
1010
1011 let element_num = (tag.element() << 8) | (element as u16);
1012 self.get(Tag(group, element_num)).ok_or_else(|| {
1013 ElementNotFoundSnafu {
1014 group,
1015 creator: creator.to_string(),
1016 elem: element,
1017 }
1018 .build()
1019 })
1020 }
1021
1022 pub fn put(&mut self, elt: InMemElement<D>) -> Option<InMemElement<D>> {
1027 self.put_element(elt)
1028 }
1029
1030 pub fn put_element(&mut self, elt: InMemElement<D>) -> Option<InMemElement<D>> {
1035 self.len = Length::UNDEFINED;
1036 self.invalidate_if_charset_changed(elt.tag());
1037 self.entries.insert(elt.tag(), elt)
1038 }
1039
1040 pub fn put_private_element(
1081 &mut self,
1082 group: GroupNumber,
1083 creator: &str,
1084 element: u8,
1085 vr: VR,
1086 value: PrimitiveValue,
1087 ) -> Result<Option<InMemElement<D>>, PrivateElementError> {
1088 ensure!(group % 2 == 1, InvalidGroupSnafu { group });
1089 let private_creator = self.find_private_creator(group, creator);
1090 if let Some(tag) = private_creator {
1091 let tag = Tag(group, (tag.element() << 8) | element as u16);
1093 Ok(self.put_element(DataElement::new(tag, vr, value)))
1094 } else {
1095 let range = Tag(group, 0)..Tag(group, 0xFF);
1097 let last_entry = self.entries.range(range).next_back();
1098 let next_available = match last_entry {
1099 Some((tag, _)) => tag.element() + 1,
1100 None => 0x01,
1101 };
1102 if next_available < 0xFF {
1103 let tag = Tag(group, next_available);
1105 self.put_str(tag, VR::LO, creator);
1106
1107 let tag = Tag(group, (next_available << 8) | element as u16);
1109 Ok(self.put_element(DataElement::new(tag, vr, value)))
1110 } else {
1111 NoSpaceSnafu { group }.fail()
1112 }
1113 }
1114 }
1115
1116 pub fn put_str(
1119 &mut self,
1120 tag: Tag,
1121 vr: VR,
1122 string: impl Into<String>,
1123 ) -> Option<InMemElement<D>> {
1124 self.put_element(DataElement::new(tag, vr, string.into()))
1125 }
1126
1127 pub fn remove_element(&mut self, tag: Tag) -> bool {
1130 if self.entries.remove(&tag).is_some() {
1131 self.len = Length::UNDEFINED;
1132 true
1133 } else {
1134 false
1135 }
1136 }
1137
1138 pub fn remove_element_by_name(&mut self, name: &str) -> Result<bool, AccessByNameError> {
1141 let tag = self.lookup_name(name)?;
1142 Ok(self.entries.remove(&tag).is_some()).inspect(|removed| {
1143 if *removed {
1144 self.len = Length::UNDEFINED;
1145 }
1146 })
1147 }
1148
1149 pub fn take_element(&mut self, tag: Tag) -> Result<InMemElement<D>> {
1151 self.entries
1152 .remove(&tag)
1153 .inspect(|_e| {
1154 self.len = Length::UNDEFINED;
1155 })
1156 .context(NoSuchDataElementTagSnafu { tag })
1157 }
1158
1159 pub fn take(&mut self, tag: Tag) -> Option<InMemElement<D>> {
1163 self.entries.remove(&tag).inspect(|_e| {
1164 self.len = Length::UNDEFINED;
1165 })
1166 }
1167
1168 pub fn take_element_by_name(
1170 &mut self,
1171 name: &str,
1172 ) -> Result<InMemElement<D>, AccessByNameError> {
1173 let tag = self.lookup_name(name)?;
1174 self.entries
1175 .remove(&tag)
1176 .inspect(|_e| {
1177 self.len = Length::UNDEFINED;
1178 })
1179 .with_context(|| NoSuchDataElementAliasSnafu {
1180 tag,
1181 alias: name.to_string(),
1182 })
1183 }
1184
1185 pub fn retain(&mut self, mut f: impl FnMut(&InMemElement<D>) -> bool) {
1191 self.entries.retain(|_, elem| f(elem));
1192 self.len = Length::UNDEFINED;
1193 }
1194
1195 pub fn update_value(
1223 &mut self,
1224 tag: Tag,
1225 f: impl FnMut(&mut Value<InMemDicomObject<D>, InMemFragment>),
1226 ) -> bool {
1227 self.invalidate_if_charset_changed(tag);
1228 if let Some(e) = self.entries.get_mut(&tag) {
1229 e.update_value(f);
1230 self.len = Length::UNDEFINED;
1231 true
1232 } else {
1233 false
1234 }
1235 }
1236
1237 pub fn update_value_at(
1287 &mut self,
1288 selector: impl Into<AttributeSelector>,
1289 f: impl FnMut(&mut Value<InMemDicomObject<D>, InMemFragment>),
1290 ) -> Result<(), AtAccessError> {
1291 self.entry_at_mut(selector)
1292 .map(|e| e.update_value(f))
1293 .map(|_| {
1294 self.len = Length::UNDEFINED;
1295 })
1296 }
1297
1298 pub fn value_at(
1325 &self,
1326 selector: impl Into<AttributeSelector>,
1327 ) -> Result<&Value<InMemDicomObject<D>, InMemFragment>, AtAccessError> {
1328 let selector: AttributeSelector = selector.into();
1329
1330 let mut obj = self;
1331 for (i, step) in selector.iter().enumerate() {
1332 match step {
1333 AttributeSelectorStep::Tag(tag) => {
1335 return obj.get(*tag).map(|e| e.value()).with_context(|| {
1336 MissingLeafElementSnafu {
1337 selector: selector.clone(),
1338 }
1339 });
1340 }
1341 AttributeSelectorStep::Nested { tag, item } => {
1343 let e = obj
1344 .entries
1345 .get(tag)
1346 .with_context(|| crate::MissingSequenceSnafu {
1347 selector: selector.clone(),
1348 step_index: i as u32,
1349 })?;
1350
1351 let items = e.items().with_context(|| NotASequenceSnafu {
1353 selector: selector.clone(),
1354 step_index: i as u32,
1355 })?;
1356
1357 obj =
1359 items
1360 .get(*item as usize)
1361 .with_context(|| crate::MissingSequenceSnafu {
1362 selector: selector.clone(),
1363 step_index: i as u32,
1364 })?;
1365 }
1366 }
1367 }
1368
1369 unreachable!()
1370 }
1371
1372 pub fn convert_to_utf8(&mut self) {
1374 self.put(DataElement::new(
1375 tags::SPECIFIC_CHARACTER_SET,
1376 VR::CS,
1377 "ISO_IR 192",
1378 ));
1379 }
1380
1381 pub fn entry_at(
1390 &self,
1391 selector: impl Into<AttributeSelector>,
1392 ) -> Result<&InMemElement<D>, AtAccessError> {
1393 let selector: AttributeSelector = selector.into();
1394
1395 let mut obj = self;
1396 for (i, step) in selector.iter().enumerate() {
1397 match step {
1398 AttributeSelectorStep::Tag(tag) => {
1400 return obj.get(*tag).with_context(|| MissingLeafElementSnafu {
1401 selector: selector.clone(),
1402 });
1403 }
1404 AttributeSelectorStep::Nested { tag, item } => {
1406 let e = obj
1407 .entries
1408 .get(tag)
1409 .with_context(|| crate::MissingSequenceSnafu {
1410 selector: selector.clone(),
1411 step_index: i as u32,
1412 })?;
1413
1414 let items = e.items().with_context(|| NotASequenceSnafu {
1416 selector: selector.clone(),
1417 step_index: i as u32,
1418 })?;
1419
1420 obj =
1422 items
1423 .get(*item as usize)
1424 .with_context(|| crate::MissingSequenceSnafu {
1425 selector: selector.clone(),
1426 step_index: i as u32,
1427 })?;
1428 }
1429 }
1430 }
1431
1432 unreachable!()
1433 }
1434
1435 fn entry_at_mut(
1439 &mut self,
1440 selector: impl Into<AttributeSelector>,
1441 ) -> Result<&mut InMemElement<D>, AtAccessError> {
1442 let selector: AttributeSelector = selector.into();
1443
1444 let mut obj = self;
1445 for (i, step) in selector.iter().enumerate() {
1446 match step {
1447 AttributeSelectorStep::Tag(tag) => {
1449 return obj.get_mut(*tag).with_context(|| MissingLeafElementSnafu {
1450 selector: selector.clone(),
1451 });
1452 }
1453 AttributeSelectorStep::Nested { tag, item } => {
1455 let e =
1456 obj.entries
1457 .get_mut(tag)
1458 .with_context(|| crate::MissingSequenceSnafu {
1459 selector: selector.clone(),
1460 step_index: i as u32,
1461 })?;
1462
1463 let items = e.items_mut().with_context(|| NotASequenceSnafu {
1465 selector: selector.clone(),
1466 step_index: i as u32,
1467 })?;
1468
1469 obj = items.get_mut(*item as usize).with_context(|| {
1471 crate::MissingSequenceSnafu {
1472 selector: selector.clone(),
1473 step_index: i as u32,
1474 }
1475 })?;
1476 }
1477 }
1478 }
1479
1480 unreachable!()
1481 }
1482
1483 fn apply(&mut self, op: AttributeOp) -> ApplyResult {
1523 let AttributeOp { selector, action } = op;
1524 let dict = self.dict.clone();
1525
1526 let mut obj = self;
1527 for (i, step) in selector.iter().enumerate() {
1528 match step {
1529 AttributeSelectorStep::Tag(tag) => return obj.apply_leaf(*tag, action),
1531 AttributeSelectorStep::Nested { tag, item } => {
1533 if !obj.entries.contains_key(tag) {
1534 if action.is_constructive() {
1536 let vr = dict
1537 .by_tag(*tag)
1538 .and_then(|entry| entry.vr().exact())
1539 .unwrap_or(VR::UN);
1540
1541 if vr != VR::SQ && vr != VR::UN {
1542 return Err(ApplyError::NotASequence {
1543 selector: selector.clone(),
1544 step_index: i as u32,
1545 });
1546 }
1547
1548 obj.put(DataElement::new(*tag, vr, DataSetSequence::empty()));
1549 } else {
1550 return Err(ApplyError::MissingSequence {
1551 selector: selector.clone(),
1552 step_index: i as u32,
1553 });
1554 }
1555 };
1556
1557 let items = obj
1559 .entries
1560 .get_mut(tag)
1561 .expect("sequence element should exist at this point")
1562 .items_mut()
1563 .ok_or_else(|| ApplyError::NotASequence {
1564 selector: selector.clone(),
1565 step_index: i as u32,
1566 })?;
1567
1568 obj = if items.len() == *item as usize && action.is_constructive() {
1570 items.push(InMemDicomObject::new_empty_with_dict(dict.clone()));
1571 items.last_mut().unwrap()
1572 } else {
1573 items.get_mut(*item as usize).ok_or_else(|| {
1574 ApplyError::MissingSequence {
1575 selector: selector.clone(),
1576 step_index: i as u32,
1577 }
1578 })?
1579 };
1580 }
1581 }
1582 }
1583 unreachable!()
1584 }
1585
1586 fn apply_leaf(&mut self, tag: Tag, action: AttributeAction) -> ApplyResult {
1587 self.invalidate_if_charset_changed(tag);
1588 match action {
1589 AttributeAction::Remove => {
1590 self.remove_element(tag);
1591 Ok(())
1592 }
1593 AttributeAction::Empty => {
1594 if let Some(e) = self.entries.get_mut(&tag) {
1595 let vr = e.vr();
1596 *e = DataElement::empty(tag, vr);
1598 self.len = Length::UNDEFINED;
1599 }
1600 Ok(())
1601 }
1602 AttributeAction::SetVr(new_vr) => {
1603 if let Some(e) = self.entries.remove(&tag) {
1604 let (header, value) = e.into_parts();
1605 let e = DataElement::new(header.tag, new_vr, value);
1606 self.put(e);
1607 } else {
1608 self.put(DataElement::empty(tag, new_vr));
1609 }
1610 Ok(())
1611 }
1612 AttributeAction::Set(new_value) => {
1613 self.apply_change_value_impl(tag, new_value);
1614 Ok(())
1615 }
1616 AttributeAction::SetStr(string) => {
1617 let new_value = PrimitiveValue::from(&*string);
1618 self.apply_change_value_impl(tag, new_value);
1619 Ok(())
1620 }
1621 AttributeAction::SetIfMissing(new_value) => {
1622 if self.get(tag).is_none() {
1623 self.apply_change_value_impl(tag, new_value);
1624 }
1625 Ok(())
1626 }
1627 AttributeAction::SetStrIfMissing(string) => {
1628 if self.get(tag).is_none() {
1629 let new_value = PrimitiveValue::from(&*string);
1630 self.apply_change_value_impl(tag, new_value);
1631 }
1632 Ok(())
1633 }
1634 AttributeAction::Replace(new_value) => {
1635 if self.get(tag).is_some() {
1636 self.apply_change_value_impl(tag, new_value);
1637 }
1638 Ok(())
1639 }
1640 AttributeAction::ReplaceStr(string) => {
1641 if self.get(tag).is_some() {
1642 let new_value = PrimitiveValue::from(&*string);
1643 self.apply_change_value_impl(tag, new_value);
1644 }
1645 Ok(())
1646 }
1647 AttributeAction::PushStr(string) => self.apply_push_str_impl(tag, string),
1648 AttributeAction::PushI32(integer) => self.apply_push_i32_impl(tag, integer),
1649 AttributeAction::PushU32(integer) => self.apply_push_u32_impl(tag, integer),
1650 AttributeAction::PushI16(integer) => self.apply_push_i16_impl(tag, integer),
1651 AttributeAction::PushU16(integer) => self.apply_push_u16_impl(tag, integer),
1652 AttributeAction::PushF32(number) => self.apply_push_f32_impl(tag, number),
1653 AttributeAction::PushF64(number) => self.apply_push_f64_impl(tag, number),
1654 AttributeAction::Truncate(limit) => {
1655 self.update_value(tag, |value| value.truncate(limit));
1656 Ok(())
1657 }
1658 _ => UnsupportedActionSnafu.fail(),
1659 }
1660 }
1661
1662 fn apply_change_value_impl(&mut self, tag: Tag, new_value: PrimitiveValue) {
1663 self.invalidate_if_charset_changed(tag);
1664
1665 if let Some(e) = self.entries.get_mut(&tag) {
1666 let vr = e.vr();
1667 let new_value = if vr == VR::SQ && new_value.is_empty() {
1670 DataSetSequence::empty().into()
1671 } else {
1672 Value::from(new_value)
1673 };
1674 *e = DataElement::new(tag, vr, new_value);
1675 self.len = Length::UNDEFINED;
1676 } else {
1677 let vr = dicom_dictionary_std::StandardDataDictionary
1679 .by_tag(tag)
1680 .and_then(|entry| entry.vr().exact())
1681 .unwrap_or(VR::UN);
1682 let new_value = if vr == VR::SQ && new_value.is_empty() {
1687 DataSetSequence::empty().into()
1688 } else {
1689 Value::from(new_value)
1690 };
1691
1692 self.put(DataElement::new(tag, vr, new_value));
1693 }
1694 }
1695
1696 fn invalidate_if_charset_changed(&mut self, tag: Tag) {
1697 if tag == tags::SPECIFIC_CHARACTER_SET {
1698 self.charset_changed = true;
1699 }
1700 }
1701
1702 fn apply_push_str_impl(&mut self, tag: Tag, string: Cow<'static, str>) -> ApplyResult {
1703 if let Some(e) = self.entries.remove(&tag) {
1704 let (header, value) = e.into_parts();
1705 match value {
1706 Value::Primitive(mut v) => {
1707 self.invalidate_if_charset_changed(tag);
1708 v.extend_str([string]).context(ModifySnafu)?;
1710 self.put(DataElement::new(tag, header.vr, v));
1712 Ok(())
1713 }
1714
1715 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1716 kind: ValueType::PixelSequence,
1717 }
1718 .fail(),
1719 Value::Sequence(..) => IncompatibleTypesSnafu {
1720 kind: ValueType::DataSetSequence,
1721 }
1722 .fail(),
1723 }
1724 } else {
1725 let vr = dicom_dictionary_std::StandardDataDictionary
1727 .by_tag(tag)
1728 .and_then(|entry| entry.vr().exact())
1729 .unwrap_or(VR::UN);
1730 self.put(DataElement::new(tag, vr, PrimitiveValue::from(&*string)));
1732 Ok(())
1733 }
1734 }
1735
1736 fn apply_push_i32_impl(&mut self, tag: Tag, integer: i32) -> ApplyResult {
1737 if let Some(e) = self.entries.remove(&tag) {
1738 let (header, value) = e.into_parts();
1739 match value {
1740 Value::Primitive(mut v) => {
1741 v.extend_i32([integer]).context(ModifySnafu)?;
1743 self.put(DataElement::new(tag, header.vr, v));
1745 Ok(())
1746 }
1747
1748 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1749 kind: ValueType::PixelSequence,
1750 }
1751 .fail(),
1752 Value::Sequence(..) => IncompatibleTypesSnafu {
1753 kind: ValueType::DataSetSequence,
1754 }
1755 .fail(),
1756 }
1757 } else {
1758 let vr = dicom_dictionary_std::StandardDataDictionary
1760 .by_tag(tag)
1761 .and_then(|entry| entry.vr().exact())
1762 .unwrap_or(VR::SL);
1763 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1765 Ok(())
1766 }
1767 }
1768
1769 fn apply_push_u32_impl(&mut self, tag: Tag, integer: u32) -> ApplyResult {
1770 if let Some(e) = self.entries.remove(&tag) {
1771 let (header, value) = e.into_parts();
1772 match value {
1773 Value::Primitive(mut v) => {
1774 v.extend_u32([integer]).context(ModifySnafu)?;
1776 self.put(DataElement::new(tag, header.vr, v));
1778 Ok(())
1779 }
1780
1781 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1782 kind: ValueType::PixelSequence,
1783 }
1784 .fail(),
1785 Value::Sequence(..) => IncompatibleTypesSnafu {
1786 kind: ValueType::DataSetSequence,
1787 }
1788 .fail(),
1789 }
1790 } else {
1791 let vr = dicom_dictionary_std::StandardDataDictionary
1793 .by_tag(tag)
1794 .and_then(|entry| entry.vr().exact())
1795 .unwrap_or(VR::UL);
1796 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1798 Ok(())
1799 }
1800 }
1801
1802 fn apply_push_i16_impl(&mut self, tag: Tag, integer: i16) -> ApplyResult {
1803 if let Some(e) = self.entries.remove(&tag) {
1804 let (header, value) = e.into_parts();
1805 match value {
1806 Value::Primitive(mut v) => {
1807 v.extend_i16([integer]).context(ModifySnafu)?;
1809 self.put(DataElement::new(tag, header.vr, v));
1811 Ok(())
1812 }
1813
1814 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1815 kind: ValueType::PixelSequence,
1816 }
1817 .fail(),
1818 Value::Sequence(..) => IncompatibleTypesSnafu {
1819 kind: ValueType::DataSetSequence,
1820 }
1821 .fail(),
1822 }
1823 } else {
1824 let vr = dicom_dictionary_std::StandardDataDictionary
1826 .by_tag(tag)
1827 .and_then(|entry| entry.vr().exact())
1828 .unwrap_or(VR::SS);
1829 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1831 Ok(())
1832 }
1833 }
1834
1835 fn apply_push_u16_impl(&mut self, tag: Tag, integer: u16) -> ApplyResult {
1836 if let Some(e) = self.entries.remove(&tag) {
1837 let (header, value) = e.into_parts();
1838 match value {
1839 Value::Primitive(mut v) => {
1840 v.extend_u16([integer]).context(ModifySnafu)?;
1842 self.put(DataElement::new(tag, header.vr, v));
1844 Ok(())
1845 }
1846
1847 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1848 kind: ValueType::PixelSequence,
1849 }
1850 .fail(),
1851 Value::Sequence(..) => IncompatibleTypesSnafu {
1852 kind: ValueType::DataSetSequence,
1853 }
1854 .fail(),
1855 }
1856 } else {
1857 let vr = dicom_dictionary_std::StandardDataDictionary
1859 .by_tag(tag)
1860 .and_then(|entry| entry.vr().exact())
1861 .unwrap_or(VR::US);
1862 self.put(DataElement::new(tag, vr, PrimitiveValue::from(integer)));
1864 Ok(())
1865 }
1866 }
1867
1868 fn apply_push_f32_impl(&mut self, tag: Tag, number: f32) -> ApplyResult {
1869 if let Some(e) = self.entries.remove(&tag) {
1870 let (header, value) = e.into_parts();
1871 match value {
1872 Value::Primitive(mut v) => {
1873 v.extend_f32([number]).context(ModifySnafu)?;
1875 self.put(DataElement::new(tag, header.vr, v));
1877 Ok(())
1878 }
1879
1880 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1881 kind: ValueType::PixelSequence,
1882 }
1883 .fail(),
1884 Value::Sequence(..) => IncompatibleTypesSnafu {
1885 kind: ValueType::DataSetSequence,
1886 }
1887 .fail(),
1888 }
1889 } else {
1890 let vr = dicom_dictionary_std::StandardDataDictionary
1892 .by_tag(tag)
1893 .and_then(|entry| entry.vr().exact())
1894 .unwrap_or(VR::FL);
1895 self.put(DataElement::new(tag, vr, PrimitiveValue::from(number)));
1897 Ok(())
1898 }
1899 }
1900
1901 fn apply_push_f64_impl(&mut self, tag: Tag, number: f64) -> ApplyResult {
1902 if let Some(e) = self.entries.remove(&tag) {
1903 let (header, value) = e.into_parts();
1904 match value {
1905 Value::Primitive(mut v) => {
1906 v.extend_f64([number]).context(ModifySnafu)?;
1908 self.put(DataElement::new(tag, header.vr, v));
1910 Ok(())
1911 }
1912
1913 Value::PixelSequence(..) => IncompatibleTypesSnafu {
1914 kind: ValueType::PixelSequence,
1915 }
1916 .fail(),
1917 Value::Sequence(..) => IncompatibleTypesSnafu {
1918 kind: ValueType::DataSetSequence,
1919 }
1920 .fail(),
1921 }
1922 } else {
1923 let vr = dicom_dictionary_std::StandardDataDictionary
1925 .by_tag(tag)
1926 .and_then(|entry| entry.vr().exact())
1927 .unwrap_or(VR::FD);
1928 self.put(DataElement::new(tag, vr, PrimitiveValue::from(number)));
1930 Ok(())
1931 }
1932 }
1933
1934 pub fn write_dataset<W, E>(&self, to: W, encoder: E) -> Result<(), WriteError>
1952 where
1953 W: Write,
1954 E: EncodeTo<W>,
1955 {
1956 let mut dset_writer = DataSetWriter::new(to, encoder);
1958 let required_options = IntoTokensOptions::new(self.charset_changed);
1959 dset_writer
1961 .write_sequence(self.into_tokens_with_options(required_options))
1962 .context(PrintDataSetSnafu)?;
1963
1964 Ok(())
1965 }
1966
1967 pub fn write_dataset_with_ts_cs<W>(
1978 &self,
1979 to: W,
1980 ts: &TransferSyntax,
1981 cs: SpecificCharacterSet,
1982 ) -> Result<(), WriteError>
1983 where
1984 W: Write,
1985 {
1986 if let Codec::Dataset(Some(adapter)) = ts.codec() {
1987 let adapter = adapter.adapt_writer(Box::new(to));
1988 let mut dset_writer =
1990 DataSetWriter::with_ts(adapter, ts).context(CreatePrinterSnafu)?;
1991
1992 dset_writer
1994 .write_sequence(self.into_tokens())
1995 .context(PrintDataSetSnafu)?;
1996
1997 Ok(())
1998 } else {
1999 let mut dset_writer =
2001 DataSetWriter::with_ts_cs(to, ts, cs).context(CreatePrinterSnafu)?;
2002
2003 dset_writer
2005 .write_sequence(self.into_tokens())
2006 .context(PrintDataSetSnafu)?;
2007
2008 Ok(())
2009 }
2010 }
2011
2012 pub fn write_dataset_with_ts_cs_options<W>(
2020 &self,
2021 to: W,
2022 ts: &TransferSyntax,
2023 cs: SpecificCharacterSet,
2024 options: DataSetWriterOptions,
2025 ) -> Result<(), WriteError>
2026 where
2027 W: Write,
2028 {
2029 let mut dset_writer =
2031 DataSetWriter::with_ts_cs_options(to, ts, cs, options).context(CreatePrinterSnafu)?;
2032 let required_options = IntoTokensOptions::new(self.charset_changed);
2033
2034 dset_writer
2036 .write_sequence(self.into_tokens_with_options(required_options))
2037 .context(PrintDataSetSnafu)?;
2038
2039 Ok(())
2040 }
2041
2042 pub fn write_dataset_with_ts<W>(&self, to: W, ts: &TransferSyntax) -> Result<(), WriteError>
2053 where
2054 W: Write,
2055 {
2056 self.write_dataset_with_ts_cs(to, ts, SpecificCharacterSet::default())
2057 }
2058
2059 pub fn write_dataset_with_ts_options<W>(
2067 &self,
2068 to: W,
2069 ts: &TransferSyntax,
2070 options: DataSetWriterOptions,
2071 ) -> Result<(), WriteError>
2072 where
2073 W: Write,
2074 {
2075 self.write_dataset_with_ts_cs_options(to, ts, SpecificCharacterSet::default(), options)
2076 }
2077
2078 pub fn with_exact_meta(self, meta: FileMetaTable) -> FileDicomObject<Self> {
2087 FileDicomObject { meta, obj: self }
2088 }
2089
2090 pub fn with_meta(
2123 self,
2124 mut meta: FileMetaTableBuilder,
2125 ) -> Result<FileDicomObject<Self>, WithMetaError> {
2126 if let Some(elem) = self.get(tags::SOP_INSTANCE_UID) {
2127 meta = meta.media_storage_sop_instance_uid(
2128 elem.value().to_str().context(PrepareMetaTableSnafu)?,
2129 );
2130 }
2131 if let Some(elem) = self.get(tags::SOP_CLASS_UID) {
2132 meta = meta
2133 .media_storage_sop_class_uid(elem.value().to_str().context(PrepareMetaTableSnafu)?);
2134 }
2135 Ok(FileDicomObject {
2136 meta: meta.build().context(BuildMetaTableSnafu)?,
2137 obj: self,
2138 })
2139 }
2140
2141 pub fn iter(&self) -> impl Iterator<Item = &InMemElement<D>> + '_ {
2143 self.into_iter()
2144 }
2145
2146 pub fn tags(&self) -> impl Iterator<Item = Tag> + '_ {
2148 self.entries.keys().copied()
2149 }
2150
2151 fn build_object<I>(
2155 dataset: &mut I,
2156 dict: D,
2157 in_item: bool,
2158 len: Length,
2159 read_until: Option<Tag>,
2160 read_to: Option<Tag>,
2161 ) -> Result<Self, ReadError>
2162 where
2163 I: ?Sized + Iterator<Item = ParserResult<DataToken>>,
2164 {
2165 let mut entries: BTreeMap<Tag, InMemElement<D>> = BTreeMap::new();
2166 while let Some(token) = dataset.next() {
2168 let elem = match token.context(ReadTokenSnafu)? {
2169 DataToken::PixelSequenceStart => {
2170 let sq_start_tag = Tag(0x7fe0, 0x0010);
2171 if read_until.map(|t| t <= sq_start_tag).unwrap_or(false) {
2173 break;
2174 }
2175 if read_to.map(|t| t < sq_start_tag).unwrap_or(false) {
2177 break;
2178 }
2179 let value = InMemDicomObject::build_encapsulated_data(&mut *dataset)?;
2180 DataElement::new(sq_start_tag, VR::OB, value)
2181 }
2182 DataToken::ElementHeader(header) => {
2183 if read_until.map(|t| t <= header.tag).unwrap_or(false) {
2185 break;
2186 }
2187 if read_to.map(|t| t < header.tag).unwrap_or(false) {
2189 break;
2190 }
2191
2192 let next_token = dataset.next().context(MissingElementValueSnafu)?;
2194 match next_token.context(ReadTokenSnafu)? {
2195 DataToken::PrimitiveValue(v) => InMemElement::new_with_len(
2196 header.tag,
2197 header.vr,
2198 header.len,
2199 Value::Primitive(v),
2200 ),
2201 token => {
2202 return UnexpectedTokenSnafu { token }.fail();
2203 }
2204 }
2205 }
2206 DataToken::SequenceStart { tag, len } => {
2207 if read_until.map(|t| t <= tag).unwrap_or(false) {
2209 break;
2210 }
2211 if read_to.map(|t| t < tag).unwrap_or(false) {
2213 break;
2214 }
2215
2216 let items = Self::build_sequence(tag, len, &mut *dataset, &dict)?;
2218 DataElement::new_with_len(
2219 tag,
2220 VR::SQ,
2221 len,
2222 Value::Sequence(DataSetSequence::new(items, len)),
2223 )
2224 }
2225 DataToken::ItemEnd if in_item => {
2226 return Ok(InMemDicomObject {
2228 entries,
2229 dict,
2230 len,
2231 charset_changed: false,
2232 });
2233 }
2234 token => return UnexpectedTokenSnafu { token }.fail(),
2235 };
2236 entries.insert(elem.tag(), elem);
2237 }
2238
2239 Ok(InMemDicomObject {
2240 entries,
2241 dict,
2242 len,
2243 charset_changed: false,
2244 })
2245 }
2246
2247 fn build_encapsulated_data<I>(
2250 dataset: I,
2251 ) -> Result<Value<InMemDicomObject<D>, InMemFragment>, ReadError>
2252 where
2253 I: Iterator<Item = ParserResult<DataToken>>,
2254 {
2255 let mut offset_table = None;
2260
2261 let mut fragments = C::new();
2262
2263 for token in dataset {
2264 match token.context(ReadTokenSnafu)? {
2265 DataToken::OffsetTable(table) => {
2266 offset_table = Some(table);
2267 }
2268 DataToken::ItemValue(data) => {
2269 fragments.push(data);
2270 }
2271 DataToken::ItemEnd => {
2272 if offset_table.is_none() {
2276 offset_table = Some(Vec::new())
2277 }
2278 }
2279 DataToken::ItemStart { len: _ } => { }
2280 DataToken::SequenceEnd => {
2281 break;
2283 }
2284 token @ DataToken::ElementHeader(_)
2286 | token @ DataToken::PixelSequenceStart
2287 | token @ DataToken::SequenceStart { .. }
2288 | token @ DataToken::PrimitiveValue(_) => {
2289 return UnexpectedTokenSnafu { token }.fail();
2290 }
2291 }
2292 }
2293
2294 Ok(Value::PixelSequence(PixelFragmentSequence::new(
2295 offset_table.unwrap_or_default(),
2296 fragments,
2297 )))
2298 }
2299
2300 fn build_sequence<I>(
2302 _tag: Tag,
2303 _len: Length,
2304 dataset: &mut I,
2305 dict: &D,
2306 ) -> Result<C<InMemDicomObject<D>>, ReadError>
2307 where
2308 I: ?Sized + Iterator<Item = ParserResult<DataToken>>,
2309 {
2310 let mut items: C<_> = SmallVec::new();
2311 while let Some(token) = dataset.next() {
2312 match token.context(ReadTokenSnafu)? {
2313 DataToken::ItemStart { len } => {
2314 items.push(Self::build_object(
2315 &mut *dataset,
2316 dict.clone(),
2317 true,
2318 len,
2319 None,
2320 None,
2321 )?);
2322 }
2323 DataToken::SequenceEnd => {
2324 return Ok(items);
2325 }
2326 token => return UnexpectedTokenSnafu { token }.fail(),
2327 };
2328 }
2329
2330 PrematureEndSnafu.fail()
2332 }
2333
2334 fn lookup_name(&self, name: &str) -> Result<Tag, AccessByNameError> {
2335 self.dict
2336 .by_name(name)
2337 .context(NoSuchAttributeNameSnafu { name })
2338 .map(|e| e.tag())
2339 }
2340}
2341
2342impl<D> ApplyOp for InMemDicomObject<D>
2343where
2344 D: DataDictionary,
2345 D: Clone,
2346{
2347 type Err = ApplyError;
2348
2349 #[inline]
2350 fn apply(&mut self, op: AttributeOp) -> ApplyResult {
2351 self.apply(op)
2352 }
2353}
2354
2355impl<'a, D> IntoIterator for &'a InMemDicomObject<D> {
2356 type Item = &'a InMemElement<D>;
2357 type IntoIter = ::std::collections::btree_map::Values<'a, Tag, InMemElement<D>>;
2358
2359 fn into_iter(self) -> Self::IntoIter {
2360 self.entries.values()
2361 }
2362}
2363
2364impl<D> IntoIterator for InMemDicomObject<D> {
2365 type Item = InMemElement<D>;
2366 type IntoIter = Iter<D>;
2367
2368 fn into_iter(self) -> Self::IntoIter {
2369 Iter {
2370 inner: self.entries.into_iter(),
2371 }
2372 }
2373}
2374
2375#[derive(Debug)]
2377pub struct Iter<D> {
2378 inner: ::std::collections::btree_map::IntoIter<Tag, InMemElement<D>>,
2379}
2380
2381impl<D> Iterator for Iter<D> {
2382 type Item = InMemElement<D>;
2383
2384 fn next(&mut self) -> Option<Self::Item> {
2385 self.inner.next().map(|x| x.1)
2386 }
2387
2388 fn size_hint(&self) -> (usize, Option<usize>) {
2389 self.inner.size_hint()
2390 }
2391
2392 fn count(self) -> usize {
2393 self.inner.count()
2394 }
2395}
2396
2397impl<D> Extend<InMemElement<D>> for InMemDicomObject<D> {
2398 fn extend<I>(&mut self, iter: I)
2399 where
2400 I: IntoIterator<Item = InMemElement<D>>,
2401 {
2402 self.len = Length::UNDEFINED;
2403 self.entries.extend(iter.into_iter().map(|e| (e.tag(), e)))
2404 }
2405}
2406
2407fn even_len(l: u32) -> u32 {
2408 (l + 1) & !1
2409}
2410
2411#[cfg(test)]
2412mod tests {
2413 use super::*;
2414 use crate::{DicomAttribute as _, open_file};
2415 use byteordered::Endianness;
2416 use dicom_core::chrono::FixedOffset;
2417 use dicom_core::value::{DicomDate, DicomDateTime, DicomTime};
2418 use dicom_core::{dicom_value, header::DataElementHeader};
2419 use dicom_encoding::{
2420 decode::{basic::BasicDecoder, implicit_le::ImplicitVRLittleEndianDecoder},
2421 encode::{EncoderFor, implicit_le::ImplicitVRLittleEndianEncoder},
2422 };
2423 use dicom_parser::StatefulDecoder;
2424
2425 fn assert_obj_eq<D>(obj1: &InMemDicomObject<D>, obj2: &InMemDicomObject<D>)
2426 where
2427 D: std::fmt::Debug,
2428 {
2429 assert_eq!(format!("{obj1:?}"), format!("{:?}", obj2))
2432 }
2433
2434 #[test]
2435 fn inmem_object_compare() {
2436 let mut obj1 = InMemDicomObject::new_empty();
2437 let mut obj2 = InMemDicomObject::new_empty();
2438 assert_eq!(obj1, obj2);
2439 let empty_patient_name = DataElement::empty(Tag(0x0010, 0x0010), VR::PN);
2440 obj1.put(empty_patient_name.clone());
2441 assert_ne!(obj1, obj2);
2442 obj2.put(empty_patient_name.clone());
2443 assert_obj_eq(&obj1, &obj2);
2444 }
2445
2446 #[test]
2447 fn inmem_object_read_dataset() {
2448 let data_in = [
2449 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2452 ];
2453
2454 let decoder = ImplicitVRLittleEndianDecoder::default();
2455 let text = SpecificCharacterSet::default();
2456 let mut cursor = &data_in[..];
2457 let parser = StatefulDecoder::new(
2458 &mut cursor,
2459 decoder,
2460 BasicDecoder::new(Endianness::Little),
2461 text,
2462 );
2463
2464 let obj = InMemDicomObject::read_dataset(parser).unwrap();
2465
2466 let mut gt = InMemDicomObject::new_empty();
2467
2468 let patient_name = DataElement::new(
2469 Tag(0x0010, 0x0010),
2470 VR::PN,
2471 dicom_value!(Strs, ["Doe^John"]),
2472 );
2473 gt.put(patient_name);
2474
2475 assert_eq!(obj, gt);
2476 }
2477
2478 #[test]
2479 fn inmem_object_read_dataset_with_ts_cs() {
2480 let data_in = [
2481 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2484 ];
2485
2486 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2").unwrap();
2487 let cs = SpecificCharacterSet::default();
2488 let mut cursor = &data_in[..];
2489
2490 let obj = InMemDicomObject::read_dataset_with_dict_ts_cs(
2491 &mut cursor,
2492 StandardDataDictionary,
2493 ts,
2494 cs,
2495 )
2496 .unwrap();
2497
2498 let mut gt = InMemDicomObject::new_empty();
2499
2500 let patient_name = DataElement::new(
2501 Tag(0x0010, 0x0010),
2502 VR::PN,
2503 dicom_value!(Strs, ["Doe^John"]),
2504 );
2505 gt.put(patient_name);
2506
2507 assert_eq!(obj, gt);
2508 }
2509
2510 #[test]
2513 fn inmem_object_read_dataset_saves_len() {
2514 let data_in = [
2515 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',
2520 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,
2524 b'o', b' ',
2525 ];
2526
2527 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2").unwrap();
2528 let mut cursor = &data_in[..];
2529
2530 let obj =
2531 InMemDicomObject::read_dataset_with_dict_ts(&mut cursor, StandardDataDictionary, ts)
2532 .unwrap();
2533
2534 let physician_name = obj.element(Tag(0x0008, 0x0090)).unwrap();
2535 assert_eq!(physician_name.header().len, Length(12));
2536 assert_eq!(physician_name.value().to_str().unwrap(), "Simões^João");
2537 }
2538
2539 #[test]
2540 fn inmem_object_write_dataset() {
2541 let mut obj = InMemDicomObject::new_empty();
2542
2543 let patient_name =
2544 DataElement::new(Tag(0x0010, 0x0010), VR::PN, dicom_value!(Str, "Doe^John"));
2545 obj.put(patient_name);
2546
2547 let mut out = Vec::new();
2548
2549 let printer = EncoderFor::new(ImplicitVRLittleEndianEncoder::default());
2550
2551 obj.write_dataset(&mut out, printer).unwrap();
2552
2553 assert_eq!(
2554 out,
2555 &[
2556 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2559 ][..],
2560 );
2561 }
2562
2563 #[test]
2564 fn inmem_object_write_dataset_with_ts() {
2565 let mut obj = InMemDicomObject::new_empty();
2566
2567 let patient_name =
2568 DataElement::new(Tag(0x0010, 0x0010), VR::PN, dicom_value!(Str, "Doe^John"));
2569 obj.put(patient_name);
2570
2571 let mut out = Vec::new();
2572
2573 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2.1").unwrap();
2574
2575 obj.write_dataset_with_ts(&mut out, ts).unwrap();
2576
2577 assert_eq!(
2578 out,
2579 &[
2580 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',
2584 ][..],
2585 );
2586 }
2587
2588 #[test]
2589 fn inmem_object_write_dataset_encapsulated_pixel_data() {
2590 let mut obj = InMemDicomObject::new_empty();
2591
2592 let sop_instance_uid = DataElement::new(
2593 tags::SOP_INSTANCE_UID,
2594 VR::UI,
2595 "2.25.44399302050596340528032699331187776010",
2596 );
2597 obj.put(sop_instance_uid);
2598
2599 obj.put(DataElement::new(
2600 tags::PIXEL_DATA,
2601 VR::OB,
2602 PixelFragmentSequence::new_fragments([
2603 vec![0x01, 0x02, 0x03, 0x04],
2604 vec![0x05, 0x06, 0x07, 0x08],
2605 ]),
2606 ));
2607
2608 let mut out = Vec::new();
2609
2610 let ts = TransferSyntaxRegistry
2611 .get(uids::ENCAPSULATED_UNCOMPRESSED_EXPLICIT_VR_LITTLE_ENDIAN)
2612 .unwrap();
2613
2614 obj.write_dataset_with_ts(&mut out, ts).unwrap();
2615
2616 assert_eq!(
2617 out,
2618 &[
2619 0x08, 0x00, 0x18, 0x00, b'U', b'I', 0x2c, 0x00, b'2', b'.', b'2', b'5', b'.', b'4', b'4', b'3', b'9', b'9', b'3', b'0', b'2', b'0',
2624 b'5', b'0', b'5', b'9', b'6', b'3', b'4', b'0', b'5', b'2', b'8', b'0', b'3', b'2',
2625 b'6', b'9', b'9', b'3', b'3', b'1', b'1', b'8', b'7', b'7', b'7', b'6', b'0', b'1',
2626 b'0', b'\0', 0xe0, 0x7f, 0x10, 0x00, b'O', b'B', 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xfe, 0xff, 0x00, 0xe0, 0x00, 0x00, 0x00, 0x00, 0xfe, 0xff, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x00, 0x01, 0x02, 0x03, 0x04, 0xfe, 0xff, 0x00, 0xe0, 0x04, 0x00, 0x00, 0x00, 0x05, 0x06, 0x07, 0x08, 0xfe, 0xff, 0xdd, 0xe0, 0x00, 0x00, 0x00, 0x00, ][..],
2640 );
2641 }
2642
2643 #[test]
2644 fn inmem_object_write_dataset_with_ts_cs() {
2645 let mut obj = InMemDicomObject::new_empty();
2646
2647 let patient_name =
2648 DataElement::new(Tag(0x0010, 0x0010), VR::PN, dicom_value!(Str, "Doe^John"));
2649 obj.put(patient_name);
2650
2651 let mut out = Vec::new();
2652
2653 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2").unwrap();
2654 let cs = SpecificCharacterSet::default();
2655
2656 obj.write_dataset_with_ts_cs(&mut out, ts, cs).unwrap();
2657
2658 assert_eq!(
2659 out,
2660 &[
2661 0x10, 0x00, 0x10, 0x00, 0x08, 0x00, 0x00, 0x00, b'D', b'o', b'e', b'^', b'J', b'o', b'h', b'n',
2664 ][..],
2665 );
2666 }
2667
2668 #[test]
2671 fn inmem_object_write_datetime_odd() {
2672 let mut obj = InMemDicomObject::new_empty();
2673
2674 let instance_number =
2676 DataElement::new(Tag(0x0020, 0x0013), VR::IS, PrimitiveValue::from(1_i32));
2677 obj.put(instance_number);
2678
2679 let dt = DicomDateTime::from_date_and_time_with_time_zone(
2681 DicomDate::from_ymd(2022, 11, 22).unwrap(),
2682 DicomTime::from_hms(18, 9, 35).unwrap(),
2683 FixedOffset::east_opt(3600).unwrap(),
2684 )
2685 .unwrap();
2686 let instance_coercion_date_time =
2687 DataElement::new(Tag(0x0008, 0x0015), VR::DT, dicom_value!(DateTime, dt));
2688 obj.put(instance_coercion_date_time);
2689
2690 let ts = TransferSyntaxRegistry.get("1.2.840.10008.1.2.1").unwrap();
2692
2693 let mut out = Vec::new();
2694 obj.write_dataset_with_ts(&mut out, ts)
2695 .expect("should write DICOM data without errors");
2696
2697 assert_eq!(
2698 out,
2699 &[
2700 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' ' ][..],
2714 );
2715 }
2716
2717 #[test]
2720 fn inmem_write_to_file_with_meta() {
2721 let sop_uid = "1.4.645.212121";
2722 let mut obj = InMemDicomObject::new_empty();
2723
2724 obj.put(DataElement::new(
2725 Tag(0x0010, 0x0010),
2726 VR::PN,
2727 dicom_value!(Strs, ["Doe^John"]),
2728 ));
2729 obj.put(DataElement::new(
2730 Tag(0x0008, 0x0060),
2731 VR::CS,
2732 dicom_value!(Strs, ["CR"]),
2733 ));
2734 obj.put(DataElement::new(
2735 Tag(0x0008, 0x0018),
2736 VR::UI,
2737 dicom_value!(Strs, [sop_uid]),
2738 ));
2739
2740 let file_object = obj
2741 .with_meta(
2742 FileMetaTableBuilder::default()
2743 .transfer_syntax("1.2.840.10008.1.2.1")
2745 .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.1")
2747 .media_storage_sop_instance_uid(sop_uid),
2748 )
2749 .unwrap();
2750
2751 let dir = tempfile::tempdir().unwrap();
2753 let mut file_path = dir.keep();
2754 file_path.push(format!("{sop_uid}.dcm"));
2755
2756 file_object.write_to_file(&file_path).unwrap();
2757
2758 let saved_object = open_file(file_path).unwrap();
2760 assert_eq!(file_object, saved_object);
2761 }
2762
2763 #[test]
2766 fn inmem_with_meta_infers_sop_instance_uid() {
2767 let sop_uid = "1.4.645.252521";
2768 let mut obj = InMemDicomObject::new_empty();
2769
2770 obj.put(DataElement::new(
2771 tags::SOP_INSTANCE_UID,
2772 VR::UI,
2773 PrimitiveValue::from(sop_uid),
2774 ));
2775
2776 let file_object = obj
2777 .with_meta(
2778 FileMetaTableBuilder::default()
2780 .transfer_syntax("1.2.840.10008.1.2.1")
2782 .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.1"),
2784 )
2785 .unwrap();
2786
2787 let meta = file_object.meta();
2788
2789 assert_eq!(
2790 meta.media_storage_sop_instance_uid.trim_end_matches('\0'),
2791 sop_uid.trim_end_matches('\0'),
2792 );
2793 }
2794
2795 #[test]
2797 fn inmem_write_to_file_with_exact_meta() {
2798 let sop_uid = "1.4.645.212121";
2799 let mut obj = InMemDicomObject::new_empty();
2800
2801 obj.put(DataElement::new(
2802 Tag(0x0010, 0x0010),
2803 VR::PN,
2804 dicom_value!(Strs, ["Doe^John"]),
2805 ));
2806 obj.put(DataElement::new(
2807 Tag(0x0008, 0x0060),
2808 VR::CS,
2809 dicom_value!(Strs, ["CR"]),
2810 ));
2811 obj.put(DataElement::new(
2812 Tag(0x0008, 0x0018),
2813 VR::UI,
2814 dicom_value!(Strs, [sop_uid]),
2815 ));
2816
2817 let file_object = obj.with_exact_meta(
2818 FileMetaTableBuilder::default()
2819 .transfer_syntax("1.2.840.10008.1.2.1")
2821 .media_storage_sop_class_uid("1.2.840.10008.5.1.4.1.1.1")
2823 .media_storage_sop_instance_uid(sop_uid)
2824 .build()
2825 .unwrap(),
2826 );
2827
2828 let dir = tempfile::tempdir().unwrap();
2830 let mut file_path = dir.keep();
2831 file_path.push(format!("{sop_uid}.dcm"));
2832
2833 file_object.write_to_file(&file_path).unwrap();
2834
2835 let saved_object = open_file(file_path).unwrap();
2837 assert_eq!(file_object, saved_object);
2838 }
2839
2840 #[test]
2841 fn inmem_object_get() {
2842 let another_patient_name = DataElement::new(
2843 Tag(0x0010, 0x0010),
2844 VR::PN,
2845 PrimitiveValue::Str("Doe^John".to_string()),
2846 );
2847 let mut obj = InMemDicomObject::new_empty();
2848 obj.put(another_patient_name.clone());
2849 let elem1 = obj.element(Tag(0x0010, 0x0010)).unwrap();
2850 assert_eq!(elem1, &another_patient_name);
2851 }
2852
2853 #[test]
2854 fn infer_media_sop_from_dataset_sop_elements() {
2855 let sop_instance_uid = "1.4.645.313131";
2856 let sop_class_uid = "1.2.840.10008.5.1.4.1.1.2";
2857 let mut obj = InMemDicomObject::new_empty();
2858
2859 obj.put(DataElement::new(
2860 Tag(0x0008, 0x0018),
2861 VR::UI,
2862 dicom_value!(Strs, [sop_instance_uid]),
2863 ));
2864 obj.put(DataElement::new(
2865 Tag(0x0008, 0x0016),
2866 VR::UI,
2867 dicom_value!(Strs, [sop_class_uid]),
2868 ));
2869
2870 let file_object = obj.with_exact_meta(
2871 FileMetaTableBuilder::default()
2872 .transfer_syntax("1.2.840.10008.1.2.1")
2873 .media_storage_sop_class_uid("")
2875 .media_storage_sop_instance_uid("")
2876 .build()
2877 .unwrap(),
2878 );
2879
2880 let dir = tempfile::tempdir().unwrap();
2882 let mut file_path = dir.keep();
2883 file_path.push(format!("{sop_instance_uid}.dcm"));
2884
2885 file_object.write_to_file(&file_path).unwrap();
2886
2887 let saved_object = open_file(file_path).unwrap();
2889
2890 assert_eq!(
2892 saved_object.meta().media_storage_sop_instance_uid(),
2893 sop_instance_uid
2894 );
2895 assert_eq!(
2896 saved_object.meta().media_storage_sop_class_uid(),
2897 sop_class_uid
2898 );
2899 }
2900
2901 #[test]
2902 fn inmem_object_get_opt() {
2903 let another_patient_name = DataElement::new(
2904 Tag(0x0010, 0x0010),
2905 VR::PN,
2906 PrimitiveValue::Str("Doe^John".to_string()),
2907 );
2908 let mut obj = InMemDicomObject::new_empty();
2909 obj.put(another_patient_name.clone());
2910 let elem1 = obj.element_opt(Tag(0x0010, 0x0010)).unwrap();
2911 assert_eq!(elem1, Some(&another_patient_name));
2912
2913 assert_eq!(obj.element_opt(Tag(0x0010, 0x0020)).unwrap(), None);
2915 }
2916
2917 #[test]
2918 fn inmem_object_get_by_name() {
2919 let another_patient_name = DataElement::new(
2920 Tag(0x0010, 0x0010),
2921 VR::PN,
2922 PrimitiveValue::Str("Doe^John".to_string()),
2923 );
2924 let mut obj = InMemDicomObject::new_empty();
2925 obj.put(another_patient_name.clone());
2926 let elem1 = obj.element_by_name("PatientName").unwrap();
2927 assert_eq!(elem1, &another_patient_name);
2928 }
2929
2930 #[test]
2931 fn inmem_object_get_by_name_opt() {
2932 let another_patient_name = DataElement::new(
2933 Tag(0x0010, 0x0010),
2934 VR::PN,
2935 PrimitiveValue::Str("Doe^John".to_string()),
2936 );
2937 let mut obj = InMemDicomObject::new_empty();
2938 obj.put(another_patient_name.clone());
2939 let elem1 = obj.element_by_name_opt("PatientName").unwrap();
2940 assert_eq!(elem1, Some(&another_patient_name));
2941
2942 assert_eq!(obj.element_by_name_opt("PatientID").unwrap(), None);
2944 }
2945
2946 #[test]
2947 fn inmem_object_take_element() {
2948 let another_patient_name = DataElement::new(
2949 Tag(0x0010, 0x0010),
2950 VR::PN,
2951 PrimitiveValue::Str("Doe^John".to_string()),
2952 );
2953 let mut obj = InMemDicomObject::new_empty();
2954 obj.put(another_patient_name.clone());
2955 let elem1 = obj.take_element(Tag(0x0010, 0x0010)).unwrap();
2956 assert_eq!(elem1, another_patient_name);
2957 assert!(matches!(
2958 obj.take_element(Tag(0x0010, 0x0010)),
2959 Err(AccessError::NoSuchDataElementTag {
2960 tag: Tag(0x0010, 0x0010),
2961 ..
2962 })
2963 ));
2964 }
2965
2966 #[test]
2967 fn inmem_object_take_element_by_name() {
2968 let another_patient_name = DataElement::new(
2969 Tag(0x0010, 0x0010),
2970 VR::PN,
2971 PrimitiveValue::Str("Doe^John".to_string()),
2972 );
2973 let mut obj = InMemDicomObject::new_empty();
2974 obj.put(another_patient_name.clone());
2975 let elem1 = obj.take_element_by_name("PatientName").unwrap();
2976 assert_eq!(elem1, another_patient_name);
2977 assert!(matches!(
2978 obj.take_element_by_name("PatientName"),
2979 Err(AccessByNameError::NoSuchDataElementAlias {
2980 tag: Tag(0x0010, 0x0010),
2981 alias,
2982 ..
2983 }) if alias == "PatientName"));
2984 }
2985
2986 #[test]
2987 fn inmem_object_remove_element() {
2988 let another_patient_name = DataElement::new(
2989 Tag(0x0010, 0x0010),
2990 VR::PN,
2991 PrimitiveValue::Str("Doe^John".to_string()),
2992 );
2993 let mut obj = InMemDicomObject::new_empty();
2994 obj.put(another_patient_name.clone());
2995 assert!(obj.remove_element(Tag(0x0010, 0x0010)));
2996 assert!(!obj.remove_element(Tag(0x0010, 0x0010)));
2997 }
2998
2999 #[test]
3000 fn inmem_object_remove_element_by_name() {
3001 let another_patient_name = DataElement::new(
3002 Tag(0x0010, 0x0010),
3003 VR::PN,
3004 PrimitiveValue::Str("Doe^John".to_string()),
3005 );
3006 let mut obj = InMemDicomObject::new_empty();
3007 obj.put(another_patient_name.clone());
3008 assert!(obj.remove_element_by_name("PatientName").unwrap());
3009 assert!(!obj.remove_element_by_name("PatientName").unwrap());
3010 }
3011
3012 #[test]
3014 fn inmem_traverse_elements() {
3015 let sop_uid = "1.4.645.212121";
3016 let mut obj = InMemDicomObject::new_empty();
3017
3018 obj.put(DataElement::new(
3019 Tag(0x0010, 0x0010),
3020 VR::PN,
3021 dicom_value!(Strs, ["Doe^John"]),
3022 ));
3023 obj.put(DataElement::new(
3024 Tag(0x0008, 0x0060),
3025 VR::CS,
3026 dicom_value!(Strs, ["CR"]),
3027 ));
3028 obj.put(DataElement::new(
3029 Tag(0x0008, 0x0018),
3030 VR::UI,
3031 dicom_value!(Strs, [sop_uid]),
3032 ));
3033
3034 {
3035 let mut iter = obj.iter();
3036 assert_eq!(
3037 *iter.next().unwrap().header(),
3038 DataElementHeader::new(Tag(0x0008, 0x0018), VR::UI, Length(sop_uid.len() as u32)),
3039 );
3040 assert_eq!(
3041 *iter.next().unwrap().header(),
3042 DataElementHeader::new(Tag(0x0008, 0x0060), VR::CS, Length(2)),
3043 );
3044 assert_eq!(
3045 *iter.next().unwrap().header(),
3046 DataElementHeader::new(Tag(0x0010, 0x0010), VR::PN, Length(8)),
3047 );
3048 }
3049
3050 let tags: Vec<_> = obj.tags().collect();
3052 assert_eq!(
3053 tags,
3054 vec![
3055 Tag(0x0008, 0x0018),
3056 Tag(0x0008, 0x0060),
3057 Tag(0x0010, 0x0010),
3058 ]
3059 );
3060
3061 let mut iter = obj.into_iter();
3063 assert_eq!(
3064 iter.next(),
3065 Some(DataElement::new(
3066 Tag(0x0008, 0x0018),
3067 VR::UI,
3068 dicom_value!(Strs, [sop_uid]),
3069 )),
3070 );
3071 assert_eq!(
3072 iter.next(),
3073 Some(DataElement::new(
3074 Tag(0x0008, 0x0060),
3075 VR::CS,
3076 dicom_value!(Strs, ["CR"]),
3077 )),
3078 );
3079 assert_eq!(
3080 iter.next(),
3081 Some(DataElement::new(
3082 Tag(0x0010, 0x0010),
3083 VR::PN,
3084 PrimitiveValue::from("Doe^John"),
3085 )),
3086 );
3087 }
3088
3089 #[test]
3090 fn inmem_empty_object_into_tokens() {
3091 let obj = InMemDicomObject::new_empty();
3092 let tokens = obj.into_tokens();
3093 assert_eq!(tokens.count(), 0);
3094 }
3095
3096 #[test]
3097 fn inmem_shallow_object_from_tokens() {
3098 let tokens = vec![
3099 DataToken::ElementHeader(DataElementHeader {
3100 tag: Tag(0x0008, 0x0060),
3101 vr: VR::CS,
3102 len: Length(2),
3103 }),
3104 DataToken::PrimitiveValue(PrimitiveValue::Str("MG".to_owned())),
3105 DataToken::ElementHeader(DataElementHeader {
3106 tag: Tag(0x0010, 0x0010),
3107 vr: VR::PN,
3108 len: Length(8),
3109 }),
3110 DataToken::PrimitiveValue(PrimitiveValue::Str("Doe^John".to_owned())),
3111 ];
3112
3113 let gt_obj = InMemDicomObject::from_element_iter(vec![
3114 DataElement::new(
3115 Tag(0x0010, 0x0010),
3116 VR::PN,
3117 PrimitiveValue::Str("Doe^John".to_string()),
3118 ),
3119 DataElement::new(
3120 Tag(0x0008, 0x0060),
3121 VR::CS,
3122 PrimitiveValue::Str("MG".to_string()),
3123 ),
3124 ]);
3125
3126 let obj = InMemDicomObject::build_object(
3127 &mut tokens.into_iter().map(Result::Ok),
3128 StandardDataDictionary,
3129 false,
3130 Length::UNDEFINED,
3131 None,
3132 None,
3133 )
3134 .unwrap();
3135
3136 assert_obj_eq(&obj, >_obj);
3137 }
3138
3139 #[test]
3140 fn inmem_shallow_object_into_tokens() {
3141 let patient_name = DataElement::new(
3142 Tag(0x0010, 0x0010),
3143 VR::PN,
3144 PrimitiveValue::Str("Doe^John".to_string()),
3145 );
3146 let modality = DataElement::new(
3147 Tag(0x0008, 0x0060),
3148 VR::CS,
3149 PrimitiveValue::Str("MG".to_string()),
3150 );
3151 let mut obj = InMemDicomObject::new_empty();
3152 obj.put(patient_name);
3153 obj.put(modality);
3154
3155 let tokens: Vec<_> = obj.into_tokens().collect();
3156
3157 assert_eq!(
3158 tokens,
3159 vec![
3160 DataToken::ElementHeader(DataElementHeader {
3161 tag: Tag(0x0008, 0x0060),
3162 vr: VR::CS,
3163 len: Length(2),
3164 }),
3165 DataToken::PrimitiveValue(PrimitiveValue::Str("MG".to_owned())),
3166 DataToken::ElementHeader(DataElementHeader {
3167 tag: Tag(0x0010, 0x0010),
3168 vr: VR::PN,
3169 len: Length(8),
3170 }),
3171 DataToken::PrimitiveValue(PrimitiveValue::Str("Doe^John".to_owned())),
3172 ]
3173 );
3174 }
3175
3176 #[test]
3177 fn inmem_deep_object_from_tokens() {
3178 use smallvec::smallvec;
3179
3180 let obj_1 = InMemDicomObject::from_element_iter(vec![
3181 DataElement::new(Tag(0x0018, 0x6012), VR::US, Value::Primitive(1_u16.into())),
3182 DataElement::new(Tag(0x0018, 0x6014), VR::US, Value::Primitive(2_u16.into())),
3183 ]);
3184
3185 let obj_2 = InMemDicomObject::from_element_iter(vec![DataElement::new(
3186 Tag(0x0018, 0x6012),
3187 VR::US,
3188 Value::Primitive(4_u16.into()),
3189 )]);
3190
3191 let gt_obj = InMemDicomObject::from_element_iter(vec![
3192 DataElement::new(
3193 Tag(0x0018, 0x6011),
3194 VR::SQ,
3195 Value::from(DataSetSequence::new(
3196 smallvec![obj_1, obj_2],
3197 Length::UNDEFINED,
3198 )),
3199 ),
3200 DataElement::new(Tag(0x0020, 0x4000), VR::LT, Value::Primitive("TEST".into())),
3201 ]);
3202
3203 let tokens: Vec<_> = vec![
3204 DataToken::SequenceStart {
3205 tag: Tag(0x0018, 0x6011),
3206 len: Length::UNDEFINED,
3207 },
3208 DataToken::ItemStart {
3209 len: Length::UNDEFINED,
3210 },
3211 DataToken::ElementHeader(DataElementHeader {
3212 tag: Tag(0x0018, 0x6012),
3213 vr: VR::US,
3214 len: Length(2),
3215 }),
3216 DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
3217 DataToken::ElementHeader(DataElementHeader {
3218 tag: Tag(0x0018, 0x6014),
3219 vr: VR::US,
3220 len: Length(2),
3221 }),
3222 DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
3223 DataToken::ItemEnd,
3224 DataToken::ItemStart {
3225 len: Length::UNDEFINED,
3226 },
3227 DataToken::ElementHeader(DataElementHeader {
3228 tag: Tag(0x0018, 0x6012),
3229 vr: VR::US,
3230 len: Length(2),
3231 }),
3232 DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
3233 DataToken::ItemEnd,
3234 DataToken::SequenceEnd,
3235 DataToken::ElementHeader(DataElementHeader {
3236 tag: Tag(0x0020, 0x4000),
3237 vr: VR::LT,
3238 len: Length(4),
3239 }),
3240 DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
3241 ];
3242
3243 let obj = InMemDicomObject::build_object(
3244 &mut tokens.into_iter().map(Result::Ok),
3245 StandardDataDictionary,
3246 false,
3247 Length::UNDEFINED,
3248 None,
3249 None,
3250 )
3251 .unwrap();
3252
3253 assert_obj_eq(&obj, >_obj);
3254 }
3255
3256 #[test]
3257 fn inmem_deep_object_into_tokens() {
3258 use smallvec::smallvec;
3259
3260 let obj_1 = InMemDicomObject::from_element_iter(vec![
3261 DataElement::new(Tag(0x0018, 0x6012), VR::US, Value::Primitive(1_u16.into())),
3262 DataElement::new(Tag(0x0018, 0x6014), VR::US, Value::Primitive(2_u16.into())),
3263 ]);
3264
3265 let obj_2 = InMemDicomObject::from_element_iter(vec![DataElement::new(
3266 Tag(0x0018, 0x6012),
3267 VR::US,
3268 Value::Primitive(4_u16.into()),
3269 )]);
3270
3271 let main_obj = InMemDicomObject::from_element_iter(vec![
3272 DataElement::new(
3273 Tag(0x0018, 0x6011),
3274 VR::SQ,
3275 Value::from(DataSetSequence::new(
3276 smallvec![obj_1, obj_2],
3277 Length::UNDEFINED,
3278 )),
3279 ),
3280 DataElement::new(Tag(0x0020, 0x4000), VR::LT, Value::Primitive("TEST".into())),
3281 ]);
3282
3283 let tokens: Vec<_> = main_obj.into_tokens().collect();
3284
3285 assert_eq!(
3286 tokens,
3287 vec![
3288 DataToken::SequenceStart {
3289 tag: Tag(0x0018, 0x6011),
3290 len: Length::UNDEFINED,
3291 },
3292 DataToken::ItemStart {
3293 len: Length::UNDEFINED,
3294 },
3295 DataToken::ElementHeader(DataElementHeader {
3296 tag: Tag(0x0018, 0x6012),
3297 vr: VR::US,
3298 len: Length(2),
3299 }),
3300 DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
3301 DataToken::ElementHeader(DataElementHeader {
3302 tag: Tag(0x0018, 0x6014),
3303 vr: VR::US,
3304 len: Length(2),
3305 }),
3306 DataToken::PrimitiveValue(PrimitiveValue::U16([2].as_ref().into())),
3307 DataToken::ItemEnd,
3308 DataToken::ItemStart {
3309 len: Length::UNDEFINED,
3310 },
3311 DataToken::ElementHeader(DataElementHeader {
3312 tag: Tag(0x0018, 0x6012),
3313 vr: VR::US,
3314 len: Length(2),
3315 }),
3316 DataToken::PrimitiveValue(PrimitiveValue::U16([4].as_ref().into())),
3317 DataToken::ItemEnd,
3318 DataToken::SequenceEnd,
3319 DataToken::ElementHeader(DataElementHeader {
3320 tag: Tag(0x0020, 0x4000),
3321 vr: VR::LT,
3322 len: Length(4),
3323 }),
3324 DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
3325 ]
3326 );
3327 }
3328
3329 #[test]
3330 fn inmem_encapsulated_pixel_data_from_tokens() {
3331 use smallvec::smallvec;
3332
3333 let gt_obj = InMemDicomObject::from_element_iter(vec![DataElement::new(
3334 Tag(0x7fe0, 0x0010),
3335 VR::OB,
3336 Value::from(PixelFragmentSequence::new_fragments(smallvec![vec![
3337 0x33;
3338 32
3339 ]])),
3340 )]);
3341
3342 let tokens: Vec<_> = vec![
3343 DataToken::PixelSequenceStart,
3344 DataToken::ItemStart { len: Length(0) },
3345 DataToken::ItemEnd,
3346 DataToken::ItemStart { len: Length(32) },
3347 DataToken::ItemValue(vec![0x33; 32]),
3348 DataToken::ItemEnd,
3349 DataToken::SequenceEnd,
3350 ];
3351
3352 let obj = InMemDicomObject::build_object(
3353 &mut tokens.into_iter().map(Result::Ok),
3354 StandardDataDictionary,
3355 false,
3356 Length::UNDEFINED,
3357 None,
3358 None,
3359 )
3360 .unwrap();
3361
3362 assert_obj_eq(&obj, >_obj);
3363 }
3364
3365 #[test]
3366 fn inmem_encapsulated_pixel_data_into_tokens() {
3367 use smallvec::smallvec;
3368
3369 let main_obj = InMemDicomObject::from_element_iter(vec![DataElement::new(
3370 Tag(0x7fe0, 0x0010),
3371 VR::OB,
3372 Value::from(PixelFragmentSequence::new_fragments(smallvec![vec![
3373 0x33;
3374 32
3375 ]])),
3376 )]);
3377
3378 let tokens: Vec<_> = main_obj.into_tokens().collect();
3379
3380 assert_eq!(
3381 tokens,
3382 vec![
3383 DataToken::PixelSequenceStart,
3384 DataToken::ItemStart { len: Length(0) },
3385 DataToken::ItemEnd,
3386 DataToken::ItemStart { len: Length(32) },
3387 DataToken::ItemValue(vec![0x33; 32]),
3388 DataToken::ItemEnd,
3389 DataToken::SequenceEnd,
3390 ]
3391 );
3392 }
3393
3394 #[test]
3397 fn can_use_behind_trait() {
3398 fn dicom_dataset() -> impl DicomObject {
3399 InMemDicomObject::from_element_iter([DataElement::new(
3400 tags::PATIENT_NAME,
3401 VR::PN,
3402 PrimitiveValue::Str("Doe^John".to_string()),
3403 )])
3404 }
3405
3406 let obj = dicom_dataset();
3407 let elem1 = obj
3408 .attr_by_name_opt("PatientName")
3409 .unwrap()
3410 .expect("PatientName should be present");
3411 assert_eq!(
3412 &elem1
3413 .to_str()
3414 .expect("should be able to retrieve patient name as string"),
3415 "Doe^John"
3416 );
3417
3418 assert!(obj.attr_opt(tags::PATIENT_ID).unwrap().is_none());
3420 }
3421
3422 #[test]
3424 fn inmem_ops() {
3425 let base_obj = InMemDicomObject::from_element_iter([
3427 DataElement::new(
3428 tags::SERIES_INSTANCE_UID,
3429 VR::UI,
3430 PrimitiveValue::from("2.25.137041794342168732369025909031346220736.1"),
3431 ),
3432 DataElement::new(
3433 tags::SERIES_INSTANCE_UID,
3434 VR::UI,
3435 PrimitiveValue::from("2.25.137041794342168732369025909031346220736.1"),
3436 ),
3437 DataElement::new(
3438 tags::SOP_INSTANCE_UID,
3439 VR::UI,
3440 PrimitiveValue::from("2.25.137041794342168732369025909031346220736.1.1"),
3441 ),
3442 DataElement::new(
3443 tags::STUDY_DESCRIPTION,
3444 VR::LO,
3445 PrimitiveValue::from("Test study"),
3446 ),
3447 DataElement::new(
3448 tags::INSTITUTION_NAME,
3449 VR::LO,
3450 PrimitiveValue::from("Test Hospital"),
3451 ),
3452 DataElement::new(tags::ROWS, VR::US, PrimitiveValue::from(768_u16)),
3453 DataElement::new(tags::COLUMNS, VR::US, PrimitiveValue::from(1024_u16)),
3454 DataElement::new(
3455 tags::LOSSY_IMAGE_COMPRESSION,
3456 VR::CS,
3457 PrimitiveValue::from("01"),
3458 ),
3459 DataElement::new(
3460 tags::LOSSY_IMAGE_COMPRESSION_RATIO,
3461 VR::DS,
3462 PrimitiveValue::from("5"),
3463 ),
3464 DataElement::new(
3465 tags::LOSSY_IMAGE_COMPRESSION_METHOD,
3466 VR::DS,
3467 PrimitiveValue::from("ISO_10918_1"),
3468 ),
3469 ]);
3470
3471 {
3472 let mut obj = base_obj.clone();
3474 let op = AttributeOp {
3475 selector: AttributeSelector::from(tags::STUDY_DESCRIPTION),
3476 action: AttributeAction::Remove,
3477 };
3478
3479 obj.apply(op).unwrap();
3480
3481 assert_eq!(obj.get(tags::STUDY_DESCRIPTION), None);
3482 }
3483 {
3484 let mut obj = base_obj.clone();
3485
3486 let op = AttributeOp {
3489 selector: tags::INSTITUTION_NAME.into(),
3490 action: AttributeAction::SetIfMissing("Nope Hospital".into()),
3491 };
3492
3493 obj.apply(op).unwrap();
3494
3495 assert_eq!(
3496 obj.get(tags::INSTITUTION_NAME),
3497 Some(&DataElement::new(
3498 tags::INSTITUTION_NAME,
3499 VR::LO,
3500 PrimitiveValue::from("Test Hospital"),
3501 ))
3502 );
3503
3504 let op = AttributeOp::new(
3506 tags::INSTITUTION_NAME,
3507 AttributeAction::ReplaceStr("REMOVED".into()),
3508 );
3509
3510 obj.apply(op).unwrap();
3511
3512 assert_eq!(
3513 obj.get(tags::INSTITUTION_NAME),
3514 Some(&DataElement::new(
3515 tags::INSTITUTION_NAME,
3516 VR::LO,
3517 PrimitiveValue::from("REMOVED"),
3518 ))
3519 );
3520
3521 let op = AttributeOp::new(
3524 tags::REQUESTING_PHYSICIAN,
3525 AttributeAction::ReplaceStr("Doctor^Anonymous".into()),
3526 );
3527
3528 obj.apply(op).unwrap();
3529
3530 assert_eq!(obj.get(tags::REQUESTING_PHYSICIAN), None);
3531
3532 let op = AttributeOp::new(
3534 tags::REQUESTING_PHYSICIAN,
3535 AttributeAction::SetStrIfMissing("Doctor^Anonymous".into()),
3536 );
3537
3538 obj.apply(op).unwrap();
3539
3540 assert_eq!(
3541 obj.get(tags::REQUESTING_PHYSICIAN),
3542 Some(&DataElement::new(
3543 tags::REQUESTING_PHYSICIAN,
3544 VR::PN,
3545 PrimitiveValue::from("Doctor^Anonymous"),
3546 ))
3547 );
3548 }
3549 {
3550 let mut obj = base_obj.clone();
3552 let op = AttributeOp::new(
3553 tags::REQUESTING_PHYSICIAN,
3554 AttributeAction::SetStr("Doctor^Anonymous".into()),
3555 );
3556
3557 obj.apply(op).unwrap();
3558
3559 assert_eq!(
3560 obj.get(tags::REQUESTING_PHYSICIAN),
3561 Some(&DataElement::new(
3562 tags::REQUESTING_PHYSICIAN,
3563 VR::PN,
3564 PrimitiveValue::from("Doctor^Anonymous"),
3565 ))
3566 );
3567 }
3568
3569 {
3570 let mut obj = base_obj.clone();
3572 let op = AttributeOp::new(
3573 tags::LOSSY_IMAGE_COMPRESSION_RATIO,
3574 AttributeAction::PushF64(1.25),
3575 );
3576
3577 obj.apply(op).unwrap();
3578
3579 assert_eq!(
3580 obj.get(tags::LOSSY_IMAGE_COMPRESSION_RATIO),
3581 Some(&DataElement::new(
3582 tags::LOSSY_IMAGE_COMPRESSION_RATIO,
3583 VR::DS,
3584 dicom_value!(Strs, ["5", "1.25"]),
3585 ))
3586 );
3587 }
3588 }
3589
3590 #[test]
3592 fn nested_inmem_ops() {
3593 let obj_1 = InMemDicomObject::from_element_iter([
3594 DataElement::new(Tag(0x0018, 0x6012), VR::US, PrimitiveValue::from(1_u16)),
3595 DataElement::new(Tag(0x0018, 0x6014), VR::US, PrimitiveValue::from(2_u16)),
3596 ]);
3597
3598 let obj_2 = InMemDicomObject::from_element_iter([DataElement::new(
3599 Tag(0x0018, 0x6012),
3600 VR::US,
3601 PrimitiveValue::from(4_u16),
3602 )]);
3603
3604 let mut main_obj = InMemDicomObject::from_element_iter(vec![
3605 DataElement::new(
3606 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3607 VR::SQ,
3608 DataSetSequence::from(vec![obj_1, obj_2]),
3609 ),
3610 DataElement::new(Tag(0x0020, 0x4000), VR::LT, Value::Primitive("TEST".into())),
3611 ]);
3612
3613 let selector: AttributeSelector =
3614 (tags::SEQUENCE_OF_ULTRASOUND_REGIONS, 0, Tag(0x0018, 0x6014)).into();
3615
3616 main_obj
3617 .apply(AttributeOp::new(selector, AttributeAction::Set(3.into())))
3618 .unwrap();
3619
3620 assert_eq!(
3621 main_obj
3622 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3623 .unwrap()
3624 .items()
3625 .unwrap()[0]
3626 .get(Tag(0x0018, 0x6014))
3627 .unwrap()
3628 .value(),
3629 &PrimitiveValue::from(3).into(),
3630 );
3631
3632 let selector: AttributeSelector =
3633 (tags::SEQUENCE_OF_ULTRASOUND_REGIONS, 1, Tag(0x0018, 0x6012)).into();
3634
3635 main_obj
3636 .apply(AttributeOp::new(selector, AttributeAction::Remove))
3637 .unwrap();
3638
3639 assert_eq!(
3641 main_obj
3642 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3643 .unwrap()
3644 .items()
3645 .unwrap()[1]
3646 .tags()
3647 .collect::<Vec<_>>(),
3648 Vec::<Tag>::new(),
3649 );
3650
3651 assert!(matches!(
3653 main_obj.value_at((tags::SEQUENCE_OF_ULTRASOUND_REGIONS, 1, Tag(0x0018, 0x6012),)),
3654 Err(AtAccessError::MissingLeafElement { .. })
3655 ))
3656 }
3657
3658 #[test]
3660 fn constructive_op() {
3661 let mut obj = InMemDicomObject::from_element_iter([DataElement::new(
3662 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3663 VR::SQ,
3664 DataSetSequence::empty(),
3665 )]);
3666
3667 let op = AttributeOp::new(
3668 (
3669 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3670 0,
3671 tags::REGION_SPATIAL_FORMAT,
3672 ),
3673 AttributeAction::Set(5_u16.into()),
3674 );
3675
3676 obj.apply(op).unwrap();
3677
3678 assert_eq!(
3680 obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3681 .unwrap()
3682 .items()
3683 .unwrap()
3684 .len(),
3685 1,
3686 );
3687
3688 assert_eq!(
3690 &obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3691 .unwrap()
3692 .items()
3693 .unwrap()[0],
3694 &InMemDicomObject::from_element_iter([DataElement::new(
3695 tags::REGION_SPATIAL_FORMAT,
3696 VR::US,
3697 PrimitiveValue::from(5_u16)
3698 )]),
3699 );
3700
3701 assert_eq!(
3703 obj.value_at((
3704 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3705 0,
3706 tags::REGION_SPATIAL_FORMAT
3707 ))
3708 .unwrap(),
3709 &Value::from(PrimitiveValue::from(5_u16)),
3710 )
3711 }
3712
3713 #[test]
3716 fn inmem_ops_can_create_seq() {
3717 let mut obj = InMemDicomObject::new_empty();
3718
3719 obj.apply(AttributeOp::new(
3720 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3721 AttributeAction::SetIfMissing(PrimitiveValue::Empty),
3722 ))
3723 .unwrap();
3724
3725 {
3726 let sequence_ultrasound = obj
3728 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3729 .expect("should have sequence element");
3730
3731 assert_eq!(sequence_ultrasound.vr(), VR::SQ);
3732
3733 assert_eq!(sequence_ultrasound.items(), Some(&[][..]),);
3734 }
3735
3736 obj.apply(AttributeOp::new(
3737 (
3738 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3739 tags::REGION_SPATIAL_FORMAT,
3740 ),
3741 AttributeAction::Set(1_u16.into()),
3742 ))
3743 .unwrap();
3744
3745 {
3746 assert_eq!(
3748 obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3749 .unwrap()
3750 .items()
3751 .map(|items| items.len()),
3752 Some(1),
3753 );
3754 }
3755 }
3756
3757 #[test]
3760 fn inmem_ops_can_create_nested_attribute() {
3761 let mut obj = InMemDicomObject::new_empty();
3762
3763 obj.apply(AttributeOp::new(
3764 (
3765 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3766 tags::REGION_SPATIAL_FORMAT,
3767 ),
3768 AttributeAction::Set(1_u16.into()),
3769 ))
3770 .unwrap();
3771
3772 {
3773 assert_eq!(
3775 obj.get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3776 .unwrap()
3777 .items()
3778 .map(|items| items.len()),
3779 Some(1),
3780 );
3781
3782 assert_eq!(
3784 obj.value_at((
3785 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3786 tags::REGION_SPATIAL_FORMAT
3787 ))
3788 .unwrap(),
3789 &PrimitiveValue::from(1_u16).into(),
3790 );
3791
3792 assert_eq!(
3794 DicomObject::at(
3795 &obj,
3796 (
3797 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3798 tags::REGION_SPATIAL_FORMAT
3799 )
3800 )
3801 .unwrap(),
3802 &PrimitiveValue::from(1_u16).into(),
3803 );
3804 }
3805 }
3806
3807 #[test]
3810 fn inmem_ops_can_truncate_seq() {
3811 let mut obj = InMemDicomObject::from_element_iter([
3812 DataElement::new(
3813 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3814 VR::SQ,
3815 DataSetSequence::from(vec![InMemDicomObject::new_empty()]),
3816 ),
3817 DataElement::new_with_len(
3818 tags::PIXEL_DATA,
3819 VR::OB,
3820 Length::UNDEFINED,
3821 PixelFragmentSequence::new(vec![], vec![vec![0xcc; 8192], vec![0x55; 1024]]),
3822 ),
3823 ]);
3824
3825 obj.apply(AttributeOp::new(
3827 tags::SEQUENCE_OF_ULTRASOUND_REGIONS,
3828 AttributeAction::Truncate(0),
3829 ))
3830 .unwrap();
3831
3832 {
3833 let sequence_ultrasound = obj
3834 .get(tags::SEQUENCE_OF_ULTRASOUND_REGIONS)
3835 .expect("should have sequence element");
3836 assert_eq!(sequence_ultrasound.items(), Some(&[][..]),);
3837 }
3838
3839 obj.apply(AttributeOp::new(
3841 tags::PIXEL_DATA,
3842 AttributeAction::Truncate(1),
3843 ))
3844 .unwrap();
3845
3846 {
3847 assert_eq!(
3849 obj.get(tags::PIXEL_DATA)
3850 .unwrap()
3851 .fragments()
3852 .map(|fragments| fragments.len()),
3853 Some(1),
3854 );
3855 }
3856 }
3857
3858 #[test]
3859 fn inmem_obj_reset_defined_length() {
3860 let mut entries: BTreeMap<Tag, InMemElement<StandardDataDictionary>> = BTreeMap::new();
3861
3862 let patient_name =
3863 DataElement::new(tags::PATIENT_NAME, VR::CS, PrimitiveValue::from("Doe^John"));
3864
3865 let study_description = DataElement::new(
3866 tags::STUDY_DESCRIPTION,
3867 VR::LO,
3868 PrimitiveValue::from("Test study"),
3869 );
3870
3871 entries.insert(tags::PATIENT_NAME, patient_name.clone());
3872
3873 let obj = InMemDicomObject::<StandardDataDictionary> {
3875 entries,
3876 dict: StandardDataDictionary,
3877 len: Length(1),
3878 charset_changed: false,
3879 };
3880
3881 assert!(obj.length().is_defined());
3882
3883 let mut o = obj.clone();
3884 o.put_element(study_description);
3885 assert!(o.length().is_undefined());
3886
3887 let mut o = obj.clone();
3888 o.remove_element(tags::PATIENT_NAME);
3889 assert!(o.length().is_undefined());
3890
3891 let mut o = obj.clone();
3892 o.remove_element_by_name("PatientName").unwrap();
3893 assert!(o.length().is_undefined());
3894
3895 let mut o = obj.clone();
3896 o.take_element(tags::PATIENT_NAME).unwrap();
3897 assert!(o.length().is_undefined());
3898
3899 let mut o = obj.clone();
3900 o.take_element_by_name("PatientName").unwrap();
3901 assert!(o.length().is_undefined());
3902
3903 let mut o = obj.clone();
3905 o.retain(|e| e.tag() == tags::PATIENT_NAME);
3906 assert!(o.length().is_undefined());
3907
3908 let mut o = obj.clone();
3909 o.apply(AttributeOp::new(
3910 tags::PATIENT_NAME,
3911 AttributeAction::Remove,
3912 ))
3913 .unwrap();
3914 assert!(o.length().is_undefined());
3915
3916 let mut o = obj.clone();
3917 o.apply(AttributeOp::new(tags::PATIENT_NAME, AttributeAction::Empty))
3918 .unwrap();
3919 assert!(o.length().is_undefined());
3920
3921 let mut o = obj.clone();
3922 o.apply(AttributeOp::new(
3923 tags::PATIENT_NAME,
3924 AttributeAction::SetVr(VR::IS),
3925 ))
3926 .unwrap();
3927 assert!(o.length().is_undefined());
3928
3929 let mut o = obj.clone();
3930 o.apply(AttributeOp::new(
3931 tags::PATIENT_NAME,
3932 AttributeAction::Set(dicom_value!(Str, "Unknown")),
3933 ))
3934 .unwrap();
3935 assert!(o.length().is_undefined());
3936
3937 let mut o = obj.clone();
3938 o.apply(AttributeOp::new(
3939 tags::PATIENT_NAME,
3940 AttributeAction::SetStr("Patient^Anonymous".into()),
3941 ))
3942 .unwrap();
3943 assert!(o.length().is_undefined());
3944
3945 let mut o = obj.clone();
3946 o.apply(AttributeOp::new(
3947 tags::PATIENT_AGE,
3948 AttributeAction::SetIfMissing(dicom_value!(75)),
3949 ))
3950 .unwrap();
3951 assert!(o.length().is_undefined());
3952
3953 let mut o = obj.clone();
3954 o.apply(AttributeOp::new(
3955 tags::PATIENT_ADDRESS,
3956 AttributeAction::SetStrIfMissing("Chicago".into()),
3957 ))
3958 .unwrap();
3959 assert!(o.length().is_undefined());
3960
3961 let mut o = obj.clone();
3962 o.apply(AttributeOp::new(
3963 tags::PATIENT_NAME,
3964 AttributeAction::Replace(dicom_value!(Str, "Unknown")),
3965 ))
3966 .unwrap();
3967 assert!(o.length().is_undefined());
3968
3969 let mut o = obj.clone();
3970 o.apply(AttributeOp::new(
3971 tags::PATIENT_NAME,
3972 AttributeAction::ReplaceStr("Unknown".into()),
3973 ))
3974 .unwrap();
3975 assert!(o.length().is_undefined());
3976
3977 let mut o = obj.clone();
3978 o.apply(AttributeOp::new(
3979 tags::PATIENT_NAME,
3980 AttributeAction::PushStr("^Prof".into()),
3981 ))
3982 .unwrap();
3983 assert!(o.length().is_undefined());
3984
3985 let mut o = obj.clone();
3986 o.apply(AttributeOp::new(
3987 tags::PATIENT_NAME,
3988 AttributeAction::PushI32(-16),
3989 ))
3990 .unwrap();
3991 assert!(o.length().is_undefined());
3992
3993 let mut o = obj.clone();
3994 o.apply(AttributeOp::new(
3995 tags::PATIENT_NAME,
3996 AttributeAction::PushU32(16),
3997 ))
3998 .unwrap();
3999 assert!(o.length().is_undefined());
4000
4001 let mut o = obj.clone();
4002 o.apply(AttributeOp::new(
4003 tags::PATIENT_NAME,
4004 AttributeAction::PushI16(-16),
4005 ))
4006 .unwrap();
4007 assert!(o.length().is_undefined());
4008
4009 let mut o = obj.clone();
4010 o.apply(AttributeOp::new(
4011 tags::PATIENT_NAME,
4012 AttributeAction::PushU16(16),
4013 ))
4014 .unwrap();
4015 assert!(o.length().is_undefined());
4016
4017 let mut o = obj.clone();
4018 o.apply(AttributeOp::new(
4019 tags::PATIENT_NAME,
4020 AttributeAction::PushF32(16.16),
4021 ))
4022 .unwrap();
4023 assert!(o.length().is_undefined());
4024
4025 let mut o = obj.clone();
4026 o.apply(AttributeOp::new(
4027 tags::PATIENT_NAME,
4028 AttributeAction::PushF64(16.1616),
4029 ))
4030 .unwrap();
4031 assert!(o.length().is_undefined());
4032 }
4033
4034 #[test]
4035 fn create_commands() {
4036 let obj = InMemDicomObject::command_from_element_iter([]);
4038 assert_eq!(
4039 obj.get(tags::COMMAND_GROUP_LENGTH)
4040 .map(|e| e.value().to_int::<u32>().unwrap()),
4041 Some(0)
4042 );
4043
4044 let obj = InMemDicomObject::command_from_element_iter([
4046 DataElement::new(
4048 tags::AFFECTED_SOP_CLASS_UID,
4049 VR::UI,
4050 PrimitiveValue::from("1.2.840.10008.5.1.4.1.2.1.1"),
4051 ),
4052 DataElement::new(
4054 tags::COMMAND_FIELD,
4055 VR::US,
4056 dicom_value!(U16, [0x0020]),
4058 ),
4059 DataElement::new(tags::MESSAGE_ID, VR::US, dicom_value!(U16, [0])),
4061 DataElement::new(
4063 tags::PRIORITY,
4064 VR::US,
4065 dicom_value!(U16, [0x0000]),
4067 ),
4068 DataElement::new(
4070 tags::COMMAND_DATA_SET_TYPE,
4071 VR::US,
4072 dicom_value!(U16, [0x0001]),
4073 ),
4074 ]);
4075 assert_eq!(
4076 obj.get(tags::COMMAND_GROUP_LENGTH)
4077 .map(|e| e.value().to_int::<u32>().unwrap()),
4078 Some(76)
4079 );
4080
4081 let storage_sop_class_uid = "1.2.840.10008.5.1.4.1.1.4";
4082 let storage_sop_instance_uid = "2.25.221314879990624101283043547144116927116";
4083
4084 let obj = InMemDicomObject::command_from_element_iter([
4086 DataElement::new(
4088 tags::COMMAND_GROUP_LENGTH,
4089 VR::UL,
4090 PrimitiveValue::from(9999_u32),
4091 ),
4092 DataElement::new(
4094 tags::AFFECTED_SOP_CLASS_UID,
4095 VR::UI,
4096 dicom_value!(Str, storage_sop_class_uid),
4097 ),
4098 DataElement::new(tags::COMMAND_FIELD, VR::US, dicom_value!(U16, [0x0001])),
4100 DataElement::new(tags::MESSAGE_ID, VR::US, dicom_value!(U16, [1])),
4102 DataElement::new(tags::PRIORITY, VR::US, dicom_value!(U16, [0x0000])),
4104 DataElement::new(
4106 tags::COMMAND_DATA_SET_TYPE,
4107 VR::US,
4108 dicom_value!(U16, [0x0000]),
4109 ),
4110 DataElement::new(
4112 tags::AFFECTED_SOP_INSTANCE_UID,
4113 VR::UI,
4114 dicom_value!(Str, storage_sop_instance_uid),
4115 ),
4116 ]);
4117
4118 assert_eq!(
4119 obj.get(tags::COMMAND_GROUP_LENGTH)
4120 .map(|e| e.value().to_int::<u32>().unwrap()),
4121 Some(126)
4122 );
4123 }
4124
4125 #[test]
4126 fn test_even_len() {
4127 assert_eq!(even_len(0), 0);
4128 assert_eq!(even_len(1), 2);
4129 assert_eq!(even_len(2), 2);
4130 assert_eq!(even_len(3), 4);
4131 assert_eq!(even_len(4), 4);
4132 assert_eq!(even_len(5), 6);
4133 }
4134
4135 #[test]
4136 fn can_update_value() {
4137 let mut obj = InMemDicomObject::from_element_iter([DataElement::new(
4138 tags::ANATOMIC_REGION_SEQUENCE,
4139 VR::SQ,
4140 DataSetSequence::empty(),
4141 )]);
4142 assert_eq!(
4143 obj.get(tags::ANATOMIC_REGION_SEQUENCE).map(|e| e.length()),
4144 Some(Length(0)),
4145 );
4146
4147 assert!(!obj.update_value(tags::BURNED_IN_ANNOTATION, |_value| {
4148 panic!("should not be called")
4149 }),);
4150
4151 let o = obj.update_value(tags::ANATOMIC_REGION_SEQUENCE, |value| {
4152 let items = value.items_mut().unwrap();
4154 items.push(InMemDicomObject::from_element_iter([DataElement::new(
4155 tags::INSTANCE_NUMBER,
4156 VR::IS,
4157 PrimitiveValue::from(1),
4158 )]));
4159 });
4160 assert!(o);
4161
4162 assert!(
4163 obj.get(tags::ANATOMIC_REGION_SEQUENCE)
4164 .unwrap()
4165 .length()
4166 .is_undefined()
4167 );
4168 }
4169
4170 #[test]
4171 fn deep_sequence_change_encoding_writes_undefined_sequence_length() {
4172 use smallvec::smallvec;
4173
4174 let obj_1 = InMemDicomObject::from_element_iter(vec![
4175 DataElement::new(
4177 tags::STUDY_DESCRIPTION,
4178 VR::SL,
4179 Value::Primitive("MORFOLOGÍA Y FUNCIÓN".into()),
4180 ),
4181 DataElement::new(
4183 tags::SERIES_DESCRIPTION,
4184 VR::SL,
4185 Value::Primitive("0123456789".into()),
4186 ),
4187 ]);
4188
4189 let some_tag = Tag(0x0018, 0x6011);
4190
4191 let inner_sequence = InMemDicomObject::from_element_iter(vec![DataElement::new(
4192 some_tag,
4193 VR::SQ,
4194 Value::from(DataSetSequence::new(
4195 smallvec![obj_1],
4196 Length(30), )),
4198 )]);
4199 let outer_sequence = DataElement::new(
4200 some_tag,
4201 VR::SQ,
4202 Value::from(DataSetSequence::new(
4203 smallvec![inner_sequence.clone(), inner_sequence],
4204 Length(60), )),
4206 );
4207
4208 let original_object = InMemDicomObject::from_element_iter(vec![
4209 DataElement::new(tags::SPECIFIC_CHARACTER_SET, VR::CS, "ISO_IR 100"),
4210 outer_sequence,
4211 ]);
4212
4213 assert_eq!(
4214 original_object
4215 .get(some_tag)
4216 .expect("object should be present")
4217 .length(),
4218 Length(60)
4219 );
4220
4221 let mut changed_charset = original_object.clone();
4222 changed_charset.convert_to_utf8();
4223 assert!(changed_charset.charset_changed);
4224
4225 use dicom_parser::dataset::DataToken as token;
4226 let options = IntoTokensOptions::new(true);
4227 let converted_tokens: Vec<_> = changed_charset.into_tokens_with_options(options).collect();
4228
4229 assert_eq!(
4230 vec![
4231 token::ElementHeader(DataElementHeader {
4232 tag: Tag(0x0008, 0x0005),
4233 vr: VR::CS,
4234 len: Length(10),
4235 }),
4236 token::PrimitiveValue("ISO_IR 192".into()),
4237 token::SequenceStart {
4238 tag: Tag(0x0018, 0x6011),
4239 len: Length::UNDEFINED,
4240 },
4241 token::ItemStart {
4242 len: Length::UNDEFINED
4243 },
4244 token::SequenceStart {
4245 tag: Tag(0x0018, 0x6011),
4246 len: Length::UNDEFINED,
4247 },
4248 token::ItemStart {
4249 len: Length::UNDEFINED
4250 },
4251 token::ElementHeader(DataElementHeader {
4252 tag: Tag(0x0008, 0x1030),
4253 vr: VR::SL,
4254 len: Length(22),
4255 }),
4256 token::PrimitiveValue("MORFOLOGÍA Y FUNCIÓN".into()),
4257 token::ElementHeader(DataElementHeader {
4258 tag: Tag(0x0008, 0x103E),
4259 vr: VR::SL,
4260 len: Length(10),
4261 }),
4262 token::PrimitiveValue("0123456789".into()),
4263 token::ItemEnd,
4264 token::SequenceEnd,
4265 token::ItemEnd,
4266 token::ItemStart {
4267 len: Length::UNDEFINED
4268 },
4269 token::SequenceStart {
4270 tag: Tag(0x0018, 0x6011),
4271 len: Length::UNDEFINED,
4272 },
4273 token::ItemStart {
4274 len: Length::UNDEFINED
4275 },
4276 token::ElementHeader(DataElementHeader {
4277 tag: Tag(0x0008, 0x1030),
4278 vr: VR::SL,
4279 len: Length(22),
4280 }),
4281 token::PrimitiveValue("MORFOLOGÍA Y FUNCIÓN".into()),
4282 token::ElementHeader(DataElementHeader {
4283 tag: Tag(0x0008, 0x103E),
4284 vr: VR::SL,
4285 len: Length(10),
4286 }),
4287 token::PrimitiveValue("0123456789".into()),
4288 token::ItemEnd,
4289 token::SequenceEnd,
4290 token::ItemEnd,
4291 token::SequenceEnd,
4292 ],
4293 converted_tokens
4294 );
4295 }
4296
4297 #[test]
4298 fn private_elements() {
4299 let mut ds = InMemDicomObject::from_element_iter(vec![
4300 DataElement::new(
4301 Tag(0x0009, 0x0010),
4302 VR::LO,
4303 PrimitiveValue::from("CREATOR 1"),
4304 ),
4305 DataElement::new(
4306 Tag(0x0009, 0x0011),
4307 VR::LO,
4308 PrimitiveValue::from("CREATOR 2"),
4309 ),
4310 DataElement::new(
4311 Tag(0x0011, 0x0010),
4312 VR::LO,
4313 PrimitiveValue::from("CREATOR 3"),
4314 ),
4315 ]);
4316 ds.put_private_element(
4317 0x0009,
4318 "CREATOR 1",
4319 0x01,
4320 VR::DS,
4321 PrimitiveValue::Str("1.0".to_string()),
4322 )
4323 .unwrap();
4324 ds.put_private_element(
4325 0x0009,
4326 "CREATOR 4",
4327 0x02,
4328 VR::DS,
4329 PrimitiveValue::Str("1.0".to_string()),
4330 )
4331 .unwrap();
4332
4333 let res = ds.put_private_element(
4334 0x0012,
4335 "CREATOR 4",
4336 0x02,
4337 VR::DS,
4338 PrimitiveValue::Str("1.0".to_string()),
4339 );
4340 assert_eq!(
4341 &res.err().unwrap().to_string(),
4342 "Group number must be odd, found 0x0012"
4343 );
4344
4345 assert_eq!(
4346 ds.private_element(0x0009, "CREATOR 1", 0x01)
4347 .unwrap()
4348 .value()
4349 .to_str()
4350 .unwrap(),
4351 "1.0"
4352 );
4353 assert_eq!(
4354 ds.private_element(0x0009, "CREATOR 4", 0x02)
4355 .unwrap()
4356 .value()
4357 .to_str()
4358 .unwrap(),
4359 "1.0"
4360 );
4361 assert_eq!(
4362 ds.private_element(0x0009, "CREATOR 4", 0x02)
4363 .unwrap()
4364 .header()
4365 .tag(),
4366 Tag(0x0009, 0x1202)
4367 );
4368 }
4369
4370 #[test]
4371 fn private_element_group_full() {
4372 let mut ds = InMemDicomObject::from_element_iter(
4373 (0..=0x00FFu16)
4374 .map(|i| {
4375 DataElement::new(Tag(0x0009, i), VR::LO, PrimitiveValue::from("CREATOR 1"))
4376 })
4377 .collect::<Vec<DataElement<_>>>(),
4378 );
4379 let res = ds.put_private_element(0x0009, "TEST", 0x01, VR::DS, PrimitiveValue::from("1.0"));
4380 assert_eq!(
4381 res.err().unwrap().to_string(),
4382 "No space available in group 0x0009"
4383 );
4384 }
4385
4386 fn tokens_with_sequence() -> Vec<DataToken> {
4390 vec![
4391 DataToken::SequenceStart {
4392 tag: Tag(0x0018, 0x6011),
4393 len: Length::UNDEFINED,
4394 },
4395 DataToken::ItemStart {
4396 len: Length::UNDEFINED,
4397 },
4398 DataToken::ElementHeader(DataElementHeader {
4399 tag: Tag(0x0018, 0x6012),
4400 vr: VR::US,
4401 len: Length(2),
4402 }),
4403 DataToken::PrimitiveValue(PrimitiveValue::U16([1].as_ref().into())),
4404 DataToken::ItemEnd,
4405 DataToken::SequenceEnd,
4406 DataToken::ElementHeader(DataElementHeader {
4407 tag: Tag(0x0020, 0x4000),
4408 vr: VR::LT,
4409 len: Length(4),
4410 }),
4411 DataToken::PrimitiveValue(PrimitiveValue::Str("TEST".into())),
4412 ]
4413 }
4414
4415 #[test]
4416 fn build_object_read_to_sequence_tag() {
4417 let tokens = tokens_with_sequence();
4419 let obj = InMemDicomObject::build_object(
4420 &mut tokens.into_iter().map(Result::Ok),
4421 StandardDataDictionary,
4422 false,
4423 Length::UNDEFINED,
4424 None,
4425 Some(Tag(0x0018, 0x6011)),
4426 )
4427 .unwrap();
4428
4429 assert!(
4430 obj.element(Tag(0x0018, 0x6011)).is_ok(),
4431 "sequence should be present"
4432 );
4433 assert!(
4434 obj.element(Tag(0x0020, 0x4000)).is_err(),
4435 "element after sequence should be absent"
4436 );
4437 }
4438
4439 #[test]
4440 fn build_object_read_to_element_after_sequence() {
4441 let tokens = tokens_with_sequence();
4443 let obj = InMemDicomObject::build_object(
4444 &mut tokens.into_iter().map(Result::Ok),
4445 StandardDataDictionary,
4446 false,
4447 Length::UNDEFINED,
4448 None,
4449 Some(Tag(0x0020, 0x4000)),
4450 )
4451 .unwrap();
4452
4453 assert!(
4454 obj.element(Tag(0x0018, 0x6011)).is_ok(),
4455 "sequence should be present"
4456 );
4457 assert!(
4458 obj.element(Tag(0x0020, 0x4000)).is_ok(),
4459 "element at read_to tag should be present"
4460 );
4461 }
4462
4463 #[test]
4464 fn build_object_read_to_and_read_until_same_sequence_tag() {
4465 let tokens = tokens_with_sequence();
4467 let obj = InMemDicomObject::build_object(
4468 &mut tokens.into_iter().map(Result::Ok),
4469 StandardDataDictionary,
4470 false,
4471 Length::UNDEFINED,
4472 Some(Tag(0x0018, 0x6011)),
4473 Some(Tag(0x0018, 0x6011)),
4474 )
4475 .unwrap();
4476
4477 assert!(
4478 obj.element(Tag(0x0018, 0x6011)).is_err(),
4479 "read_until takes priority: sequence should be excluded"
4480 );
4481 }
4482
4483 #[test]
4484 fn build_object_read_to_sequence_equals_read_until_next() {
4485 let tokens_a = tokens_with_sequence();
4487 let tokens_b = tokens_with_sequence();
4488
4489 let obj_read_to = InMemDicomObject::build_object(
4490 &mut tokens_a.into_iter().map(Result::Ok),
4491 StandardDataDictionary,
4492 false,
4493 Length::UNDEFINED,
4494 None,
4495 Some(Tag(0x0018, 0x6011)),
4496 )
4497 .unwrap();
4498
4499 let obj_read_until = InMemDicomObject::build_object(
4500 &mut tokens_b.into_iter().map(Result::Ok),
4501 StandardDataDictionary,
4502 false,
4503 Length::UNDEFINED,
4504 Some(Tag(0x0020, 0x4000)),
4505 None,
4506 )
4507 .unwrap();
4508
4509 assert_obj_eq(&obj_read_to, &obj_read_until);
4510 }
4511}