Mercurial > hg > orthanc
comparison OrthancFramework/UnitTestsSources/DicomMapTests.cpp @ 4215:28e9457dc7ab
working on sequences
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 29 Sep 2020 16:30:24 +0200 |
parents | 7b011cfda135 |
children | 61585d8a9faf |
comparison
equal
deleted
inserted
replaced
4214:7b011cfda135 | 4215:28e9457dc7ab |
---|---|
787 public: | 787 public: |
788 virtual ~IVisitor() | 788 virtual ~IVisitor() |
789 { | 789 { |
790 } | 790 } |
791 | 791 |
792 // The data from this function will always be Little Endian (as | |
793 // specified by the DICOM standard) | |
792 virtual void VisitMetaHeaderTag(const DicomTag& tag, | 794 virtual void VisitMetaHeaderTag(const DicomTag& tag, |
793 const ValueRepresentation& vr, | 795 const ValueRepresentation& vr, |
794 const std::string& value) = 0; | 796 const std::string& value) = 0; |
795 | 797 |
796 // Return "false" to stop processing | 798 // Return "false" to stop processing |
797 virtual bool VisitDatasetTag(const DicomTag& tag, | 799 virtual bool VisitDatasetTag(const DicomTag& tag, |
798 const ValueRepresentation& vr, | 800 const ValueRepresentation& vr, |
799 DicomTransferSyntax transferSyntax, | 801 DicomTransferSyntax transferSyntax, |
800 const std::string& value) = 0; | 802 const std::string& value, |
803 bool isLittleEndian) = 0; | |
801 }; | 804 }; |
802 | 805 |
803 private: | 806 private: |
804 enum State | 807 enum State |
805 { | 808 { |
812 }; | 815 }; |
813 | 816 |
814 StreamBlockReader reader_; | 817 StreamBlockReader reader_; |
815 State state_; | 818 State state_; |
816 DicomTransferSyntax transferSyntax_; | 819 DicomTransferSyntax transferSyntax_; |
820 DicomTag previousTag_; | |
817 DicomTag danglingTag_; | 821 DicomTag danglingTag_; |
818 ValueRepresentation danglingVR_; | 822 ValueRepresentation danglingVR_; |
823 unsigned int sequenceDepth_; | |
819 | 824 |
820 static uint16_t ReadUnsignedInteger16(const char* dicom, | 825 static uint16_t ReadUnsignedInteger16(const char* dicom, |
821 bool littleEndian) | 826 bool littleEndian) |
822 { | 827 { |
823 const uint8_t* p = reinterpret_cast<const uint8_t*>(dicom); | 828 const uint8_t* p = reinterpret_cast<const uint8_t*>(dicom); |
892 vr == ValueRepresentation_ShortText /* ST */ || | 897 vr == ValueRepresentation_ShortText /* ST */ || |
893 vr == ValueRepresentation_Time /* TM */ || | 898 vr == ValueRepresentation_Time /* TM */ || |
894 vr == ValueRepresentation_UniqueIdentifier /* UI */ || | 899 vr == ValueRepresentation_UniqueIdentifier /* UI */ || |
895 vr == ValueRepresentation_UnsignedLong /* UL */ || | 900 vr == ValueRepresentation_UnsignedLong /* UL */ || |
896 vr == ValueRepresentation_UnsignedShort /* US */); | 901 vr == ValueRepresentation_UnsignedShort /* US */); |
902 } | |
903 | |
904 | |
905 bool IsLittleEndian() const | |
906 { | |
907 return (transferSyntax_ != DicomTransferSyntax_BigEndianExplicit); | |
897 } | 908 } |
898 | 909 |
899 | 910 |
900 void PrintBlock(const std::string& block) | 911 void PrintBlock(const std::string& block) |
901 { | 912 { |
1029 | 1040 |
1030 | 1041 |
1031 void HandleDatasetTag(IVisitor& visitor, | 1042 void HandleDatasetTag(IVisitor& visitor, |
1032 const std::string& block) | 1043 const std::string& block) |
1033 { | 1044 { |
1034 printf("DATASET TAG:\n"); | 1045 static const DicomTag DICOM_TAG_SEQUENCE_ITEM(0xfffe, 0xe000); |
1035 PrintBlock(block); | 1046 static const DicomTag DICOM_TAG_SEQUENCE_DELIMITATION_ITEM(0xfffe, 0xe00d); |
1047 static const DicomTag DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE(0xfffe, 0xe0dd); | |
1048 | |
1049 //printf("DATASET TAG:\n"); | |
1050 //PrintBlock(block); | |
1036 | 1051 |
1037 assert(block.size() == 8u); | 1052 assert(block.size() == 8u); |
1038 | 1053 |
1039 const bool littleEndian = (transferSyntax_ != DicomTransferSyntax_BigEndianExplicit); | 1054 const bool littleEndian = IsLittleEndian(); |
1055 DicomTag tag = ReadTag(block.c_str(), littleEndian); | |
1056 | |
1057 if (tag == DICOM_TAG_SEQUENCE_ITEM || | |
1058 tag == DICOM_TAG_SEQUENCE_DELIMITATION_ITEM || | |
1059 tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE) | |
1060 { | |
1061 printf("SEQUENCE TAG:\n"); | |
1062 PrintBlock(block); | |
1063 | |
1064 // The special sequence items are encoded like "Implicit VR" | |
1065 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, littleEndian); | |
1066 | |
1067 if (tag == DICOM_TAG_SEQUENCE_ITEM) | |
1068 { | |
1069 for (unsigned int i = 0; i <= sequenceDepth_; i++) | |
1070 printf(" "); | |
1071 if (length == 0xffffffffu) | |
1072 { | |
1073 // Undefined length: Need to loop over the tags of the nested dataset | |
1074 printf("...next dataset in sequence...\n"); | |
1075 reader_.Schedule(8); | |
1076 state_ = State_DatasetTag; | |
1077 } | |
1078 else | |
1079 { | |
1080 // Explicit length: Can skip the full sequence at once | |
1081 printf("...next dataset in sequence... %u bytes\n", length); | |
1082 reader_.Schedule(length); | |
1083 state_ = State_DatasetValue; | |
1084 } | |
1085 } | |
1086 else if (tag == DICOM_TAG_SEQUENCE_DELIMITATION_ITEM || | |
1087 tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE) | |
1088 { | |
1089 if (length != 0 || | |
1090 sequenceDepth_ == 0) | |
1091 { | |
1092 throw OrthancException(ErrorCode_BadFileFormat); | |
1093 } | |
1094 | |
1095 if (tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE) | |
1096 { | |
1097 sequenceDepth_ --; | |
1098 | |
1099 for (unsigned int i = 0; i <= sequenceDepth_; i++) | |
1100 printf(" "); | |
1101 printf("...leaving sequence...\n"); | |
1102 } | |
1103 | |
1104 reader_.Schedule(8); | |
1105 state_ = State_DatasetTag; | |
1106 } | |
1107 else | |
1108 { | |
1109 throw OrthancException(ErrorCode_InternalError); | |
1110 } | |
1111 } | |
1112 else | |
1113 { | |
1114 ValueRepresentation vr = ValueRepresentation_Unknown; | |
1040 | 1115 |
1041 danglingTag_ = ReadTag(block.c_str(), littleEndian); | 1116 if (transferSyntax_ == DicomTransferSyntax_LittleEndianImplicit) |
1042 danglingVR_ = ValueRepresentation_Unknown; | 1117 { |
1043 | 1118 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, true /* little endian */); |
1044 /*if (danglingTag_ == DICOM_TAG_PIXEL_DATA) | |
1045 { | |
1046 state_ = State_Done; | |
1047 return; | |
1048 }*/ | |
1049 | |
1050 if (transferSyntax_ == DicomTransferSyntax_LittleEndianImplicit) | |
1051 { | |
1052 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, true /* little endian */); | |
1053 | 1119 |
1054 reader_.Schedule(length); | |
1055 state_ = State_DatasetValue; | |
1056 } | |
1057 else | |
1058 { | |
1059 // This in an explicit transfer syntax | |
1060 | |
1061 danglingVR_ = StringToValueRepresentation( | |
1062 std::string(block.c_str() + 4, 2), false /* ignore unknown VR */); | |
1063 | |
1064 if (IsShortExplicitTag(danglingVR_)) | |
1065 { | |
1066 uint16_t length = ReadUnsignedInteger16(block.c_str() + 6, littleEndian); | |
1067 | |
1068 reader_.Schedule(length); | 1120 reader_.Schedule(length); |
1069 state_ = State_DatasetValue; | 1121 state_ = State_DatasetValue; |
1070 } | 1122 } |
1071 else | 1123 else |
1072 { | 1124 { |
1073 uint16_t reserved = ReadUnsignedInteger16(block.c_str() + 6, littleEndian); | 1125 // This in an explicit transfer syntax |
1074 if (reserved != 0) | 1126 |
1127 vr = StringToValueRepresentation( | |
1128 std::string(block.c_str() + 4, 2), false /* ignore unknown VR */); | |
1129 | |
1130 if (vr == ValueRepresentation_Sequence) | |
1075 { | 1131 { |
1076 throw OrthancException(ErrorCode_BadFileFormat); | 1132 for (unsigned int i = 0; i <= sequenceDepth_; i++) |
1133 printf(" "); | |
1134 printf("...entering sequence... %s\n", previousTag_.Format().c_str()); | |
1135 sequenceDepth_ ++; | |
1136 reader_.Schedule(4); | |
1137 state_ = State_DatasetExplicitLength; | |
1077 } | 1138 } |
1078 | 1139 else if (IsShortExplicitTag(vr)) |
1079 reader_.Schedule(4); | 1140 { |
1080 state_ = State_DatasetExplicitLength; | 1141 uint16_t length = ReadUnsignedInteger16(block.c_str() + 6, littleEndian); |
1142 | |
1143 reader_.Schedule(length); | |
1144 state_ = State_DatasetValue; | |
1145 } | |
1146 else | |
1147 { | |
1148 uint16_t reserved = ReadUnsignedInteger16(block.c_str() + 6, littleEndian); | |
1149 if (reserved != 0) | |
1150 { | |
1151 throw OrthancException(ErrorCode_BadFileFormat); | |
1152 } | |
1153 | |
1154 reader_.Schedule(4); | |
1155 state_ = State_DatasetExplicitLength; | |
1156 } | |
1081 } | 1157 } |
1082 }; | 1158 |
1159 previousTag_ = tag; | |
1160 | |
1161 if (sequenceDepth_ == 0) | |
1162 { | |
1163 danglingTag_ = tag; | |
1164 danglingVR_ = vr; | |
1165 } | |
1166 else | |
1167 { | |
1168 for (unsigned int i = 0; i <= sequenceDepth_; i++) | |
1169 printf(" "); | |
1170 printf(" %s\n", tag.Format().c_str()); | |
1171 } | |
1172 } | |
1083 } | 1173 } |
1084 | 1174 |
1085 | 1175 |
1086 void HandleDatasetExplicitLength(IVisitor& visitor, | 1176 void HandleDatasetExplicitLength(IVisitor& visitor, |
1087 const std::string& block) | 1177 const std::string& block) |
1089 //printf("DATASET TAG LENGTH:\n"); | 1179 //printf("DATASET TAG LENGTH:\n"); |
1090 //PrintBlock(block); | 1180 //PrintBlock(block); |
1091 | 1181 |
1092 assert(block.size() == 4); | 1182 assert(block.size() == 4); |
1093 | 1183 |
1094 const bool littleEndian = (transferSyntax_ != DicomTransferSyntax_BigEndianExplicit); | 1184 uint32_t length = ReadUnsignedInteger32(block.c_str(), IsLittleEndian()); |
1095 | |
1096 uint32_t length = ReadUnsignedInteger32(block.c_str(), littleEndian); | |
1097 if (length == 0xffffffffu) | 1185 if (length == 0xffffffffu) |
1098 { | 1186 { |
1099 // http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.5.html | |
1100 printf("AIE\n"); | |
1101 | |
1102 /** | 1187 /** |
1103 * This is the case for compressed transfer syntaxes. We stop | 1188 * This is the case of sequences, or pixel data with |
1104 * the processing here, as this would cause StreamBlockReader | 1189 * compressed transfer syntaxes. Schedule the reading of the |
1105 * to allocate a huge memory buffer of 2GB. | 1190 * first tag of the nested dataset. |
1191 * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.5.html | |
1106 **/ | 1192 **/ |
1107 state_ = State_Done; | 1193 |
1194 state_ = State_DatasetTag; | |
1195 reader_.Schedule(8); | |
1108 } | 1196 } |
1109 else | 1197 else |
1110 { | 1198 { |
1111 reader_.Schedule(length); | 1199 reader_.Schedule(length); |
1112 state_ = State_DatasetValue; | 1200 state_ = State_DatasetValue; |
1117 public: | 1205 public: |
1118 DicomStreamReader(std::istream& stream) : | 1206 DicomStreamReader(std::istream& stream) : |
1119 reader_(stream), | 1207 reader_(stream), |
1120 state_(State_Preamble), | 1208 state_(State_Preamble), |
1121 transferSyntax_(DicomTransferSyntax_LittleEndianImplicit), // Dummy | 1209 transferSyntax_(DicomTransferSyntax_LittleEndianImplicit), // Dummy |
1210 previousTag_(0x0000, 0x0000), // Dummy | |
1122 danglingTag_(0x0000, 0x0000), // Dummy | 1211 danglingTag_(0x0000, 0x0000), // Dummy |
1123 danglingVR_(ValueRepresentation_Unknown) // Dummy | 1212 danglingVR_(ValueRepresentation_Unknown), // Dummy |
1213 sequenceDepth_(0) | |
1124 { | 1214 { |
1125 reader_.Schedule(128 /* empty header */ + | 1215 reader_.Schedule(128 /* empty header */ + |
1126 4 /* "DICM" magic value */ + | 1216 4 /* "DICM" magic value */ + |
1127 4 /* (0x0002, 0x0000) tag */ + | 1217 4 /* (0x0002, 0x0000) tag */ + |
1128 2 /* value representation of (0x0002, 0x0000) == "UL" */ + | 1218 2 /* value representation of (0x0002, 0x0000) == "UL" */ + |
1154 case State_DatasetExplicitLength: | 1244 case State_DatasetExplicitLength: |
1155 HandleDatasetExplicitLength(visitor, block); | 1245 HandleDatasetExplicitLength(visitor, block); |
1156 break; | 1246 break; |
1157 | 1247 |
1158 case State_DatasetValue: | 1248 case State_DatasetValue: |
1159 if (visitor.VisitDatasetTag(danglingTag_, danglingVR_, transferSyntax_, block)) | 1249 if (sequenceDepth_ == 0 && |
1250 !visitor.VisitDatasetTag(danglingTag_, danglingVR_, transferSyntax_, block, IsLittleEndian())) | |
1251 { | |
1252 state_ = State_Done; | |
1253 } | |
1254 else | |
1160 { | 1255 { |
1161 reader_.Schedule(8); | 1256 reader_.Schedule(8); |
1162 state_ = State_DatasetTag; | 1257 state_ = State_DatasetTag; |
1163 } | 1258 } |
1164 else | 1259 |
1165 { | |
1166 state_ = State_Done; | |
1167 } | |
1168 break; | 1260 break; |
1169 | 1261 |
1170 default: | 1262 default: |
1171 throw OrthancException(ErrorCode_InternalError); | 1263 throw OrthancException(ErrorCode_InternalError); |
1172 } | 1264 } |
1194 class V : public DicomStreamReader::IVisitor | 1286 class V : public DicomStreamReader::IVisitor |
1195 { | 1287 { |
1196 public: | 1288 public: |
1197 virtual void VisitMetaHeaderTag(const DicomTag& tag, | 1289 virtual void VisitMetaHeaderTag(const DicomTag& tag, |
1198 const ValueRepresentation& vr, | 1290 const ValueRepresentation& vr, |
1199 const std::string& value) | 1291 const std::string& value) ORTHANC_OVERRIDE |
1200 { | 1292 { |
1201 std::cout << "Header: " << tag.Format() << " [" << value.c_str() << "] (" << value.size() << ")" << std::endl; | 1293 std::cout << "Header: " << tag.Format() << " [" << Toolbox::ConvertToAscii(value).c_str() << "] (" << value.size() << ")" << std::endl; |
1202 } | 1294 } |
1203 | 1295 |
1204 virtual bool VisitDatasetTag(const DicomTag& tag, | 1296 virtual bool VisitDatasetTag(const DicomTag& tag, |
1205 const ValueRepresentation& vr, | 1297 const ValueRepresentation& vr, |
1206 DicomTransferSyntax transferSyntax, | 1298 DicomTransferSyntax transferSyntax, |
1207 const std::string& value) | 1299 const std::string& value, |
1208 { | 1300 bool isLittleEndian) ORTHANC_OVERRIDE |
1301 { | |
1302 if (!isLittleEndian) | |
1303 printf("** "); | |
1209 if (tag.GetGroup() < 0x7f00) | 1304 if (tag.GetGroup() < 0x7f00) |
1210 std::cout << "Dataset: " << tag.Format() << " [" << value.c_str() << "] (" << value.size() << ")" << std::endl; | 1305 std::cout << "Dataset: " << tag.Format() << " [" << Toolbox::ConvertToAscii(value).c_str() << "] (" << value.size() << ")" << std::endl; |
1211 else | 1306 else |
1212 std::cout << "Dataset: " << tag.Format() << " [PIXEL] (" << value.size() << ")" << std::endl; | 1307 std::cout << "Dataset: " << tag.Format() << " [PIXEL] (" << value.size() << ")" << std::endl; |
1213 | 1308 |
1214 return true; | 1309 return true; |
1215 } | 1310 } |
1222 { | 1317 { |
1223 static const std::string PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/"; | 1318 static const std::string PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/"; |
1224 | 1319 |
1225 std::string dicom; | 1320 std::string dicom; |
1226 //SystemToolbox::ReadFile(dicom, PATH + "../ColorTestMalaterre.dcm", false); | 1321 //SystemToolbox::ReadFile(dicom, PATH + "../ColorTestMalaterre.dcm", false); |
1322 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.1.dcm", false); | |
1227 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.2.dcm", false); // Big Endian | 1323 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.2.dcm", false); // Big Endian |
1228 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.1.dcm", false); | |
1229 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.50.dcm", false); | 1324 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.50.dcm", false); |
1230 SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.51.dcm", false); | 1325 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.51.dcm", false); |
1326 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.57.dcm", false); | |
1327 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.70.dcm", false); | |
1328 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.80.dcm", false); | |
1329 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.81.dcm", false); | |
1330 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.90.dcm", false); | |
1331 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.91.dcm", false); | |
1332 SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.5.dcm", false); | |
1231 | 1333 |
1232 std::stringstream stream; | 1334 std::stringstream stream; |
1233 size_t pos = 0; | 1335 size_t pos = 0; |
1234 | 1336 |
1235 DicomStreamReader r(stream); | 1337 DicomStreamReader r(stream); |