comparison Resources/Orthanc/Core/DicomFormat/DicomMap.cpp @ 200:03afbee0cc7b

integration of Orthanc core into Stone
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 23 Mar 2018 11:04:03 +0100
parents
children
comparison
equal deleted inserted replaced
199:dabe9982fca3 200:03afbee0cc7b
1 /**
2 * Orthanc - A Lightweight, RESTful DICOM Store
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
4 * Department, University Hospital of Liege, Belgium
5 * Copyright (C) 2017-2018 Osimis S.A., Belgium
6 *
7 * This program is free software: you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License as
9 * published by the Free Software Foundation, either version 3 of the
10 * License, or (at your option) any later version.
11 *
12 * In addition, as a special exception, the copyright holders of this
13 * program give permission to link the code of its release with the
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it
15 * that use the same license as the "OpenSSL" library), and distribute
16 * the linked executables. You must obey the GNU General Public License
17 * in all respects for all of the code used other than "OpenSSL". If you
18 * modify file(s) with this exception, you may extend this exception to
19 * your version of the file(s), but you are not obligated to do so. If
20 * you do not wish to do so, delete this exception statement from your
21 * version. If you delete this exception statement from all source files
22 * in the program, then also delete it here.
23 *
24 * This program is distributed in the hope that it will be useful, but
25 * WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
27 * General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program. If not, see <http://www.gnu.org/licenses/>.
31 **/
32
33
34 #include "../PrecompiledHeaders.h"
35 #include "DicomMap.h"
36
37 #include <stdio.h>
38 #include <memory>
39
40 #include "../Endianness.h"
41 #include "../Logging.h"
42 #include "../OrthancException.h"
43
44
45 namespace Orthanc
46 {
47 static DicomTag patientTags[] =
48 {
49 //DicomTag(0x0010, 0x1010), // PatientAge
50 //DicomTag(0x0010, 0x1040) // PatientAddress
51 DicomTag(0x0010, 0x0010), // PatientName
52 DicomTag(0x0010, 0x0030), // PatientBirthDate
53 DicomTag(0x0010, 0x0040), // PatientSex
54 DicomTag(0x0010, 0x1000), // OtherPatientIDs
55 DICOM_TAG_PATIENT_ID
56 };
57
58 static DicomTag studyTags[] =
59 {
60 //DicomTag(0x0010, 0x1020), // PatientSize
61 //DicomTag(0x0010, 0x1030) // PatientWeight
62 DICOM_TAG_STUDY_DATE,
63 DicomTag(0x0008, 0x0030), // StudyTime
64 DicomTag(0x0020, 0x0010), // StudyID
65 DICOM_TAG_STUDY_DESCRIPTION,
66 DICOM_TAG_ACCESSION_NUMBER,
67 DICOM_TAG_STUDY_INSTANCE_UID,
68 DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION, // New in db v6
69 DICOM_TAG_INSTITUTION_NAME, // New in db v6
70 DICOM_TAG_REQUESTING_PHYSICIAN, // New in db v6
71 DICOM_TAG_REFERRING_PHYSICIAN_NAME // New in db v6
72 };
73
74 static DicomTag seriesTags[] =
75 {
76 //DicomTag(0x0010, 0x1080), // MilitaryRank
77 DicomTag(0x0008, 0x0021), // SeriesDate
78 DicomTag(0x0008, 0x0031), // SeriesTime
79 DICOM_TAG_MODALITY,
80 DicomTag(0x0008, 0x0070), // Manufacturer
81 DicomTag(0x0008, 0x1010), // StationName
82 DICOM_TAG_SERIES_DESCRIPTION,
83 DicomTag(0x0018, 0x0015), // BodyPartExamined
84 DicomTag(0x0018, 0x0024), // SequenceName
85 DicomTag(0x0018, 0x1030), // ProtocolName
86 DicomTag(0x0020, 0x0011), // SeriesNumber
87 DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES,
88 DICOM_TAG_IMAGES_IN_ACQUISITION,
89 DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS,
90 DICOM_TAG_NUMBER_OF_SLICES,
91 DICOM_TAG_NUMBER_OF_TIME_SLICES,
92 DICOM_TAG_SERIES_INSTANCE_UID,
93 DICOM_TAG_IMAGE_ORIENTATION_PATIENT, // New in db v6
94 DICOM_TAG_SERIES_TYPE, // New in db v6
95 DICOM_TAG_OPERATOR_NAME, // New in db v6
96 DICOM_TAG_PERFORMED_PROCEDURE_STEP_DESCRIPTION, // New in db v6
97 DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION, // New in db v6
98 DICOM_TAG_CONTRAST_BOLUS_AGENT // New in db v6
99 };
100
101 static DicomTag instanceTags[] =
102 {
103 DicomTag(0x0008, 0x0012), // InstanceCreationDate
104 DicomTag(0x0008, 0x0013), // InstanceCreationTime
105 DicomTag(0x0020, 0x0012), // AcquisitionNumber
106 DICOM_TAG_IMAGE_INDEX,
107 DICOM_TAG_INSTANCE_NUMBER,
108 DICOM_TAG_NUMBER_OF_FRAMES,
109 DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER,
110 DICOM_TAG_SOP_INSTANCE_UID,
111 DICOM_TAG_IMAGE_POSITION_PATIENT, // New in db v6
112 DICOM_TAG_IMAGE_COMMENTS // New in db v6
113 };
114
115
116 void DicomMap::LoadMainDicomTags(const DicomTag*& tags,
117 size_t& size,
118 ResourceType level)
119 {
120 switch (level)
121 {
122 case ResourceType_Patient:
123 tags = patientTags;
124 size = sizeof(patientTags) / sizeof(DicomTag);
125 break;
126
127 case ResourceType_Study:
128 tags = studyTags;
129 size = sizeof(studyTags) / sizeof(DicomTag);
130 break;
131
132 case ResourceType_Series:
133 tags = seriesTags;
134 size = sizeof(seriesTags) / sizeof(DicomTag);
135 break;
136
137 case ResourceType_Instance:
138 tags = instanceTags;
139 size = sizeof(instanceTags) / sizeof(DicomTag);
140 break;
141
142 default:
143 throw OrthancException(ErrorCode_ParameterOutOfRange);
144 }
145 }
146
147
148 void DicomMap::SetValue(uint16_t group,
149 uint16_t element,
150 DicomValue* value)
151 {
152 DicomTag tag(group, element);
153 Map::iterator it = map_.find(tag);
154
155 if (it != map_.end())
156 {
157 delete it->second;
158 it->second = value;
159 }
160 else
161 {
162 map_.insert(std::make_pair(tag, value));
163 }
164 }
165
166 void DicomMap::SetValue(DicomTag tag,
167 DicomValue* value)
168 {
169 SetValue(tag.GetGroup(), tag.GetElement(), value);
170 }
171
172
173
174
175 void DicomMap::Clear()
176 {
177 for (Map::iterator it = map_.begin(); it != map_.end(); ++it)
178 {
179 delete it->second;
180 }
181
182 map_.clear();
183 }
184
185
186 void DicomMap::ExtractTags(DicomMap& result,
187 const DicomTag* tags,
188 size_t count) const
189 {
190 result.Clear();
191
192 for (unsigned int i = 0; i < count; i++)
193 {
194 Map::const_iterator it = map_.find(tags[i]);
195 if (it != map_.end())
196 {
197 result.SetValue(it->first, it->second->Clone());
198 }
199 }
200 }
201
202
203 void DicomMap::ExtractPatientInformation(DicomMap& result) const
204 {
205 ExtractTags(result, patientTags, sizeof(patientTags) / sizeof(DicomTag));
206 }
207
208 void DicomMap::ExtractStudyInformation(DicomMap& result) const
209 {
210 ExtractTags(result, studyTags, sizeof(studyTags) / sizeof(DicomTag));
211 }
212
213 void DicomMap::ExtractSeriesInformation(DicomMap& result) const
214 {
215 ExtractTags(result, seriesTags, sizeof(seriesTags) / sizeof(DicomTag));
216 }
217
218 void DicomMap::ExtractInstanceInformation(DicomMap& result) const
219 {
220 ExtractTags(result, instanceTags, sizeof(instanceTags) / sizeof(DicomTag));
221 }
222
223
224
225 DicomMap* DicomMap::Clone() const
226 {
227 std::auto_ptr<DicomMap> result(new DicomMap);
228
229 for (Map::const_iterator it = map_.begin(); it != map_.end(); ++it)
230 {
231 result->map_.insert(std::make_pair(it->first, it->second->Clone()));
232 }
233
234 return result.release();
235 }
236
237
238 void DicomMap::Assign(const DicomMap& other)
239 {
240 Clear();
241
242 for (Map::const_iterator it = other.map_.begin(); it != other.map_.end(); ++it)
243 {
244 map_.insert(std::make_pair(it->first, it->second->Clone()));
245 }
246 }
247
248
249 const DicomValue& DicomMap::GetValue(const DicomTag& tag) const
250 {
251 const DicomValue* value = TestAndGetValue(tag);
252
253 if (value)
254 {
255 return *value;
256 }
257 else
258 {
259 throw OrthancException(ErrorCode_InexistentTag);
260 }
261 }
262
263
264 const DicomValue* DicomMap::TestAndGetValue(const DicomTag& tag) const
265 {
266 Map::const_iterator it = map_.find(tag);
267
268 if (it == map_.end())
269 {
270 return NULL;
271 }
272 else
273 {
274 return it->second;
275 }
276 }
277
278
279 void DicomMap::Remove(const DicomTag& tag)
280 {
281 Map::iterator it = map_.find(tag);
282 if (it != map_.end())
283 {
284 delete it->second;
285 map_.erase(it);
286 }
287 }
288
289
290 static void SetupFindTemplate(DicomMap& result,
291 const DicomTag* tags,
292 size_t count)
293 {
294 result.Clear();
295
296 for (size_t i = 0; i < count; i++)
297 {
298 result.SetValue(tags[i], "", false);
299 }
300 }
301
302 void DicomMap::SetupFindPatientTemplate(DicomMap& result)
303 {
304 SetupFindTemplate(result, patientTags, sizeof(patientTags) / sizeof(DicomTag));
305 }
306
307 void DicomMap::SetupFindStudyTemplate(DicomMap& result)
308 {
309 SetupFindTemplate(result, studyTags, sizeof(studyTags) / sizeof(DicomTag));
310 result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false);
311 result.SetValue(DICOM_TAG_PATIENT_ID, "", false);
312
313 // These main DICOM tags are only indirectly related to the
314 // General Study Module, remove them
315 result.Remove(DICOM_TAG_INSTITUTION_NAME);
316 result.Remove(DICOM_TAG_REQUESTING_PHYSICIAN);
317 result.Remove(DICOM_TAG_REQUESTED_PROCEDURE_DESCRIPTION);
318 }
319
320 void DicomMap::SetupFindSeriesTemplate(DicomMap& result)
321 {
322 SetupFindTemplate(result, seriesTags, sizeof(seriesTags) / sizeof(DicomTag));
323 result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false);
324 result.SetValue(DICOM_TAG_PATIENT_ID, "", false);
325 result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false);
326
327 // These tags are considered as "main" by Orthanc, but are not in the Series module
328 result.Remove(DicomTag(0x0008, 0x0070)); // Manufacturer
329 result.Remove(DicomTag(0x0008, 0x1010)); // Station name
330 result.Remove(DicomTag(0x0018, 0x0024)); // Sequence name
331 result.Remove(DICOM_TAG_CARDIAC_NUMBER_OF_IMAGES);
332 result.Remove(DICOM_TAG_IMAGES_IN_ACQUISITION);
333 result.Remove(DICOM_TAG_NUMBER_OF_SLICES);
334 result.Remove(DICOM_TAG_NUMBER_OF_TEMPORAL_POSITIONS);
335 result.Remove(DICOM_TAG_NUMBER_OF_TIME_SLICES);
336 result.Remove(DICOM_TAG_IMAGE_ORIENTATION_PATIENT);
337 result.Remove(DICOM_TAG_SERIES_TYPE);
338 result.Remove(DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION);
339 result.Remove(DICOM_TAG_CONTRAST_BOLUS_AGENT);
340 }
341
342 void DicomMap::SetupFindInstanceTemplate(DicomMap& result)
343 {
344 SetupFindTemplate(result, instanceTags, sizeof(instanceTags) / sizeof(DicomTag));
345 result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false);
346 result.SetValue(DICOM_TAG_PATIENT_ID, "", false);
347 result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false);
348 result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "", false);
349 }
350
351
352 void DicomMap::CopyTagIfExists(const DicomMap& source,
353 const DicomTag& tag)
354 {
355 if (source.HasTag(tag))
356 {
357 SetValue(tag, source.GetValue(tag));
358 }
359 }
360
361
362 bool DicomMap::IsMainDicomTag(const DicomTag& tag, ResourceType level)
363 {
364 DicomTag *tags = NULL;
365 size_t size;
366
367 switch (level)
368 {
369 case ResourceType_Patient:
370 tags = patientTags;
371 size = sizeof(patientTags) / sizeof(DicomTag);
372 break;
373
374 case ResourceType_Study:
375 tags = studyTags;
376 size = sizeof(studyTags) / sizeof(DicomTag);
377 break;
378
379 case ResourceType_Series:
380 tags = seriesTags;
381 size = sizeof(seriesTags) / sizeof(DicomTag);
382 break;
383
384 case ResourceType_Instance:
385 tags = instanceTags;
386 size = sizeof(instanceTags) / sizeof(DicomTag);
387 break;
388
389 default:
390 throw OrthancException(ErrorCode_ParameterOutOfRange);
391 }
392
393 for (size_t i = 0; i < size; i++)
394 {
395 if (tags[i] == tag)
396 {
397 return true;
398 }
399 }
400
401 return false;
402 }
403
404 bool DicomMap::IsMainDicomTag(const DicomTag& tag)
405 {
406 return (IsMainDicomTag(tag, ResourceType_Patient) ||
407 IsMainDicomTag(tag, ResourceType_Study) ||
408 IsMainDicomTag(tag, ResourceType_Series) ||
409 IsMainDicomTag(tag, ResourceType_Instance));
410 }
411
412
413 void DicomMap::GetMainDicomTagsInternal(std::set<DicomTag>& result, ResourceType level)
414 {
415 DicomTag *tags = NULL;
416 size_t size;
417
418 switch (level)
419 {
420 case ResourceType_Patient:
421 tags = patientTags;
422 size = sizeof(patientTags) / sizeof(DicomTag);
423 break;
424
425 case ResourceType_Study:
426 tags = studyTags;
427 size = sizeof(studyTags) / sizeof(DicomTag);
428 break;
429
430 case ResourceType_Series:
431 tags = seriesTags;
432 size = sizeof(seriesTags) / sizeof(DicomTag);
433 break;
434
435 case ResourceType_Instance:
436 tags = instanceTags;
437 size = sizeof(instanceTags) / sizeof(DicomTag);
438 break;
439
440 default:
441 throw OrthancException(ErrorCode_ParameterOutOfRange);
442 }
443
444 for (size_t i = 0; i < size; i++)
445 {
446 result.insert(tags[i]);
447 }
448 }
449
450
451 void DicomMap::GetMainDicomTags(std::set<DicomTag>& result, ResourceType level)
452 {
453 result.clear();
454 GetMainDicomTagsInternal(result, level);
455 }
456
457
458 void DicomMap::GetMainDicomTags(std::set<DicomTag>& result)
459 {
460 result.clear();
461 GetMainDicomTagsInternal(result, ResourceType_Patient);
462 GetMainDicomTagsInternal(result, ResourceType_Study);
463 GetMainDicomTagsInternal(result, ResourceType_Series);
464 GetMainDicomTagsInternal(result, ResourceType_Instance);
465 }
466
467
468 void DicomMap::GetTags(std::set<DicomTag>& tags) const
469 {
470 tags.clear();
471
472 for (Map::const_iterator it = map_.begin();
473 it != map_.end(); ++it)
474 {
475 tags.insert(it->first);
476 }
477 }
478
479
480 static uint16_t ReadUnsignedInteger16(const char* dicom)
481 {
482 return le16toh(*reinterpret_cast<const uint16_t*>(dicom));
483 }
484
485
486 static uint32_t ReadUnsignedInteger32(const char* dicom)
487 {
488 return le32toh(*reinterpret_cast<const uint32_t*>(dicom));
489 }
490
491
492 static bool ValidateTag(const ValueRepresentation& vr,
493 const std::string& value)
494 {
495 switch (vr)
496 {
497 case ValueRepresentation_ApplicationEntity:
498 return value.size() <= 16;
499
500 case ValueRepresentation_AgeString:
501 return (value.size() == 4 &&
502 isdigit(value[0]) &&
503 isdigit(value[1]) &&
504 isdigit(value[2]) &&
505 (value[3] == 'D' || value[3] == 'W' || value[3] == 'M' || value[3] == 'Y'));
506
507 case ValueRepresentation_AttributeTag:
508 return value.size() == 4;
509
510 case ValueRepresentation_CodeString:
511 return value.size() <= 16;
512
513 case ValueRepresentation_Date:
514 return value.size() <= 18;
515
516 case ValueRepresentation_DecimalString:
517 return value.size() <= 16;
518
519 case ValueRepresentation_DateTime:
520 return value.size() <= 54;
521
522 case ValueRepresentation_FloatingPointSingle:
523 return value.size() == 4;
524
525 case ValueRepresentation_FloatingPointDouble:
526 return value.size() == 8;
527
528 case ValueRepresentation_IntegerString:
529 return value.size() <= 12;
530
531 case ValueRepresentation_LongString:
532 return value.size() <= 64;
533
534 case ValueRepresentation_LongText:
535 return value.size() <= 10240;
536
537 case ValueRepresentation_OtherByte:
538 return true;
539
540 case ValueRepresentation_OtherDouble:
541 return value.size() <= (static_cast<uint64_t>(1) << 32) - 8;
542
543 case ValueRepresentation_OtherFloat:
544 return value.size() <= (static_cast<uint64_t>(1) << 32) - 4;
545
546 case ValueRepresentation_OtherLong:
547 return true;
548
549 case ValueRepresentation_OtherWord:
550 return true;
551
552 case ValueRepresentation_PersonName:
553 return true;
554
555 case ValueRepresentation_ShortString:
556 return value.size() <= 16;
557
558 case ValueRepresentation_SignedLong:
559 return value.size() == 4;
560
561 case ValueRepresentation_Sequence:
562 return true;
563
564 case ValueRepresentation_SignedShort:
565 return value.size() == 2;
566
567 case ValueRepresentation_ShortText:
568 return value.size() <= 1024;
569
570 case ValueRepresentation_Time:
571 return value.size() <= 28;
572
573 case ValueRepresentation_UnlimitedCharacters:
574 return value.size() <= (static_cast<uint64_t>(1) << 32) - 2;
575
576 case ValueRepresentation_UniqueIdentifier:
577 return value.size() <= 64;
578
579 case ValueRepresentation_UnsignedLong:
580 return value.size() == 4;
581
582 case ValueRepresentation_Unknown:
583 return true;
584
585 case ValueRepresentation_UniversalResource:
586 return value.size() <= (static_cast<uint64_t>(1) << 32) - 2;
587
588 case ValueRepresentation_UnsignedShort:
589 return value.size() == 2;
590
591 case ValueRepresentation_UnlimitedText:
592 return value.size() <= (static_cast<uint64_t>(1) << 32) - 2;
593
594 default:
595 // Assume unsupported tags are OK
596 return true;
597 }
598 }
599
600
601 static void RemoveTagPadding(std::string& value,
602 const ValueRepresentation& vr)
603 {
604 /**
605 * Remove padding from character strings, if need be. For the time
606 * being, only the UI VR is supported.
607 * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html
608 **/
609
610 switch (vr)
611 {
612 case ValueRepresentation_UniqueIdentifier:
613 {
614 /**
615 * "Values with a VR of UI shall be padded with a single
616 * trailing NULL (00H) character when necessary to achieve even
617 * length."
618 **/
619
620 if (!value.empty() &&
621 value[value.size() - 1] == '\0')
622 {
623 value.resize(value.size() - 1);
624 }
625
626 break;
627 }
628
629 /**
630 * TODO implement other VR
631 **/
632
633 default:
634 // No padding is applicable to this VR
635 break;
636 }
637 }
638
639
640 static bool ReadNextTag(DicomTag& tag,
641 ValueRepresentation& vr,
642 std::string& value,
643 const char* dicom,
644 size_t size,
645 size_t& position)
646 {
647 /**
648 * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/chapter_7.html#sect_7.1.2
649 * This function reads a data element with Explicit VR encoded using Little-Endian.
650 **/
651
652 if (position + 6 > size)
653 {
654 return false;
655 }
656
657 tag = DicomTag(ReadUnsignedInteger16(dicom + position),
658 ReadUnsignedInteger16(dicom + position + 2));
659
660 vr = StringToValueRepresentation(std::string(dicom + position + 4, 2), true);
661 if (vr == ValueRepresentation_NotSupported)
662 {
663 return false;
664 }
665
666 if (vr == ValueRepresentation_OtherByte ||
667 vr == ValueRepresentation_OtherDouble ||
668 vr == ValueRepresentation_OtherFloat ||
669 vr == ValueRepresentation_OtherLong ||
670 vr == ValueRepresentation_OtherWord ||
671 vr == ValueRepresentation_Sequence ||
672 vr == ValueRepresentation_UnlimitedCharacters ||
673 vr == ValueRepresentation_UniversalResource ||
674 vr == ValueRepresentation_UnlimitedText ||
675 vr == ValueRepresentation_Unknown) // Note that "UN" should never appear in the Meta Information
676 {
677 if (position + 12 > size)
678 {
679 return false;
680 }
681
682 uint32_t length = ReadUnsignedInteger32(dicom + position + 8);
683
684 if (position + 12 + length > size)
685 {
686 return false;
687 }
688
689 value.assign(dicom + position + 12, length);
690 position += (12 + length);
691 }
692 else
693 {
694 if (position + 8 > size)
695 {
696 return false;
697 }
698
699 uint16_t length = ReadUnsignedInteger16(dicom + position + 6);
700
701 if (position + 8 + length > size)
702 {
703 return false;
704 }
705
706 value.assign(dicom + position + 8, length);
707 position += (8 + length);
708 }
709
710 if (!ValidateTag(vr, value))
711 {
712 return false;
713 }
714
715 RemoveTagPadding(value, vr);
716
717 return true;
718 }
719
720
721 bool DicomMap::ParseDicomMetaInformation(DicomMap& result,
722 const char* dicom,
723 size_t size)
724 {
725 /**
726 * http://dicom.nema.org/medical/dicom/current/output/chtml/part10/chapter_7.html
727 * According to Table 7.1-1, besides the "DICM" DICOM prefix, the
728 * file preamble (i.e. dicom[0..127]) should not be taken into
729 * account to determine whether the file is or is not a DICOM file.
730 **/
731
732 if (size < 132 ||
733 dicom[128] != 'D' ||
734 dicom[129] != 'I' ||
735 dicom[130] != 'C' ||
736 dicom[131] != 'M')
737 {
738 return false;
739 }
740
741
742 /**
743 * The DICOM File Meta Information must be encoded using the
744 * Explicit VR Little Endian Transfer Syntax
745 * (UID=1.2.840.10008.1.2.1).
746 **/
747
748 result.Clear();
749
750 // First, we read the "File Meta Information Group Length" tag
751 // (0002,0000) to know where to stop reading the meta header
752 size_t position = 132;
753
754 DicomTag tag(0x0000, 0x0000); // Dummy initialization
755 ValueRepresentation vr;
756 std::string value;
757 if (!ReadNextTag(tag, vr, value, dicom, size, position) ||
758 tag.GetGroup() != 0x0002 ||
759 tag.GetElement() != 0x0000 ||
760 vr != ValueRepresentation_UnsignedLong ||
761 value.size() != 4)
762 {
763 return false;
764 }
765
766 size_t stopPosition = position + ReadUnsignedInteger32(value.c_str());
767 if (stopPosition > size)
768 {
769 return false;
770 }
771
772 while (position < stopPosition)
773 {
774 if (ReadNextTag(tag, vr, value, dicom, size, position))
775 {
776 result.SetValue(tag, value, IsBinaryValueRepresentation(vr));
777 }
778 else
779 {
780 return false;
781 }
782 }
783
784 return true;
785 }
786
787
788 static std::string ValueAsString(const DicomMap& summary,
789 const DicomTag& tag)
790 {
791 const DicomValue& value = summary.GetValue(tag);
792 if (value.IsNull())
793 {
794 return "(null)";
795 }
796 else
797 {
798 return value.GetContent();
799 }
800 }
801
802
803 void DicomMap::LogMissingTagsForStore() const
804 {
805 std::string s, t;
806
807 if (HasTag(DICOM_TAG_PATIENT_ID))
808 {
809 if (t.size() > 0)
810 t += ", ";
811 t += "PatientID=" + ValueAsString(*this, DICOM_TAG_PATIENT_ID);
812 }
813 else
814 {
815 if (s.size() > 0)
816 s += ", ";
817 s += "PatientID";
818 }
819
820 if (HasTag(DICOM_TAG_STUDY_INSTANCE_UID))
821 {
822 if (t.size() > 0)
823 t += ", ";
824 t += "StudyInstanceUID=" + ValueAsString(*this, DICOM_TAG_STUDY_INSTANCE_UID);
825 }
826 else
827 {
828 if (s.size() > 0)
829 s += ", ";
830 s += "StudyInstanceUID";
831 }
832
833 if (HasTag(DICOM_TAG_SERIES_INSTANCE_UID))
834 {
835 if (t.size() > 0)
836 t += ", ";
837 t += "SeriesInstanceUID=" + ValueAsString(*this, DICOM_TAG_SERIES_INSTANCE_UID);
838 }
839 else
840 {
841 if (s.size() > 0)
842 s += ", ";
843 s += "SeriesInstanceUID";
844 }
845
846 if (HasTag(DICOM_TAG_SOP_INSTANCE_UID))
847 {
848 if (t.size() > 0)
849 t += ", ";
850 t += "SOPInstanceUID=" + ValueAsString(*this, DICOM_TAG_SOP_INSTANCE_UID);
851 }
852 else
853 {
854 if (s.size() > 0)
855 s += ", ";
856 s += "SOPInstanceUID";
857 }
858
859 if (t.size() == 0)
860 {
861 LOG(ERROR) << "Store has failed because all the required tags (" << s << ") are missing (is it a DICOMDIR file?)";
862 }
863 else
864 {
865 LOG(ERROR) << "Store has failed because required tags (" << s << ") are missing for the following instance: " << t;
866 }
867 }
868
869
870 bool DicomMap::CopyToString(std::string& result,
871 const DicomTag& tag,
872 bool allowBinary) const
873 {
874 const DicomValue* value = TestAndGetValue(tag);
875
876 if (value == NULL)
877 {
878 return false;
879 }
880 else
881 {
882 return value->CopyToString(result, allowBinary);
883 }
884 }
885
886 bool DicomMap::ParseInteger32(int32_t& result,
887 const DicomTag& tag) const
888 {
889 const DicomValue* value = TestAndGetValue(tag);
890
891 if (value == NULL)
892 {
893 return false;
894 }
895 else
896 {
897 return value->ParseInteger32(result);
898 }
899 }
900
901 bool DicomMap::ParseInteger64(int64_t& result,
902 const DicomTag& tag) const
903 {
904 const DicomValue* value = TestAndGetValue(tag);
905
906 if (value == NULL)
907 {
908 return false;
909 }
910 else
911 {
912 return value->ParseInteger64(result);
913 }
914 }
915
916 bool DicomMap::ParseUnsignedInteger32(uint32_t& result,
917 const DicomTag& tag) const
918 {
919 const DicomValue* value = TestAndGetValue(tag);
920
921 if (value == NULL)
922 {
923 return false;
924 }
925 else
926 {
927 return value->ParseUnsignedInteger32(result);
928 }
929 }
930
931 bool DicomMap::ParseUnsignedInteger64(uint64_t& result,
932 const DicomTag& tag) const
933 {
934 const DicomValue* value = TestAndGetValue(tag);
935
936 if (value == NULL)
937 {
938 return false;
939 }
940 else
941 {
942 return value->ParseUnsignedInteger64(result);
943 }
944 }
945
946 bool DicomMap::ParseFloat(float& result,
947 const DicomTag& tag) const
948 {
949 const DicomValue* value = TestAndGetValue(tag);
950
951 if (value == NULL)
952 {
953 return false;
954 }
955 else
956 {
957 return value->ParseFloat(result);
958 }
959 }
960
961 bool DicomMap::ParseDouble(double& result,
962 const DicomTag& tag) const
963 {
964 const DicomValue* value = TestAndGetValue(tag);
965
966 if (value == NULL)
967 {
968 return false;
969 }
970 else
971 {
972 return value->ParseDouble(result);
973 }
974 }
975 }