diff -urNp dcmtk-3.6.4-orig/dcmnet/apps/storescp.cc dcmtk-3.6.4-dwok/dcmnet/apps/storescp.cc --- dcmtk-3.6.4-orig/dcmnet/apps/storescp.cc 2018-11-29 13:14:03.000000000 +0100 +++ dcmtk-3.6.4-dwok/dcmnet/apps/storescp.cc 2019-08-01 20:24:27.274688090 +0200 @@ -353,7 +353,7 @@ int main(int argc, char *argv[]) "sort studies using prefix p and a timestamp"); cmd.addOption("--sort-on-study-uid", "-su", 1, "[p]refix: string", "sort studies using prefix p and the Study\nInstance UID"); - cmd.addOption("--sort-on-patientname", "-sp", "sort studies using the Patient's Name and\na timestamp"); + cmd.addOption("--sort-on-patientname", "-sp", "sort studies using the Patient's Name,\nStudy Date and Patient ID"); cmd.addSubGroup("filename generation:"); cmd.addOption("--default-filenames", "-uf", "generate filename from instance UID (default)"); @@ -1661,10 +1661,10 @@ static void mapCharacterAndAppendToStrin "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", // Codes 144-159 "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", // Codes 160-175 "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", "_", // Codes 176-191 - "A", "A", "A", "A", "Ae","A", "A", "C", "E", "E", "E", "E", "I", "I", "I", "I", // Codes 192-107 - "D", "N", "O", "O", "O", "O", "Oe","_", "O", "U", "U", "U", "Ue","Y", "_", "ss",// Codes 108-123 - "a", "a", "a", "a", "ae","a", "a", "c", "e", "e", "e", "e", "i", "i", "i", "i", // Codes 124-141 - "d", "n", "o", "o", "o", "o", "oe","_", "o", "u", "u", "u", "ue","y", "_", "y" // Codes 142-157 + "A", "A", "A", "A", "A", "A", "A", "C", "E", "E", "E", "E", "I", "I", "I", "I", // Codes 192-107 + "D", "N", "O", "O", "O", "O", "O", "_", "O", "U", "U", "U", "U", "Y", "_", "s", // Codes 108-123 + "a", "a", "a", "a", "a", "a", "a", "c", "e", "e", "e", "e", "i", "i", "i", "i", // Codes 124-141 + "d", "n", "o", "o", "o", "o", "o", "_", "o", "u", "u", "u", "u", "y", "_", "y" // Codes 142-157 }; output += latin1_table[c]; } @@ -1786,6 +1786,8 @@ storeSCPCallback( // if --sort-on-patientname is active, we need to extract the // patient's name (format: last_name^first_name) OFString currentPatientName; + OFString currentPatientID; + OFString currentStudyDate; if (opt_sortStudyMode == ESM_PatientName) { OFString tmpName; @@ -1814,6 +1816,62 @@ storeSCPCallback( mapCharacterAndAppendToString(tmpName[i], currentPatientName); } + if (opt_sortStudyMode == ESM_PatientName) + { + OFString tmpID; + if ((*imageDataSet)->findAndGetOFString(DCM_PatientID, tmpID).bad() || tmpID.empty()) + { + // default if patient ID is missing or empty + tmpID = "EMPTYID"; + OFLOG_WARN(storescpLogger, "element PatientID " << DCM_PatientID << " absent or empty in data set, using '" + << tmpID << "' instead"); + } + else + { + DcmElement *patElem = NULL; + OFString charset; + (*imageDataSet)->findAndGetElement(DCM_PatientID, patElem); // patElem cannot be NULL, see above + (*imageDataSet)->findAndGetOFStringArray(DCM_SpecificCharacterSet, charset); + if (!charset.empty() && !(charset == "ISO_IR 100") && (patElem->containsExtendedCharacters())) + { + OFLOG_WARN(storescpLogger, "Patient ID not in Latin-1 (charset: " << charset << "), ASCII dir name may be broken"); + } + } + + /* substitute non-ASCII characters in patient ID to ASCII "equivalent" */ + const size_t length = tmpID.length(); + for (size_t i = 0; i < length; i++) + mapCharacterAndAppendToString(tmpID[i], currentPatientID); + } + + if (opt_sortStudyMode == ESM_PatientName) + { + OFString tmpDate; + if ((*imageDataSet)->findAndGetOFString(DCM_StudyDate, tmpDate).bad() || tmpDate.empty()) + { + // default if study Date is missing or empty + tmpDate = "NODATE"; + OFLOG_WARN(storescpLogger, "element StudyDate " << DCM_StudyDate << " absent or empty in data set, using '" + << tmpDate << "' instead"); + } + else + { + DcmElement *patElem = NULL; + OFString charset; + (*imageDataSet)->findAndGetElement(DCM_StudyDate, patElem); // patElem cannot be NULL, see above + (*imageDataSet)->findAndGetOFStringArray(DCM_SpecificCharacterSet, charset); + if (!charset.empty() && !(charset == "ISO_IR 100") && (patElem->containsExtendedCharacters())) + { + OFLOG_WARN(storescpLogger, "Study Date not in Latin-1 (charset: " << charset << "), ASCII dir name may be broken"); + } + } + + /* substitute non-ASCII characters in Study Date to ASCII "equivalent" */ + const size_t length = tmpDate.length(); + for (size_t i = 0; i < length; i++) + mapCharacterAndAppendToString(tmpDate[i], currentStudyDate); + } + // if this is the first DICOM object that was received or if the study instance UID in the // current DICOM object does not equal the last object's study instance UID we need to create // a new subdirectory in which the current DICOM object will be stored @@ -1859,10 +1917,14 @@ storeSCPCallback( subdirectoryName += currentStudyInstanceUID; break; case ESM_PatientName: - // pattern: "[Patient's Name]_[YYYYMMDD]_[HHMMSSMMM]" + // pattern: "[Patient's Name]_[Study Date]_[Patient ID]" subdirectoryName = currentPatientName; subdirectoryName += '_'; - subdirectoryName += timestamp; + subdirectoryName += currentStudyDate; + subdirectoryName += '_'; + subdirectoryName += currentPatientID; +// subdirectoryName += '_'; +// subdirectoryName += currentStudyInstanceUID; break; case ESM_None: break;