Mercurial > hg > orthanc
comparison OrthancFramework/UnitTestsSources/DicomMapTests.cpp @ 4216:61585d8a9faf
fix
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 29 Sep 2020 19:44:38 +0200 |
parents | 28e9457dc7ab |
children | 78c8b4a18619 |
comparison
equal
deleted
inserted
replaced
4215:28e9457dc7ab | 4216:61585d8a9faf |
---|---|
807 enum State | 807 enum State |
808 { | 808 { |
809 State_Preamble, | 809 State_Preamble, |
810 State_MetaHeader, | 810 State_MetaHeader, |
811 State_DatasetTag, | 811 State_DatasetTag, |
812 State_SequenceExplicitLength, | |
813 State_SequenceExplicitValue, | |
812 State_DatasetExplicitLength, | 814 State_DatasetExplicitLength, |
813 State_DatasetValue, | 815 State_DatasetValue, |
814 State_Done | 816 State_Done |
815 }; | 817 }; |
816 | 818 |
817 StreamBlockReader reader_; | 819 StreamBlockReader reader_; |
818 State state_; | 820 State state_; |
819 DicomTransferSyntax transferSyntax_; | 821 DicomTransferSyntax transferSyntax_; |
820 DicomTag previousTag_; | |
821 DicomTag danglingTag_; | 822 DicomTag danglingTag_; |
822 ValueRepresentation danglingVR_; | 823 ValueRepresentation danglingVR_; |
823 unsigned int sequenceDepth_; | 824 unsigned int sequenceDepth_; |
824 | 825 |
825 static uint16_t ReadUnsignedInteger16(const char* dicom, | 826 static uint16_t ReadUnsignedInteger16(const char* dicom, |
920 } | 921 } |
921 | 922 |
922 void HandlePreamble(IVisitor& visitor, | 923 void HandlePreamble(IVisitor& visitor, |
923 const std::string& block) | 924 const std::string& block) |
924 { | 925 { |
925 printf("PREAMBLE:\n"); | 926 //printf("PREAMBLE:\n"); |
926 PrintBlock(block); | 927 //PrintBlock(block); |
927 | 928 |
928 assert(block.size() == 144u); | 929 assert(block.size() == 144u); |
929 assert(reader_.GetProcessedBytes() == 144u); | 930 assert(reader_.GetProcessedBytes() == 144u); |
930 | 931 |
931 /** | 932 /** |
953 | 954 |
954 | 955 |
955 void HandleMetaHeader(IVisitor& visitor, | 956 void HandleMetaHeader(IVisitor& visitor, |
956 const std::string& block) | 957 const std::string& block) |
957 { | 958 { |
958 printf("META-HEADER:\n"); | 959 //printf("META-HEADER:\n"); |
959 PrintBlock(block); | 960 //PrintBlock(block); |
960 | 961 |
961 size_t pos = 0; | 962 size_t pos = 0; |
962 const char* p = block.c_str(); | 963 const char* p = block.c_str(); |
963 | 964 |
964 bool hasTransferSyntax = false; | 965 bool hasTransferSyntax = false; |
1037 reader_.Schedule(8); | 1038 reader_.Schedule(8); |
1038 state_ = State_DatasetTag; | 1039 state_ = State_DatasetTag; |
1039 } | 1040 } |
1040 | 1041 |
1041 | 1042 |
1042 void HandleDatasetTag(IVisitor& visitor, | 1043 void HandleDatasetTag(const std::string& block) |
1043 const std::string& block) | |
1044 { | 1044 { |
1045 static const DicomTag DICOM_TAG_SEQUENCE_ITEM(0xfffe, 0xe000); | 1045 static const DicomTag DICOM_TAG_SEQUENCE_ITEM(0xfffe, 0xe000); |
1046 static const DicomTag DICOM_TAG_SEQUENCE_DELIMITATION_ITEM(0xfffe, 0xe00d); | 1046 static const DicomTag DICOM_TAG_SEQUENCE_DELIMITATION_ITEM(0xfffe, 0xe00d); |
1047 static const DicomTag DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE(0xfffe, 0xe0dd); | 1047 static const DicomTag DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE(0xfffe, 0xe0dd); |
1048 | 1048 |
1049 //printf("DATASET TAG:\n"); | |
1050 //PrintBlock(block); | |
1051 | |
1052 assert(block.size() == 8u); | 1049 assert(block.size() == 8u); |
1053 | 1050 |
1054 const bool littleEndian = IsLittleEndian(); | 1051 const bool littleEndian = IsLittleEndian(); |
1055 DicomTag tag = ReadTag(block.c_str(), littleEndian); | 1052 DicomTag tag = ReadTag(block.c_str(), littleEndian); |
1056 | 1053 |
1057 if (tag == DICOM_TAG_SEQUENCE_ITEM || | 1054 if (tag == DICOM_TAG_SEQUENCE_ITEM || |
1058 tag == DICOM_TAG_SEQUENCE_DELIMITATION_ITEM || | 1055 tag == DICOM_TAG_SEQUENCE_DELIMITATION_ITEM || |
1059 tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE) | 1056 tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE) |
1060 { | 1057 { |
1061 printf("SEQUENCE TAG:\n"); | 1058 //printf("SEQUENCE TAG:\n"); |
1062 PrintBlock(block); | 1059 //PrintBlock(block); |
1063 | 1060 |
1064 // The special sequence items are encoded like "Implicit VR" | 1061 // The special sequence items are encoded like "Implicit VR" |
1065 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, littleEndian); | 1062 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, littleEndian); |
1066 | 1063 |
1067 if (tag == DICOM_TAG_SEQUENCE_ITEM) | 1064 if (tag == DICOM_TAG_SEQUENCE_ITEM) |
1092 throw OrthancException(ErrorCode_BadFileFormat); | 1089 throw OrthancException(ErrorCode_BadFileFormat); |
1093 } | 1090 } |
1094 | 1091 |
1095 if (tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE) | 1092 if (tag == DICOM_TAG_SEQUENCE_DELIMITATION_SEQUENCE) |
1096 { | 1093 { |
1097 sequenceDepth_ --; | 1094 for (unsigned int i = 0; i < sequenceDepth_; i++) |
1098 | |
1099 for (unsigned int i = 0; i <= sequenceDepth_; i++) | |
1100 printf(" "); | 1095 printf(" "); |
1101 printf("...leaving sequence...\n"); | 1096 printf("...leaving sequence...\n"); |
1097 | |
1098 sequenceDepth_ --; | |
1099 } | |
1100 else | |
1101 { | |
1102 if (sequenceDepth_ == 0) | |
1103 { | |
1104 throw OrthancException(ErrorCode_BadFileFormat); | |
1105 } | |
1102 } | 1106 } |
1103 | 1107 |
1104 reader_.Schedule(8); | 1108 reader_.Schedule(8); |
1105 state_ = State_DatasetTag; | 1109 state_ = State_DatasetTag; |
1106 } | 1110 } |
1109 throw OrthancException(ErrorCode_InternalError); | 1113 throw OrthancException(ErrorCode_InternalError); |
1110 } | 1114 } |
1111 } | 1115 } |
1112 else | 1116 else |
1113 { | 1117 { |
1118 //printf("DATASET TAG:\n"); | |
1119 //PrintBlock(block); | |
1120 | |
1114 ValueRepresentation vr = ValueRepresentation_Unknown; | 1121 ValueRepresentation vr = ValueRepresentation_Unknown; |
1115 | 1122 |
1116 if (transferSyntax_ == DicomTransferSyntax_LittleEndianImplicit) | 1123 if (transferSyntax_ == DicomTransferSyntax_LittleEndianImplicit) |
1117 { | 1124 { |
1118 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, true /* little endian */); | 1125 uint32_t length = ReadUnsignedInteger32(block.c_str() + 4, true /* little endian */); |
1121 state_ = State_DatasetValue; | 1128 state_ = State_DatasetValue; |
1122 } | 1129 } |
1123 else | 1130 else |
1124 { | 1131 { |
1125 // This in an explicit transfer syntax | 1132 // This in an explicit transfer syntax |
1126 | 1133 |
1127 vr = StringToValueRepresentation( | 1134 vr = StringToValueRepresentation( |
1128 std::string(block.c_str() + 4, 2), false /* ignore unknown VR */); | 1135 std::string(block.c_str() + 4, 2), false /* ignore unknown VR */); |
1129 | 1136 |
1130 if (vr == ValueRepresentation_Sequence) | 1137 if (vr != ValueRepresentation_Sequence && |
1138 sequenceDepth_ > 0) | |
1131 { | 1139 { |
1132 for (unsigned int i = 0; i <= sequenceDepth_; i++) | 1140 for (unsigned int i = 0; i <= sequenceDepth_; i++) |
1133 printf(" "); | 1141 printf(" "); |
1134 printf("...entering sequence... %s\n", previousTag_.Format().c_str()); | 1142 printf("%s\n", tag.Format().c_str()); |
1143 } | |
1144 | |
1145 if (vr == ValueRepresentation_Sequence) | |
1146 { | |
1147 for (unsigned int i = 0; i <= sequenceDepth_; i++) | |
1148 printf(" "); | |
1149 printf("...entering sequence... %s\n", tag.Format().c_str()); | |
1135 sequenceDepth_ ++; | 1150 sequenceDepth_ ++; |
1136 reader_.Schedule(4); | 1151 reader_.Schedule(4); |
1137 state_ = State_DatasetExplicitLength; | 1152 state_ = State_SequenceExplicitLength; |
1138 } | 1153 } |
1139 else if (IsShortExplicitTag(vr)) | 1154 else if (IsShortExplicitTag(vr)) |
1140 { | 1155 { |
1141 uint16_t length = ReadUnsignedInteger16(block.c_str() + 6, littleEndian); | 1156 uint16_t length = ReadUnsignedInteger16(block.c_str() + 6, littleEndian); |
1142 | 1157 |
1154 reader_.Schedule(4); | 1169 reader_.Schedule(4); |
1155 state_ = State_DatasetExplicitLength; | 1170 state_ = State_DatasetExplicitLength; |
1156 } | 1171 } |
1157 } | 1172 } |
1158 | 1173 |
1159 previousTag_ = tag; | |
1160 | |
1161 if (sequenceDepth_ == 0) | 1174 if (sequenceDepth_ == 0) |
1162 { | 1175 { |
1163 danglingTag_ = tag; | 1176 danglingTag_ = tag; |
1164 danglingVR_ = vr; | 1177 danglingVR_ = vr; |
1165 } | 1178 } |
1166 else | 1179 } |
1167 { | 1180 } |
1168 for (unsigned int i = 0; i <= sequenceDepth_; i++) | 1181 |
1169 printf(" "); | 1182 |
1170 printf(" %s\n", tag.Format().c_str()); | 1183 void HandleDatasetExplicitLength(const std::string& block) |
1171 } | |
1172 } | |
1173 } | |
1174 | |
1175 | |
1176 void HandleDatasetExplicitLength(IVisitor& visitor, | |
1177 const std::string& block) | |
1178 { | 1184 { |
1179 //printf("DATASET TAG LENGTH:\n"); | 1185 //printf("DATASET TAG LENGTH:\n"); |
1180 //PrintBlock(block); | 1186 //PrintBlock(block); |
1181 | 1187 |
1182 assert(block.size() == 4); | 1188 assert(block.size() == 4); |
1183 | 1189 |
1184 uint32_t length = ReadUnsignedInteger32(block.c_str(), IsLittleEndian()); | 1190 uint32_t length = ReadUnsignedInteger32(block.c_str(), IsLittleEndian()); |
1191 | |
1185 if (length == 0xffffffffu) | 1192 if (length == 0xffffffffu) |
1186 { | 1193 { |
1187 /** | 1194 /** |
1188 * This is the case of sequences, or pixel data with | 1195 * This is the case of pixel data with compressed transfer |
1189 * compressed transfer syntaxes. Schedule the reading of the | 1196 * syntaxes. Schedule the reading of the first tag of the |
1190 * first tag of the nested dataset. | 1197 * nested dataset. |
1191 * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.5.html | 1198 * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_7.5.html |
1192 **/ | 1199 **/ |
1193 | 1200 |
1201 if (sequenceDepth_ != 0) | |
1202 { | |
1203 throw OrthancException(ErrorCode_BadFileFormat); | |
1204 } | |
1205 | |
1206 printf(" ...entering sequence... %s\n", danglingTag_.Format().c_str()); | |
1194 state_ = State_DatasetTag; | 1207 state_ = State_DatasetTag; |
1195 reader_.Schedule(8); | 1208 reader_.Schedule(8); |
1209 sequenceDepth_ ++; | |
1196 } | 1210 } |
1197 else | 1211 else |
1198 { | 1212 { |
1199 reader_.Schedule(length); | 1213 reader_.Schedule(length); |
1200 state_ = State_DatasetValue; | 1214 state_ = State_DatasetValue; |
1201 } | 1215 } |
1216 } | |
1217 | |
1218 | |
1219 void HandleSequenceExplicitLength(const std::string& block) | |
1220 { | |
1221 //printf("DATASET TAG LENGTH:\n"); | |
1222 //PrintBlock(block); | |
1223 | |
1224 assert(block.size() == 4); | |
1225 | |
1226 uint32_t length = ReadUnsignedInteger32(block.c_str(), IsLittleEndian()); | |
1227 if (length == 0xffffffffu) | |
1228 { | |
1229 state_ = State_DatasetTag; | |
1230 reader_.Schedule(8); | |
1231 } | |
1232 else | |
1233 { | |
1234 for (unsigned int i = 0; i <= sequenceDepth_; i++) | |
1235 printf(" "); | |
1236 printf("...skipping sequence thanks to explicit length... %d\n", length); | |
1237 | |
1238 reader_.Schedule(length); | |
1239 state_ = State_SequenceExplicitValue; | |
1240 } | |
1241 } | |
1242 | |
1243 void HandleSequenceExplicitValue() | |
1244 { | |
1245 if (sequenceDepth_ == 0) | |
1246 { | |
1247 throw OrthancException(ErrorCode_InternalError); | |
1248 } | |
1249 | |
1250 sequenceDepth_ --; | |
1251 | |
1252 state_ = State_DatasetTag; | |
1253 reader_.Schedule(8); | |
1254 } | |
1255 | |
1256 | |
1257 void HandleDatasetValue(IVisitor& visitor, | |
1258 const std::string& block) | |
1259 { | |
1260 if (sequenceDepth_ == 0) | |
1261 { | |
1262 bool c; | |
1263 | |
1264 if (!block.empty() && | |
1265 (block[block.size() - 1] == ' ' || | |
1266 block[block.size() - 1] == '\0') && | |
1267 (danglingVR_ == ValueRepresentation_ApplicationEntity || | |
1268 danglingVR_ == ValueRepresentation_AgeString || | |
1269 danglingVR_ == ValueRepresentation_CodeString || | |
1270 danglingVR_ == ValueRepresentation_DecimalString || | |
1271 danglingVR_ == ValueRepresentation_IntegerString || | |
1272 danglingVR_ == ValueRepresentation_LongString || | |
1273 danglingVR_ == ValueRepresentation_LongText || | |
1274 danglingVR_ == ValueRepresentation_PersonName || | |
1275 danglingVR_ == ValueRepresentation_ShortString || | |
1276 danglingVR_ == ValueRepresentation_ShortText || | |
1277 danglingVR_ == ValueRepresentation_UniqueIdentifier || | |
1278 danglingVR_ == ValueRepresentation_UnlimitedText)) | |
1279 { | |
1280 std::string s(block.begin(), block.end() - 1); | |
1281 c = visitor.VisitDatasetTag(danglingTag_, danglingVR_, transferSyntax_, s, IsLittleEndian()); | |
1282 } | |
1283 else | |
1284 { | |
1285 c = visitor.VisitDatasetTag(danglingTag_, danglingVR_, transferSyntax_, block, IsLittleEndian()); | |
1286 } | |
1287 | |
1288 if (!c) | |
1289 { | |
1290 state_ = State_Done; | |
1291 return; | |
1292 } | |
1293 } | |
1294 | |
1295 reader_.Schedule(8); | |
1296 state_ = State_DatasetTag; | |
1202 } | 1297 } |
1203 | 1298 |
1204 | 1299 |
1205 public: | 1300 public: |
1206 DicomStreamReader(std::istream& stream) : | 1301 DicomStreamReader(std::istream& stream) : |
1207 reader_(stream), | 1302 reader_(stream), |
1208 state_(State_Preamble), | 1303 state_(State_Preamble), |
1209 transferSyntax_(DicomTransferSyntax_LittleEndianImplicit), // Dummy | 1304 transferSyntax_(DicomTransferSyntax_LittleEndianImplicit), // Dummy |
1210 previousTag_(0x0000, 0x0000), // Dummy | |
1211 danglingTag_(0x0000, 0x0000), // Dummy | 1305 danglingTag_(0x0000, 0x0000), // Dummy |
1212 danglingVR_(ValueRepresentation_Unknown), // Dummy | 1306 danglingVR_(ValueRepresentation_Unknown), // Dummy |
1213 sequenceDepth_(0) | 1307 sequenceDepth_(0) |
1214 { | 1308 { |
1215 reader_.Schedule(128 /* empty header */ + | 1309 reader_.Schedule(128 /* empty header */ + |
1236 case State_MetaHeader: | 1330 case State_MetaHeader: |
1237 HandleMetaHeader(visitor, block); | 1331 HandleMetaHeader(visitor, block); |
1238 break; | 1332 break; |
1239 | 1333 |
1240 case State_DatasetTag: | 1334 case State_DatasetTag: |
1241 HandleDatasetTag(visitor, block); | 1335 HandleDatasetTag(block); |
1242 break; | 1336 break; |
1243 | 1337 |
1244 case State_DatasetExplicitLength: | 1338 case State_DatasetExplicitLength: |
1245 HandleDatasetExplicitLength(visitor, block); | 1339 HandleDatasetExplicitLength(block); |
1246 break; | 1340 break; |
1247 | 1341 |
1342 case State_SequenceExplicitLength: | |
1343 HandleSequenceExplicitLength(block); | |
1344 break; | |
1345 | |
1346 case State_SequenceExplicitValue: | |
1347 HandleSequenceExplicitValue(); | |
1348 break; | |
1349 | |
1248 case State_DatasetValue: | 1350 case State_DatasetValue: |
1249 if (sequenceDepth_ == 0 && | 1351 HandleDatasetValue(visitor, block); |
1250 !visitor.VisitDatasetTag(danglingTag_, danglingVR_, transferSyntax_, block, IsLittleEndian())) | |
1251 { | |
1252 state_ = State_Done; | |
1253 } | |
1254 else | |
1255 { | |
1256 reader_.Schedule(8); | |
1257 state_ = State_DatasetTag; | |
1258 } | |
1259 | |
1260 break; | 1352 break; |
1261 | 1353 |
1262 default: | 1354 default: |
1263 throw OrthancException(ErrorCode_InternalError); | 1355 throw OrthancException(ErrorCode_InternalError); |
1264 } | 1356 } |
1300 bool isLittleEndian) ORTHANC_OVERRIDE | 1392 bool isLittleEndian) ORTHANC_OVERRIDE |
1301 { | 1393 { |
1302 if (!isLittleEndian) | 1394 if (!isLittleEndian) |
1303 printf("** "); | 1395 printf("** "); |
1304 if (tag.GetGroup() < 0x7f00) | 1396 if (tag.GetGroup() < 0x7f00) |
1305 std::cout << "Dataset: " << tag.Format() << " [" << Toolbox::ConvertToAscii(value).c_str() << "] (" << value.size() << ")" << std::endl; | 1397 std::cout << "Dataset: " << tag.Format() << " " << EnumerationToString(vr) |
1398 << " [" << Toolbox::ConvertToAscii(value).c_str() << "] (" << value.size() << ")" << std::endl; | |
1306 else | 1399 else |
1307 std::cout << "Dataset: " << tag.Format() << " [PIXEL] (" << value.size() << ")" << std::endl; | 1400 std::cout << "Dataset: " << tag.Format() << " " << EnumerationToString(vr) |
1401 << " [PIXEL] (" << value.size() << ")" << std::endl; | |
1308 | 1402 |
1309 return true; | 1403 return true; |
1310 } | 1404 } |
1311 }; | 1405 }; |
1312 } | 1406 } |
1316 TEST(DicomStreamReader, DISABLED_Tutu) | 1410 TEST(DicomStreamReader, DISABLED_Tutu) |
1317 { | 1411 { |
1318 static const std::string PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/"; | 1412 static const std::string PATH = "/home/jodogne/Subversion/orthanc-tests/Database/TransferSyntaxes/"; |
1319 | 1413 |
1320 std::string dicom; | 1414 std::string dicom; |
1321 //SystemToolbox::ReadFile(dicom, PATH + "../ColorTestMalaterre.dcm", false); | 1415 SystemToolbox::ReadFile(dicom, PATH + "../ColorTestMalaterre.dcm", false); |
1322 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.1.dcm", false); | 1416 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.1.dcm", false); |
1323 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.2.dcm", false); // Big Endian | 1417 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.2.dcm", false); // Big Endian |
1324 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.50.dcm", false); | 1418 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.50.dcm", false); |
1325 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.4.51.dcm", false); | 1419 //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); | 1420 //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); | 1421 //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); | 1422 //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); | 1423 //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); | 1424 //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); | 1425 //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); | 1426 //SystemToolbox::ReadFile(dicom, PATH + "1.2.840.10008.1.2.5.dcm", false); |
1333 | 1427 |
1334 std::stringstream stream; | 1428 std::stringstream stream; |
1335 size_t pos = 0; | 1429 size_t pos = 0; |
1336 | 1430 |
1337 DicomStreamReader r(stream); | 1431 DicomStreamReader r(stream); |
1338 V visitor; | 1432 V visitor; |