comparison OrthancFramework/Sources/DicomParsing/DicomModification.cpp @ 4737:979ae3ea3381

DANGEROUS commit: Anonymization is now also applied to nested sequences
author Sebastien Jodogne <s.jodogne@gmail.com>
date Tue, 06 Jul 2021 08:12:26 +0200
parents b51c08bd5c38
children 51ec061516c9
comparison
equal deleted inserted replaced
4736:bf852fd773b7 4737:979ae3ea3381
42 static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2021b = 42 static const std::string ORTHANC_DEIDENTIFICATION_METHOD_2021b =
43 "Orthanc " ORTHANC_VERSION " - PS 3.15-2021b Table E.1-1 Basic Profile"; 43 "Orthanc " ORTHANC_VERSION " - PS 3.15-2021b Table E.1-1 Basic Profile";
44 44
45 namespace Orthanc 45 namespace Orthanc
46 { 46 {
47 namespace
48 {
49 enum TagOperation
50 {
51 TagOperation_Keep,
52 TagOperation_Remove
53 };
54 }
55
56
47 DicomModification::DicomTagRange::DicomTagRange(uint16_t groupFrom, 57 DicomModification::DicomTagRange::DicomTagRange(uint16_t groupFrom,
48 uint16_t groupTo, 58 uint16_t groupTo,
49 uint16_t elementFrom, 59 uint16_t elementFrom,
50 uint16_t elementTo) : 60 uint16_t elementTo) :
51 groupFrom_(groupFrom), 61 groupFrom_(groupFrom),
74 bool IsManuallyModified(const DicomTag& tag) const 84 bool IsManuallyModified(const DicomTag& tag) const
75 { 85 {
76 return (that_.IsCleared(tag) || 86 return (that_.IsCleared(tag) ||
77 that_.IsRemoved(tag) || 87 that_.IsRemoved(tag) ||
78 that_.IsReplaced(tag)); 88 that_.IsReplaced(tag));
79 } 89 }
90
91 bool IsKeptSequence(const std::vector<DicomTag>& parentTags,
92 const std::vector<size_t>& parentIndexes,
93 const DicomTag& tag)
94 {
95 for (DicomModification::ListOfPaths::const_iterator
96 it = that_.keepSequences_.begin(); it != that_.keepSequences_.end(); ++it)
97 {
98 if (DicomPath::IsMatch(*it, parentTags, parentIndexes, tag))
99 {
100 return true;
101 }
102 }
103
104 return false;
105 }
106
107 Action GetDefaultAction(const std::vector<DicomTag>& parentTags,
108 const std::vector<size_t>& parentIndexes,
109 const DicomTag& tag)
110 {
111 if (parentTags.empty() ||
112 !that_.isAnonymization_)
113 {
114 // Don't interfere with first-level tags or with modification
115 return Action_None;
116 }
117 else if (IsKeptSequence(parentTags, parentIndexes, tag))
118 {
119 return Action_None;
120 }
121 else if (that_.ArePrivateTagsRemoved() &&
122 tag.IsPrivate())
123 {
124 // New in Orthanc 1.9.5
125 // https://groups.google.com/g/orthanc-users/c/l1mcYCC2u-k/m/jOdGYuagAgAJ
126 return Action_Remove;
127 }
128 else if (that_.IsCleared(tag) ||
129 that_.IsRemoved(tag))
130 {
131 // New in Orthanc 1.9.5
132 // https://groups.google.com/g/orthanc-users/c/l1mcYCC2u-k/m/jOdGYuagAgAJ
133 return Action_Remove;
134 }
135 else
136 {
137 return Action_None;
138 }
139 }
80 140
81 public: 141 public:
82 explicit RelationshipsVisitor(DicomModification& that) : 142 explicit RelationshipsVisitor(DicomModification& that) :
83 that_(that) 143 that_(that)
84 { 144 {
87 virtual Action VisitNotSupported(const std::vector<DicomTag>& parentTags, 147 virtual Action VisitNotSupported(const std::vector<DicomTag>& parentTags,
88 const std::vector<size_t>& parentIndexes, 148 const std::vector<size_t>& parentIndexes,
89 const DicomTag& tag, 149 const DicomTag& tag,
90 ValueRepresentation vr) ORTHANC_OVERRIDE 150 ValueRepresentation vr) ORTHANC_OVERRIDE
91 { 151 {
92 return Action_None; 152 return GetDefaultAction(parentTags, parentIndexes, tag);
93 } 153 }
94 154
95 virtual Action VisitEmptySequence(const std::vector<DicomTag>& parentTags, 155 virtual Action VisitSequence(const std::vector<DicomTag>& parentTags,
96 const std::vector<size_t>& parentIndexes, 156 const std::vector<size_t>& parentIndexes,
97 const DicomTag& tag) ORTHANC_OVERRIDE 157 const DicomTag& tag,
98 { 158 size_t countItems) ORTHANC_OVERRIDE
99 return Action_None; 159 {
160 return GetDefaultAction(parentTags, parentIndexes, tag);
100 } 161 }
101 162
102 virtual Action VisitBinary(const std::vector<DicomTag>& parentTags, 163 virtual Action VisitBinary(const std::vector<DicomTag>& parentTags,
103 const std::vector<size_t>& parentIndexes, 164 const std::vector<size_t>& parentIndexes,
104 const DicomTag& tag, 165 const DicomTag& tag,
105 ValueRepresentation vr, 166 ValueRepresentation vr,
106 const void* data, 167 const void* data,
107 size_t size) ORTHANC_OVERRIDE 168 size_t size) ORTHANC_OVERRIDE
108 { 169 {
109 return Action_None; 170 return GetDefaultAction(parentTags, parentIndexes, tag);
110 } 171 }
111 172
112 virtual Action VisitIntegers(const std::vector<DicomTag>& parentTags, 173 virtual Action VisitIntegers(const std::vector<DicomTag>& parentTags,
113 const std::vector<size_t>& parentIndexes, 174 const std::vector<size_t>& parentIndexes,
114 const DicomTag& tag, 175 const DicomTag& tag,
115 ValueRepresentation vr, 176 ValueRepresentation vr,
116 const std::vector<int64_t>& values) ORTHANC_OVERRIDE 177 const std::vector<int64_t>& values) ORTHANC_OVERRIDE
117 { 178 {
118 return Action_None; 179 return GetDefaultAction(parentTags, parentIndexes, tag);
119 } 180 }
120 181
121 virtual Action VisitDoubles(const std::vector<DicomTag>& parentTags, 182 virtual Action VisitDoubles(const std::vector<DicomTag>& parentTags,
122 const std::vector<size_t>& parentIndexes, 183 const std::vector<size_t>& parentIndexes,
123 const DicomTag& tag, 184 const DicomTag& tag,
124 ValueRepresentation vr, 185 ValueRepresentation vr,
125 const std::vector<double>& value) ORTHANC_OVERRIDE 186 const std::vector<double>& value) ORTHANC_OVERRIDE
126 { 187 {
127 return Action_None; 188 return GetDefaultAction(parentTags, parentIndexes, tag);
128 } 189 }
129 190
130 virtual Action VisitAttributes(const std::vector<DicomTag>& parentTags, 191 virtual Action VisitAttributes(const std::vector<DicomTag>& parentTags,
131 const std::vector<size_t>& parentIndexes, 192 const std::vector<size_t>& parentIndexes,
132 const DicomTag& tag, 193 const DicomTag& tag,
133 const std::vector<DicomTag>& value) ORTHANC_OVERRIDE 194 const std::vector<DicomTag>& value) ORTHANC_OVERRIDE
134 { 195 {
135 return Action_None; 196 return GetDefaultAction(parentTags, parentIndexes, tag);
136 } 197 }
137 198
138 virtual Action VisitString(std::string& newValue, 199 virtual Action VisitString(std::string& newValue,
139 const std::vector<DicomTag>& parentTags, 200 const std::vector<DicomTag>& parentTags,
140 const std::vector<size_t>& parentIndexes, 201 const std::vector<size_t>& parentIndexes,
185 } 246 }
186 else 247 else
187 { 248 {
188 // We are within a sequence 249 // We are within a sequence
189 250
190 if (!that_.keepSequences_.empty()) 251 if (IsKeptSequence(parentTags, parentIndexes, tag))
191 { 252 {
192 // New in Orthanc 1.9.4 - Solves issue LSD-629 253 // New in Orthanc 1.9.4 - Solves issue LSD-629
193 DicomPath path(parentTags, parentIndexes, tag); 254 return Action_None;
194 255 }
195 for (ListOfPaths::const_iterator it = that_.keepSequences_.begin(); 256
196 it != that_.keepSequences_.end(); ++it) 257 if (that_.isAnonymization_)
258 {
259 // New in Orthanc 1.9.5, similar to "GetDefaultAction()"
260 // https://groups.google.com/g/orthanc-users/c/l1mcYCC2u-k/m/jOdGYuagAgAJ
261 if (that_.ArePrivateTagsRemoved() &&
262 tag.IsPrivate())
197 { 263 {
198 if (DicomPath::IsMatch(*it, path)) 264 return Action_Remove;
199 { 265 }
200 return Action_None; 266 else if (that_.IsRemoved(tag))
201 } 267 {
268 return Action_Remove;
269 }
270 else if (that_.IsCleared(tag))
271 {
272 // This is different from "GetDefaultAction()", because we know how to clear string tags
273 newValue.clear();
274 return Action_Replace;
202 } 275 }
203 } 276 }
204 277
205 if (tag == DICOM_TAG_STUDY_INSTANCE_UID) 278 if (tag == DICOM_TAG_STUDY_INSTANCE_UID)
206 { 279 {
1104 } 1177 }
1105 1178
1106 1179
1107 static void ParseListOfTags(DicomModification& target, 1180 static void ParseListOfTags(DicomModification& target,
1108 const Json::Value& query, 1181 const Json::Value& query,
1109 DicomModification::TagOperation operation, 1182 TagOperation operation,
1110 bool force) 1183 bool force)
1111 { 1184 {
1112 if (!query.isArray()) 1185 if (!query.isArray())
1113 { 1186 {
1114 throw OrthancException(ErrorCode_BadRequest); 1187 throw OrthancException(ErrorCode_BadRequest);
1129 !force && 1202 !force &&
1130 IsDatabaseKey(path.GetFinalTag())) 1203 IsDatabaseKey(path.GetFinalTag()))
1131 { 1204 {
1132 throw OrthancException(ErrorCode_BadRequest, 1205 throw OrthancException(ErrorCode_BadRequest,
1133 "Marking tag \"" + name + "\" as to be " + 1206 "Marking tag \"" + name + "\" as to be " +
1134 (operation == DicomModification::TagOperation_Keep ? "kept" : "removed") + 1207 (operation == TagOperation_Keep ? "kept" : "removed") +
1135 " requires the \"Force\" option to be set to true"); 1208 " requires the \"Force\" option to be set to true");
1136 } 1209 }
1137 1210
1138 switch (operation) 1211 switch (operation)
1139 { 1212 {
1140 case DicomModification::TagOperation_Keep: 1213 case TagOperation_Keep:
1141 target.Keep(path); 1214 target.Keep(path);
1142 LOG(TRACE) << "Keep: " << name << " = " << path.Format(); 1215 LOG(TRACE) << "Keep: " << name << " = " << path.Format();
1143 break; 1216 break;
1144 1217
1145 case DicomModification::TagOperation_Remove: 1218 case TagOperation_Remove:
1146 target.Remove(path); 1219 target.Remove(path);
1147 LOG(TRACE) << "Remove: " << name << " = " << path.Format(); 1220 LOG(TRACE) << "Remove: " << name << " = " << path.Format();
1148 break; 1221 break;
1149 1222
1150 default: 1223 default: