# HG changeset patch # User Sebastien Jodogne # Date 1465479993 -7200 # Node ID 655489d9165d5b1ea1880179ee5f6d8d8635d27f # Parent 6301bbcbcaed931d9e305004e8b4ac58ffeb929a DicomMap::ParseDicomMetaInformation() diff -r 6301bbcbcaed -r 655489d9165d Core/DicomFormat/DicomMap.cpp --- a/Core/DicomFormat/DicomMap.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/Core/DicomFormat/DicomMap.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -36,6 +36,7 @@ #include #include #include "DicomArray.h" +#include "../Endianness.h" #include "../OrthancException.h" @@ -292,7 +293,7 @@ for (size_t i = 0; i < count; i++) { - result.SetValue(tags[i], ""); + result.SetValue(tags[i], "", false); } } @@ -304,8 +305,8 @@ void DicomMap::SetupFindStudyTemplate(DicomMap& result) { SetupFindTemplate(result, studyTags, sizeof(studyTags) / sizeof(DicomTag)); - result.SetValue(DICOM_TAG_ACCESSION_NUMBER, ""); - result.SetValue(DICOM_TAG_PATIENT_ID, ""); + result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); + result.SetValue(DICOM_TAG_PATIENT_ID, "", false); // These main DICOM tags are only indirectly related to the // General Study Module, remove them @@ -317,9 +318,9 @@ void DicomMap::SetupFindSeriesTemplate(DicomMap& result) { SetupFindTemplate(result, seriesTags, sizeof(seriesTags) / sizeof(DicomTag)); - result.SetValue(DICOM_TAG_ACCESSION_NUMBER, ""); - result.SetValue(DICOM_TAG_PATIENT_ID, ""); - result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, ""); + result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); + result.SetValue(DICOM_TAG_PATIENT_ID, "", false); + result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); // These tags are considered as "main" by Orthanc, but are not in the Series module result.Remove(DicomTag(0x0008, 0x0070)); // Manufacturer @@ -339,10 +340,10 @@ void DicomMap::SetupFindInstanceTemplate(DicomMap& result) { SetupFindTemplate(result, instanceTags, sizeof(instanceTags) / sizeof(DicomTag)); - result.SetValue(DICOM_TAG_ACCESSION_NUMBER, ""); - result.SetValue(DICOM_TAG_PATIENT_ID, ""); - result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, ""); - result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, ""); + result.SetValue(DICOM_TAG_ACCESSION_NUMBER, "", false); + result.SetValue(DICOM_TAG_PATIENT_ID, "", false); + result.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "", false); + result.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "", false); } @@ -479,4 +480,312 @@ tags.insert(it->first); } } + + + static uint16_t ReadUnsignedInteger16(const char* dicom) + { + return le16toh(*reinterpret_cast(dicom)); + } + + + static uint32_t ReadUnsignedInteger32(const char* dicom) + { + return le32toh(*reinterpret_cast(dicom)); + } + + + static bool ValidateTag(const ValueRepresentation& vr, + const std::string& value) + { + switch (vr) + { + case ValueRepresentation_ApplicationEntity: + return value.size() <= 16; + + case ValueRepresentation_AgeString: + return (value.size() == 4 && + isdigit(value[0]) && + isdigit(value[1]) && + isdigit(value[2]) && + (value[3] == 'D' || value[3] == 'W' || value[3] == 'M' || value[3] == 'Y')); + + case ValueRepresentation_AttributeTag: + return value.size() == 4; + + case ValueRepresentation_CodeString: + return value.size() <= 16; + + case ValueRepresentation_Date: + return value.size() <= 18; + + case ValueRepresentation_DecimalString: + return value.size() <= 16; + + case ValueRepresentation_DateTime: + return value.size() <= 54; + + case ValueRepresentation_FloatingPointSingle: + return value.size() == 4; + + case ValueRepresentation_FloatingPointDouble: + return value.size() == 8; + + case ValueRepresentation_IntegerString: + return value.size() <= 12; + + case ValueRepresentation_LongString: + return value.size() <= 64; + + case ValueRepresentation_LongText: + return value.size() <= 10240; + + case ValueRepresentation_OtherByte: + return true; + + case ValueRepresentation_OtherDouble: + return value.size() <= static_cast((1llu << 32) - 8); + + case ValueRepresentation_OtherFloat: + return value.size() <= static_cast((1llu << 32) - 4); + + case ValueRepresentation_OtherLong: + return true; + + case ValueRepresentation_OtherWord: + return true; + + case ValueRepresentation_PersonName: + return true; + + case ValueRepresentation_ShortString: + return value.size() <= 16; + + case ValueRepresentation_SignedLong: + return value.size() == 4; + + case ValueRepresentation_Sequence: + return true; + + case ValueRepresentation_SignedShort: + return value.size() == 2; + + case ValueRepresentation_ShortText: + return value.size() <= 1024; + + case ValueRepresentation_Time: + return value.size() <= 28; + + case ValueRepresentation_UnlimitedCharacters: + return value.size() <= static_cast((1llu << 32) - 2); + + case ValueRepresentation_UniqueIdentifier: + return value.size() <= 64; + + case ValueRepresentation_UnsignedLong: + return value.size() == 4; + + case ValueRepresentation_Unknown: + return true; + + case ValueRepresentation_UniversalResource: + return value.size() <= static_cast((1llu << 32) - 2); + + case ValueRepresentation_UnsignedShort: + return value.size() == 2; + + case ValueRepresentation_UnlimitedText: + return value.size() <= static_cast((1llu << 32) - 2); + + default: + // Assume unsupported tags are OK + return true; + } + } + + + static void RemoveTagPadding(std::string& value, + const ValueRepresentation& vr) + { + /** + * Remove padding from character strings, if need be. For the time + * being, only the UI VR is supported. + * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html + **/ + + switch (vr) + { + case ValueRepresentation_UniqueIdentifier: + { + /** + * "Values with a VR of UI shall be padded with a single + * trailing NULL (00H) character when necessary to achieve even + * length." + **/ + + if (!value.empty() && + value[value.size() - 1] == '\0') + { + value.resize(value.size() - 1); + } + + break; + } + + /** + * TODO implement other VR + **/ + + default: + // No padding is applicable to this VR + break; + } + } + + + static bool ReadNextTag(DicomTag& tag, + ValueRepresentation& vr, + std::string& value, + const char* dicom, + size_t size, + size_t& position) + { + /** + * http://dicom.nema.org/medical/dicom/current/output/chtml/part05/chapter_7.html#sect_7.1.2 + * This function reads a data element with Explicit VR encoded using Little-Endian. + **/ + + if (position + 6 > size) + { + return false; + } + + tag = DicomTag(ReadUnsignedInteger16(dicom + position), + ReadUnsignedInteger16(dicom + position + 2)); + + vr = StringToValueRepresentation(std::string(dicom + position + 4, 2), true); + if (vr == ValueRepresentation_NotSupported) + { + return false; + } + + if (vr == ValueRepresentation_OtherByte || + vr == ValueRepresentation_OtherDouble || + vr == ValueRepresentation_OtherFloat || + vr == ValueRepresentation_OtherLong || + vr == ValueRepresentation_OtherWord || + vr == ValueRepresentation_Sequence || + vr == ValueRepresentation_UnlimitedCharacters || + vr == ValueRepresentation_UniversalResource || + vr == ValueRepresentation_UnlimitedText || + vr == ValueRepresentation_Unknown) // Note that "UN" should never appear in the Meta Information + { + if (position + 12 > size) + { + return false; + } + + uint32_t length = ReadUnsignedInteger32(dicom + position + 8); + + if (position + 12 + length > size) + { + return false; + } + + value.assign(dicom + position + 12, length); + position += (12 + length); + } + else + { + if (position + 8 > size) + { + return false; + } + + uint16_t length = ReadUnsignedInteger16(dicom + position + 6); + + if (position + 8 + length > size) + { + return false; + } + + value.assign(dicom + position + 8, length); + position += (8 + length); + } + + if (!ValidateTag(vr, value)) + { + return false; + } + + RemoveTagPadding(value, vr); + + return true; + } + + + bool DicomMap::ParseDicomMetaInformation(DicomMap& result, + const char* dicom, + size_t size) + { + /** + * http://dicom.nema.org/medical/dicom/current/output/chtml/part10/chapter_7.html + * According to Table 7.1-1, besides the "DICM" DICOM prefix, the + * file preamble (i.e. dicom[0..127]) should not be taken into + * account to determine whether the file is or is not a DICOM file. + **/ + + if (size < 132 || + dicom[128] != 'D' || + dicom[129] != 'I' || + dicom[130] != 'C' || + dicom[131] != 'M') + { + return false; + } + + + /** + * The DICOM File Meta Information must be encoded using the + * Explicit VR Little Endian Transfer Syntax + * (UID=1.2.840.10008.1.2.1). + **/ + + result.Clear(); + + // First, we read the "File Meta Information Group Length" tag + // (0002,0000) to know where to stop reading the meta header + size_t position = 132; + + DicomTag tag(0x0000, 0x0000); // Dummy initialization + ValueRepresentation vr; + std::string value; + if (!ReadNextTag(tag, vr, value, dicom, size, position) || + tag.GetGroup() != 0x0002 || + tag.GetElement() != 0x0000 || + vr != ValueRepresentation_UnsignedLong || + value.size() != 4) + { + return false; + } + + size_t stopPosition = position + ReadUnsignedInteger32(value.c_str()); + if (stopPosition > size) + { + return false; + } + + while (position < stopPosition) + { + if (ReadNextTag(tag, vr, value, dicom, size, position)) + { + result.SetValue(tag, value, IsBinaryValueRepresentation(vr)); + } + else + { + return false; + } + } + + return true; + } } diff -r 6301bbcbcaed -r 655489d9165d Core/DicomFormat/DicomMap.h --- a/Core/DicomFormat/DicomMap.h Thu Jun 09 14:48:40 2016 +0200 +++ b/Core/DicomFormat/DicomMap.h Thu Jun 09 15:46:33 2016 +0200 @@ -102,16 +102,18 @@ } void SetValue(const DicomTag& tag, - const std::string& str) + const std::string& str, + bool isBinary) { - SetValue(tag, new DicomValue(str, false)); + SetValue(tag, new DicomValue(str, isBinary)); } void SetValue(uint16_t group, uint16_t element, - const std::string& str) + const std::string& str, + bool isBinary) { - SetValue(group, element, new DicomValue(str, false)); + SetValue(group, element, new DicomValue(str, isBinary)); } bool HasTag(uint16_t group, uint16_t element) const @@ -176,5 +178,9 @@ static void LoadMainDicomTags(const DicomTag*& tags, size_t& size, ResourceType level); + + static bool ParseDicomMetaInformation(DicomMap& result, + const char* dicom, + size_t size); }; } diff -r 6301bbcbcaed -r 655489d9165d Core/Enumerations.cpp --- a/Core/Enumerations.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/Core/Enumerations.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -974,7 +974,7 @@ } else if (vr == "PN") { - return ValueRepresentation_PatientName; + return ValueRepresentation_PersonName; } else if (vr == "SH") { @@ -1333,4 +1333,60 @@ return (type >= FileContentType_StartUser && type <= FileContentType_EndUser); } + + + bool IsBinaryValueRepresentation(ValueRepresentation vr) + { + // http://dicom.nema.org/medical/dicom/current/output/chtml/part05/sect_6.2.html + + switch (vr) + { + case ValueRepresentation_ApplicationEntity: // AE + case ValueRepresentation_AgeString: // AS + case ValueRepresentation_CodeString: // CS + case ValueRepresentation_Date: // DA + case ValueRepresentation_DecimalString: // DS + case ValueRepresentation_DateTime: // DT + case ValueRepresentation_IntegerString: // IS + case ValueRepresentation_LongString: // LO + case ValueRepresentation_LongText: // LT + case ValueRepresentation_PersonName: // PN + case ValueRepresentation_ShortString: // SH + case ValueRepresentation_ShortText: // ST + case ValueRepresentation_Time: // TM + case ValueRepresentation_UnlimitedCharacters: // UC + case ValueRepresentation_UniqueIdentifier: // UI (UID) + case ValueRepresentation_UniversalResource: // UR (URI or URL) + case ValueRepresentation_UnlimitedText: // UT + { + return false; + } + + /** + * Below are all the VR whose character repertoire is tagged as + * "not applicable" + **/ + case ValueRepresentation_AttributeTag: // AT (2 x uint16_t) + case ValueRepresentation_FloatingPointSingle: // FL (float) + case ValueRepresentation_FloatingPointDouble: // FD (double) + case ValueRepresentation_OtherByte: // OB + case ValueRepresentation_OtherDouble: // OD + case ValueRepresentation_OtherFloat: // OF + case ValueRepresentation_OtherLong: // OL + case ValueRepresentation_OtherWord: // OW + case ValueRepresentation_SignedLong: // SL (int32_t) + case ValueRepresentation_Sequence: // SQ + case ValueRepresentation_SignedShort: // SS (int16_t) + case ValueRepresentation_UnsignedLong: // UL (uint32_t) + case ValueRepresentation_Unknown: // UN + case ValueRepresentation_UnsignedShort: // US (uint16_t) + { + return true; + } + + case ValueRepresentation_NotSupported: + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } } diff -r 6301bbcbcaed -r 655489d9165d Core/Enumerations.h --- a/Core/Enumerations.h Thu Jun 09 14:48:40 2016 +0200 +++ b/Core/Enumerations.h Thu Jun 09 15:46:33 2016 +0200 @@ -410,7 +410,7 @@ ValueRepresentation_OtherFloat = 15, // OF ValueRepresentation_OtherLong = 16, // OL ValueRepresentation_OtherWord = 17, // OW - ValueRepresentation_PatientName = 18, // PN + ValueRepresentation_PersonName = 18, // PN ValueRepresentation_ShortString = 19, // SH ValueRepresentation_SignedLong = 20, // SL (int32_t) ValueRepresentation_Sequence = 21, // SQ @@ -524,4 +524,6 @@ HttpStatus ConvertErrorCodeToHttpStatus(ErrorCode error); bool IsUserContentType(FileContentType type); + + bool IsBinaryValueRepresentation(ValueRepresentation vr); } diff -r 6301bbcbcaed -r 655489d9165d OrthancServer/DatabaseWrapperBase.cpp --- a/OrthancServer/DatabaseWrapperBase.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/OrthancServer/DatabaseWrapperBase.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -350,7 +350,7 @@ { map.SetValue(s.ColumnInt(1), s.ColumnInt(2), - s.ColumnString(3)); + s.ColumnString(3), false); } } diff -r 6301bbcbcaed -r 655489d9165d OrthancServer/DicomProtocol/DicomUserConnection.cpp --- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -401,7 +401,7 @@ if (!m.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL)) { - m.SetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL, payload.level); + m.SetValue(DICOM_TAG_QUERY_RETRIEVE_LEVEL, payload.level, false); } payload.answers->Add(m); @@ -507,7 +507,7 @@ !value->IsNull() && value->GetContent() == "*") { - fix->SetValue(*it, ""); + fix->SetValue(*it, "", false); } } } @@ -1065,7 +1065,7 @@ const std::string& patientId) { DicomMap query; - query.SetValue(DICOM_TAG_PATIENT_ID, patientId); + query.SetValue(DICOM_TAG_PATIENT_ID, patientId, false); MoveInternal(targetAet, ResourceType_Patient, query); } @@ -1073,7 +1073,7 @@ const std::string& studyUid) { DicomMap query; - query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid); + query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid, false); MoveInternal(targetAet, ResourceType_Study, query); } @@ -1082,8 +1082,8 @@ const std::string& seriesUid) { DicomMap query; - query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid); - query.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid); + query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid, false); + query.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid, false); MoveInternal(targetAet, ResourceType_Series, query); } @@ -1093,9 +1093,9 @@ const std::string& instanceUid) { DicomMap query; - query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid); - query.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid); - query.SetValue(DICOM_TAG_SOP_INSTANCE_UID, instanceUid); + query.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, studyUid, false); + query.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, seriesUid, false); + query.SetValue(DICOM_TAG_SOP_INSTANCE_UID, instanceUid, false); MoveInternal(targetAet, ResourceType_Instance, query); } diff -r 6301bbcbcaed -r 655489d9165d OrthancServer/FromDcmtkBridge.cpp --- a/OrthancServer/FromDcmtkBridge.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/OrthancServer/FromDcmtkBridge.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -1136,7 +1136,7 @@ return ValueRepresentation_OtherWord; case EVR_PN: - return ValueRepresentation_PatientName; + return ValueRepresentation_PersonName; case EVR_SH: return ValueRepresentation_ShortString; @@ -1761,7 +1761,7 @@ throw OrthancException(ErrorCode_BadFileFormat); } - target.SetValue(ParseTag(members[i]), value.asString()); + target.SetValue(ParseTag(members[i]), value.asString(), false); } } } diff -r 6301bbcbcaed -r 655489d9165d OrthancServer/OrthancFindRequestHandler.cpp --- a/OrthancServer/OrthancFindRequestHandler.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/OrthancServer/OrthancFindRequestHandler.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -84,7 +84,7 @@ s += *it; } - result.SetValue(tag, s); + result.SetValue(tag, s, false); } @@ -148,7 +148,7 @@ if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES)) { result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES, - boost::lexical_cast(studies.size())); + boost::lexical_cast(studies.size()), false); } if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES) && @@ -164,7 +164,7 @@ if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES)) { result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_SERIES, - boost::lexical_cast(series.size())); + boost::lexical_cast(series.size()), false); } if (!query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES)) @@ -178,7 +178,7 @@ if (query.HasTag(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES)) { result.SetValue(DICOM_TAG_NUMBER_OF_PATIENT_RELATED_INSTANCES, - boost::lexical_cast(instances.size())); + boost::lexical_cast(instances.size()), false); } } @@ -196,7 +196,7 @@ if (query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES)) { result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_SERIES, - boost::lexical_cast(series.size())); + boost::lexical_cast(series.size()), false); } if (query.HasTag(DICOM_TAG_MODALITIES_IN_STUDY)) @@ -218,7 +218,7 @@ if (query.HasTag(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES)) { result.SetValue(DICOM_TAG_NUMBER_OF_STUDY_RELATED_INSTANCES, - boost::lexical_cast(instances.size())); + boost::lexical_cast(instances.size()), false); } if (query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY)) @@ -241,7 +241,7 @@ if (query.HasTag(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES)) { result.SetValue(DICOM_TAG_NUMBER_OF_SERIES_RELATED_INSTANCES, - boost::lexical_cast(instances.size())); + boost::lexical_cast(instances.size()), false); } } @@ -342,11 +342,11 @@ if (resource.isMember(tag)) { value = resource.get(tag, Json::arrayValue).get("Value", "").asString(); - result.SetValue(query.GetElement(i).GetTag(), value); + result.SetValue(query.GetElement(i).GetTag(), value, false); } else { - result.SetValue(query.GetElement(i).GetTag(), ""); + result.SetValue(query.GetElement(i).GetTag(), "", false); } } } @@ -356,7 +356,7 @@ DicomArray tmp(*counters); for (size_t i = 0; i < tmp.GetSize(); i++) { - result.SetValue(tmp.GetElement(i).GetTag(), tmp.GetElement(i).GetValue().GetContent()); + result.SetValue(tmp.GetElement(i).GetTag(), tmp.GetElement(i).GetValue().GetContent(), false); } } @@ -496,7 +496,7 @@ } DicomTag tag(FromDcmtkBridge::ParseTag(members[i])); - target.SetValue(tag, output[members[i]].asString()); + target.SetValue(tag, output[members[i]].asString(), false); } return true; @@ -615,7 +615,7 @@ // DICOM specifies that searches must be case sensitive, except // for tags with a PN value representation bool sensitive = true; - if (vr == ValueRepresentation_PatientName) + if (vr == ValueRepresentation_PersonName) { sensitive = caseSensitivePN; } diff -r 6301bbcbcaed -r 655489d9165d OrthancServer/OrthancRestApi/OrthancRestModalities.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -97,7 +97,7 @@ for (size_t i = 0; i < members.size(); i++) { DicomTag t = FromDcmtkBridge::ParseTag(members[i]); - result.SetValue(t, query[members[i]].asString()); + result.SetValue(t, query[members[i]].asString(), false); } return true; @@ -287,7 +287,7 @@ std::string tmp; if (source.GetTagValue(tmp, tag)) { - target.SetValue(tag, tmp); + target.SetValue(tag, tmp, false); } } diff -r 6301bbcbcaed -r 655489d9165d OrthancServer/OrthancRestApi/OrthancRestResources.cpp --- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -1289,6 +1289,9 @@ std::string dicomContent; context.ReadFile(dicomContent, publicId, FileContentType_Dicom); + // TODO Consider using "DicomMap::ParseDicomMetaInformation()" to + // speed up things here + ParsedDicomFile dicom(dicomContent); Json::Value header; diff -r 6301bbcbcaed -r 655489d9165d OrthancServer/QueryRetrieveHandler.cpp --- a/OrthancServer/QueryRetrieveHandler.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/OrthancServer/QueryRetrieveHandler.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -84,7 +84,7 @@ const std::string& value) { Invalidate(); - query_.SetValue(tag, value); + query_.SetValue(tag, value, false); } diff -r 6301bbcbcaed -r 655489d9165d OrthancServer/Search/HierarchicalMatcher.cpp --- a/OrthancServer/Search/HierarchicalMatcher.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/OrthancServer/Search/HierarchicalMatcher.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -147,7 +147,7 @@ // DICOM specifies that searches must be case sensitive, except // for tags with a PN value representation bool sensitive = true; - if (vr == ValueRepresentation_PatientName) + if (vr == ValueRepresentation_PersonName) { sensitive = caseSensitivePN; } diff -r 6301bbcbcaed -r 655489d9165d OrthancServer/ToDcmtkBridge.cpp --- a/OrthancServer/ToDcmtkBridge.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/OrthancServer/ToDcmtkBridge.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -116,7 +116,7 @@ case ValueRepresentation_OtherWord: return EVR_OW; - case ValueRepresentation_PatientName: + case ValueRepresentation_PersonName: return EVR_PN; case ValueRepresentation_ShortString: diff -r 6301bbcbcaed -r 655489d9165d Plugins/Engine/OrthancPluginDatabase.cpp --- a/Plugins/Engine/OrthancPluginDatabase.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/Plugins/Engine/OrthancPluginDatabase.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -986,7 +986,7 @@ { const OrthancPluginDicomTag& tag = *reinterpret_cast(answer.valueGeneric); assert(answerDicomMap_ != NULL); - answerDicomMap_->SetValue(tag.group, tag.element, std::string(tag.value)); + answerDicomMap_->SetValue(tag.group, tag.element, std::string(tag.value), false); break; } diff -r 6301bbcbcaed -r 655489d9165d Plugins/Engine/OrthancPlugins.cpp --- a/Plugins/Engine/OrthancPlugins.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/Plugins/Engine/OrthancPlugins.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -511,7 +511,7 @@ { if (!input.HasTag(*it)) { - tmp.SetValue(*it, ""); + tmp.SetValue(*it, "", false); } } diff -r 6301bbcbcaed -r 655489d9165d Plugins/Engine/PluginsEnumerations.cpp --- a/Plugins/Engine/PluginsEnumerations.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/Plugins/Engine/PluginsEnumerations.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -376,7 +376,7 @@ return ValueRepresentation_OtherWord; case OrthancPluginValueRepresentation_PN: - return ValueRepresentation_PatientName; + return ValueRepresentation_PersonName; case OrthancPluginValueRepresentation_SH: return ValueRepresentation_ShortString; @@ -474,7 +474,7 @@ case ValueRepresentation_OtherWord: return OrthancPluginValueRepresentation_OW; - case ValueRepresentation_PatientName: + case ValueRepresentation_PersonName: return OrthancPluginValueRepresentation_PN; case ValueRepresentation_ShortString: diff -r 6301bbcbcaed -r 655489d9165d UnitTestsSources/DicomMapTests.cpp --- a/UnitTestsSources/DicomMapTests.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/UnitTestsSources/DicomMapTests.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -90,7 +90,7 @@ ASSERT_FALSE(m.HasTag(DICOM_TAG_PATIENT_NAME)); ASSERT_FALSE(m.HasTag(0x0010, 0x0010)); - m.SetValue(0x0010, 0x0010, "PatientName"); + m.SetValue(0x0010, 0x0010, "PatientName", false); ASSERT_TRUE(m.HasTag(DICOM_TAG_PATIENT_NAME)); ASSERT_TRUE(m.HasTag(0x0010, 0x0010)); @@ -99,9 +99,9 @@ ASSERT_EQ(DICOM_TAG_PATIENT_NAME, *s.begin()); ASSERT_FALSE(m.HasTag(DICOM_TAG_PATIENT_ID)); - m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID"); + m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID", false); ASSERT_TRUE(m.HasTag(0x0010, 0x0020)); - m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID2"); + m.SetValue(DICOM_TAG_PATIENT_ID, "PatientID2", false); ASSERT_EQ("PatientID2", m.GetValue(0x0010, 0x0020).GetContent()); m.GetTags(s); @@ -117,7 +117,7 @@ std::auto_ptr mm(m.Clone()); ASSERT_EQ("PatientName", mm->GetValue(DICOM_TAG_PATIENT_NAME).GetContent()); - m.SetValue(DICOM_TAG_PATIENT_ID, "Hello"); + m.SetValue(DICOM_TAG_PATIENT_ID, "Hello", false); ASSERT_THROW(mm->GetValue(DICOM_TAG_PATIENT_ID), OrthancException); mm->CopyTagIfExists(m, DICOM_TAG_PATIENT_ID); ASSERT_EQ("Hello", mm->GetValue(DICOM_TAG_PATIENT_ID).GetContent()); diff -r 6301bbcbcaed -r 655489d9165d UnitTestsSources/FromDcmtkTests.cpp --- a/UnitTestsSources/FromDcmtkTests.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/UnitTestsSources/FromDcmtkTests.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -301,7 +301,7 @@ TEST(FromDcmtkBridge, ValueRepresentation) { - ASSERT_EQ(ValueRepresentation_PatientName, + ASSERT_EQ(ValueRepresentation_PersonName, FromDcmtkBridge::LookupValueRepresentation(DICOM_TAG_PATIENT_NAME)); ASSERT_EQ(ValueRepresentation_Date, FromDcmtkBridge::LookupValueRepresentation(DicomTag(0x0008, 0x0020) /* StudyDate */)); @@ -576,8 +576,8 @@ TEST(ParsedDicomFile, ToJsonFlags1) { - FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7053, 0x1000), ValueRepresentation_PatientName, "MyPrivateTag", 1, 1); - FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PatientName, "Declared public tag", 1, 1); + FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7053, 0x1000), ValueRepresentation_PersonName, "MyPrivateTag", 1, 1); + FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PersonName, "Declared public tag", 1, 1); ParsedDicomFile f(true); f.Insert(DicomTag(0x7050, 0x1000), "Some public tag", false); // Even group => public tag @@ -691,7 +691,7 @@ { DicomMap m; - m.SetValue(DICOM_TAG_PATIENT_ID, "hello"); + m.SetValue(DICOM_TAG_PATIENT_ID, "hello", false); a.Add(m); } @@ -703,7 +703,7 @@ { DicomMap m; - m.SetValue(DICOM_TAG_PATIENT_ID, "world"); + m.SetValue(DICOM_TAG_PATIENT_ID, "world", false); a.Add(m); } @@ -719,7 +719,7 @@ { FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7057, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag", 1, 1); FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7059, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag", 1, 1); - FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PatientName, "Declared public tag", 1, 1); + FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PersonName, "Declared public tag", 1, 1); Json::Value v; const std::string sopClassUid = "1.2.840.10008.5.1.4.1.1.1"; // CR Image Storage: diff -r 6301bbcbcaed -r 655489d9165d UnitTestsSources/ImageProcessingTests.cpp --- a/UnitTestsSources/ImageProcessingTests.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/UnitTestsSources/ImageProcessingTests.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -44,14 +44,14 @@ { // Cardiac/MR* DicomMap m; - m.SetValue(DICOM_TAG_ROWS, "24"); - m.SetValue(DICOM_TAG_COLUMNS, "16"); - m.SetValue(DICOM_TAG_BITS_ALLOCATED, "16"); - m.SetValue(DICOM_TAG_SAMPLES_PER_PIXEL, "1"); - m.SetValue(DICOM_TAG_BITS_STORED, "12"); - m.SetValue(DICOM_TAG_HIGH_BIT, "11"); - m.SetValue(DICOM_TAG_PIXEL_REPRESENTATION, "0"); - m.SetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2"); + m.SetValue(DICOM_TAG_ROWS, "24", false); + m.SetValue(DICOM_TAG_COLUMNS, "16", false); + m.SetValue(DICOM_TAG_BITS_ALLOCATED, "16", false); + m.SetValue(DICOM_TAG_SAMPLES_PER_PIXEL, "1", false); + m.SetValue(DICOM_TAG_BITS_STORED, "12", false); + m.SetValue(DICOM_TAG_HIGH_BIT, "11", false); + m.SetValue(DICOM_TAG_PIXEL_REPRESENTATION, "0", false); + m.SetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2", false); DicomImageInformation info(m); PixelFormat format; @@ -64,14 +64,14 @@ { // Delphine CT DicomMap m; - m.SetValue(DICOM_TAG_ROWS, "24"); - m.SetValue(DICOM_TAG_COLUMNS, "16"); - m.SetValue(DICOM_TAG_BITS_ALLOCATED, "16"); - m.SetValue(DICOM_TAG_SAMPLES_PER_PIXEL, "1"); - m.SetValue(DICOM_TAG_BITS_STORED, "16"); - m.SetValue(DICOM_TAG_HIGH_BIT, "15"); - m.SetValue(DICOM_TAG_PIXEL_REPRESENTATION, "1"); - m.SetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2"); + m.SetValue(DICOM_TAG_ROWS, "24", false); + m.SetValue(DICOM_TAG_COLUMNS, "16", false); + m.SetValue(DICOM_TAG_BITS_ALLOCATED, "16", false); + m.SetValue(DICOM_TAG_SAMPLES_PER_PIXEL, "1", false); + m.SetValue(DICOM_TAG_BITS_STORED, "16", false); + m.SetValue(DICOM_TAG_HIGH_BIT, "15", false); + m.SetValue(DICOM_TAG_PIXEL_REPRESENTATION, "1", false); + m.SetValue(DICOM_TAG_PHOTOMETRIC_INTERPRETATION, "MONOCHROME2", false); DicomImageInformation info(m); PixelFormat format; diff -r 6301bbcbcaed -r 655489d9165d UnitTestsSources/ServerIndexTests.cpp --- a/UnitTestsSources/ServerIndexTests.cpp Thu Jun 09 14:48:40 2016 +0200 +++ b/UnitTestsSources/ServerIndexTests.cpp Thu Jun 09 15:46:33 2016 +0200 @@ -790,10 +790,10 @@ { std::string id = boost::lexical_cast(i); DicomMap instance; - instance.SetValue(DICOM_TAG_PATIENT_ID, "patient-" + id); - instance.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "study-" + id); - instance.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "series-" + id); - instance.SetValue(DICOM_TAG_SOP_INSTANCE_UID, "instance-" + id); + instance.SetValue(DICOM_TAG_PATIENT_ID, "patient-" + id, false); + instance.SetValue(DICOM_TAG_STUDY_INSTANCE_UID, "study-" + id, false); + instance.SetValue(DICOM_TAG_SERIES_INSTANCE_UID, "series-" + id, false); + instance.SetValue(DICOM_TAG_SOP_INSTANCE_UID, "instance-" + id, false); std::map instanceMetadata; DicomInstanceToStore toStore;