Mercurial > hg > orthanc
comparison OrthancServer/Sources/ServerEnumerations.cpp @ 4540:9c0cff7a6ca2 db-changes
integration mainline->db-changes
author | Sebastien Jodogne <s.jodogne@gmail.com> |
---|---|
date | Tue, 02 Mar 2021 16:51:19 +0100 |
parents | 5b929e6b3c36 |
children | f0038043fb97 7053502fbf97 |
comparison
equal
deleted
inserted
replaced
3141:f2b300e46755 | 4540:9c0cff7a6ca2 |
---|---|
1 /** | |
2 * Orthanc - A Lightweight, RESTful DICOM Store | |
3 * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics | |
4 * Department, University Hospital of Liege, Belgium | |
5 * Copyright (C) 2017-2021 Osimis S.A., Belgium | |
6 * | |
7 * This program is free software: you can redistribute it and/or | |
8 * modify it under the terms of the GNU General Public License as | |
9 * published by the Free Software Foundation, either version 3 of the | |
10 * License, or (at your option) any later version. | |
11 * | |
12 * In addition, as a special exception, the copyright holders of this | |
13 * program give permission to link the code of its release with the | |
14 * OpenSSL project's "OpenSSL" library (or with modified versions of it | |
15 * that use the same license as the "OpenSSL" library), and distribute | |
16 * the linked executables. You must obey the GNU General Public License | |
17 * in all respects for all of the code used other than "OpenSSL". If you | |
18 * modify file(s) with this exception, you may extend this exception to | |
19 * your version of the file(s), but you are not obligated to do so. If | |
20 * you do not wish to do so, delete this exception statement from your | |
21 * version. If you delete this exception statement from all source files | |
22 * in the program, then also delete it here. | |
23 * | |
24 * This program is distributed in the hope that it will be useful, but | |
25 * WITHOUT ANY WARRANTY; without even the implied warranty of | |
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
27 * General Public License for more details. | |
28 * | |
29 * You should have received a copy of the GNU General Public License | |
30 * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
31 **/ | |
32 | |
33 | |
34 #include "PrecompiledHeadersServer.h" | |
35 #include "ServerEnumerations.h" | |
36 | |
37 #include "../../OrthancFramework/Sources/OrthancException.h" | |
38 #include "../../OrthancFramework/Sources/EnumerationDictionary.h" | |
39 #include "../../OrthancFramework/Sources/Logging.h" | |
40 #include "../../OrthancFramework/Sources/Toolbox.h" | |
41 | |
42 #include <boost/thread.hpp> | |
43 | |
44 namespace Orthanc | |
45 { | |
46 typedef std::map<FileContentType, std::string> MimeTypes; | |
47 | |
48 static boost::mutex enumerationsMutex_; | |
49 static EnumerationDictionary<MetadataType> dictMetadataType_; | |
50 static EnumerationDictionary<FileContentType> dictContentType_; | |
51 static MimeTypes mimeTypes_; | |
52 | |
53 void InitializeServerEnumerations() | |
54 { | |
55 boost::mutex::scoped_lock lock(enumerationsMutex_); | |
56 | |
57 dictMetadataType_.Clear(); | |
58 dictContentType_.Clear(); | |
59 | |
60 dictMetadataType_.Add(MetadataType_Instance_IndexInSeries, "IndexInSeries"); | |
61 dictMetadataType_.Add(MetadataType_Instance_ReceptionDate, "ReceptionDate"); | |
62 dictMetadataType_.Add(MetadataType_RemoteAet, "RemoteAET"); | |
63 dictMetadataType_.Add(MetadataType_Series_ExpectedNumberOfInstances, "ExpectedNumberOfInstances"); | |
64 dictMetadataType_.Add(MetadataType_ModifiedFrom, "ModifiedFrom"); | |
65 dictMetadataType_.Add(MetadataType_AnonymizedFrom, "AnonymizedFrom"); | |
66 dictMetadataType_.Add(MetadataType_LastUpdate, "LastUpdate"); | |
67 dictMetadataType_.Add(MetadataType_Instance_Origin, "Origin"); | |
68 dictMetadataType_.Add(MetadataType_Instance_TransferSyntax, "TransferSyntax"); | |
69 dictMetadataType_.Add(MetadataType_Instance_SopClassUid, "SopClassUid"); | |
70 dictMetadataType_.Add(MetadataType_Instance_RemoteIp, "RemoteIP"); | |
71 dictMetadataType_.Add(MetadataType_Instance_CalledAet, "CalledAET"); | |
72 dictMetadataType_.Add(MetadataType_Instance_HttpUsername, "HttpUsername"); | |
73 dictMetadataType_.Add(MetadataType_Instance_PixelDataOffset, "PixelDataOffset"); | |
74 | |
75 dictContentType_.Add(FileContentType_Dicom, "dicom"); | |
76 dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json"); | |
77 dictContentType_.Add(FileContentType_DicomUntilPixelData, "dicom-until-pixel-data"); | |
78 } | |
79 | |
80 void RegisterUserMetadata(int metadata, | |
81 const std::string& name) | |
82 { | |
83 boost::mutex::scoped_lock lock(enumerationsMutex_); | |
84 | |
85 MetadataType type = static_cast<MetadataType>(metadata); | |
86 | |
87 if (metadata < 0 || | |
88 !IsUserMetadata(type)) | |
89 { | |
90 LOG(ERROR) << "A user content type must have index between " | |
91 << static_cast<int>(MetadataType_StartUser) << " and " | |
92 << static_cast<int>(MetadataType_EndUser) << ", but \"" | |
93 << name << "\" has index " << metadata; | |
94 | |
95 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
96 } | |
97 | |
98 if (dictMetadataType_.Contains(type)) | |
99 { | |
100 LOG(ERROR) << "Cannot associate user content type \"" | |
101 << name << "\" with index " << metadata | |
102 << ", as this index is already used"; | |
103 | |
104 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
105 } | |
106 | |
107 dictMetadataType_.Add(type, name); | |
108 } | |
109 | |
110 std::string EnumerationToString(MetadataType type) | |
111 { | |
112 // This function MUST return a "std::string" and not "const | |
113 // char*", as the result is not a static string | |
114 boost::mutex::scoped_lock lock(enumerationsMutex_); | |
115 return dictMetadataType_.Translate(type); | |
116 } | |
117 | |
118 MetadataType StringToMetadata(const std::string& str) | |
119 { | |
120 boost::mutex::scoped_lock lock(enumerationsMutex_); | |
121 return dictMetadataType_.Translate(str); | |
122 } | |
123 | |
124 void RegisterUserContentType(int contentType, | |
125 const std::string& name, | |
126 const std::string& mime) | |
127 { | |
128 boost::mutex::scoped_lock lock(enumerationsMutex_); | |
129 | |
130 FileContentType type = static_cast<FileContentType>(contentType); | |
131 | |
132 if (contentType < 0 || | |
133 !IsUserContentType(type)) | |
134 { | |
135 LOG(ERROR) << "A user content type must have index between " | |
136 << static_cast<int>(FileContentType_StartUser) << " and " | |
137 << static_cast<int>(FileContentType_EndUser) << ", but \"" | |
138 << name << "\" has index " << contentType; | |
139 | |
140 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
141 } | |
142 | |
143 if (dictContentType_.Contains(type)) | |
144 { | |
145 LOG(ERROR) << "Cannot associate user content type \"" | |
146 << name << "\" with index " << contentType | |
147 << ", as this index is already used"; | |
148 | |
149 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
150 } | |
151 | |
152 dictContentType_.Add(type, name); | |
153 mimeTypes_[type] = mime; | |
154 } | |
155 | |
156 std::string EnumerationToString(FileContentType type) | |
157 { | |
158 // This function MUST return a "std::string" and not "const | |
159 // char*", as the result is not a static string | |
160 boost::mutex::scoped_lock lock(enumerationsMutex_); | |
161 return dictContentType_.Translate(type); | |
162 } | |
163 | |
164 std::string GetFileContentMime(FileContentType type) | |
165 { | |
166 if (type >= FileContentType_StartUser && | |
167 type <= FileContentType_EndUser) | |
168 { | |
169 boost::mutex::scoped_lock lock(enumerationsMutex_); | |
170 | |
171 MimeTypes::const_iterator it = mimeTypes_.find(type); | |
172 if (it != mimeTypes_.end()) | |
173 { | |
174 return it->second; | |
175 } | |
176 } | |
177 | |
178 switch (type) | |
179 { | |
180 case FileContentType_Dicom: | |
181 return EnumerationToString(MimeType_Dicom); | |
182 | |
183 case FileContentType_DicomAsJson: | |
184 return MIME_JSON_UTF8; | |
185 | |
186 default: | |
187 return EnumerationToString(MimeType_Binary); | |
188 } | |
189 } | |
190 | |
191 FileContentType StringToContentType(const std::string& str) | |
192 { | |
193 boost::mutex::scoped_lock lock(enumerationsMutex_); | |
194 return dictContentType_.Translate(str); | |
195 } | |
196 | |
197 | |
198 FindStorageAccessMode StringToFindStorageAccessMode(const std::string& value) | |
199 { | |
200 if (value == "Always") | |
201 { | |
202 return FindStorageAccessMode_DiskOnLookupAndAnswer; | |
203 } | |
204 else if (value == "Never") | |
205 { | |
206 return FindStorageAccessMode_DatabaseOnly; | |
207 } | |
208 else if (value == "Answers") | |
209 { | |
210 return FindStorageAccessMode_DiskOnAnswer; | |
211 } | |
212 else | |
213 { | |
214 throw OrthancException(ErrorCode_ParameterOutOfRange, | |
215 "Configuration option \"StorageAccessOnFind\" " | |
216 "should be \"Always\", \"Never\" or \"Answers\": " + value); | |
217 } | |
218 } | |
219 | |
220 | |
221 BuiltinDecoderTranscoderOrder StringToBuiltinDecoderTranscoderOrder(const std::string& value) | |
222 { | |
223 if (value == "Before") | |
224 { | |
225 return BuiltinDecoderTranscoderOrder_Before; | |
226 } | |
227 else if (value == "After") | |
228 { | |
229 return BuiltinDecoderTranscoderOrder_After; | |
230 } | |
231 else if (value == "Disabled") | |
232 { | |
233 return BuiltinDecoderTranscoderOrder_Disabled; | |
234 } | |
235 else | |
236 { | |
237 throw OrthancException(ErrorCode_ParameterOutOfRange, | |
238 "Configuration option \"BuiltinDecoderTranscoderOrder\" " | |
239 "should be \"After\", \"Before\" or \"Disabled\": " + value); | |
240 } | |
241 } | |
242 | |
243 | |
244 Verbosity StringToVerbosity(const std::string& str) | |
245 { | |
246 if (str == "default") | |
247 { | |
248 return Verbosity_Default; | |
249 } | |
250 else if (str == "verbose") | |
251 { | |
252 return Verbosity_Verbose; | |
253 } | |
254 else if (str == "trace") | |
255 { | |
256 return Verbosity_Trace; | |
257 } | |
258 else | |
259 { | |
260 throw OrthancException(ErrorCode_ParameterOutOfRange, | |
261 "Verbosity can be \"default\", \"verbose\" or \"trace\": " + str); | |
262 } | |
263 } | |
264 | |
265 | |
266 std::string GetBasePath(ResourceType type, | |
267 const std::string& publicId) | |
268 { | |
269 switch (type) | |
270 { | |
271 case ResourceType_Patient: | |
272 return "/patients/" + publicId; | |
273 | |
274 case ResourceType_Study: | |
275 return "/studies/" + publicId; | |
276 | |
277 case ResourceType_Series: | |
278 return "/series/" + publicId; | |
279 | |
280 case ResourceType_Instance: | |
281 return "/instances/" + publicId; | |
282 | |
283 default: | |
284 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
285 } | |
286 } | |
287 | |
288 const char* EnumerationToString(SeriesStatus status) | |
289 { | |
290 switch (status) | |
291 { | |
292 case SeriesStatus_Complete: | |
293 return "Complete"; | |
294 | |
295 case SeriesStatus_Missing: | |
296 return "Missing"; | |
297 | |
298 case SeriesStatus_Inconsistent: | |
299 return "Inconsistent"; | |
300 | |
301 case SeriesStatus_Unknown: | |
302 return "Unknown"; | |
303 | |
304 default: | |
305 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
306 } | |
307 } | |
308 | |
309 const char* EnumerationToString(StoreStatus status) | |
310 { | |
311 switch (status) | |
312 { | |
313 case StoreStatus_Success: | |
314 return "Success"; | |
315 | |
316 case StoreStatus_AlreadyStored: | |
317 return "AlreadyStored"; | |
318 | |
319 case StoreStatus_Failure: | |
320 return "Failure"; | |
321 | |
322 case StoreStatus_FilteredOut: | |
323 return "FilteredOut"; | |
324 | |
325 default: | |
326 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
327 } | |
328 } | |
329 | |
330 | |
331 const char* EnumerationToString(ChangeType type) | |
332 { | |
333 switch (type) | |
334 { | |
335 case ChangeType_CompletedSeries: | |
336 return "CompletedSeries"; | |
337 | |
338 case ChangeType_NewInstance: | |
339 return "NewInstance"; | |
340 | |
341 case ChangeType_NewPatient: | |
342 return "NewPatient"; | |
343 | |
344 case ChangeType_NewSeries: | |
345 return "NewSeries"; | |
346 | |
347 case ChangeType_NewStudy: | |
348 return "NewStudy"; | |
349 | |
350 case ChangeType_AnonymizedStudy: | |
351 return "AnonymizedStudy"; | |
352 | |
353 case ChangeType_AnonymizedSeries: | |
354 return "AnonymizedSeries"; | |
355 | |
356 case ChangeType_ModifiedStudy: | |
357 return "ModifiedStudy"; | |
358 | |
359 case ChangeType_ModifiedSeries: | |
360 return "ModifiedSeries"; | |
361 | |
362 case ChangeType_AnonymizedPatient: | |
363 return "AnonymizedPatient"; | |
364 | |
365 case ChangeType_ModifiedPatient: | |
366 return "ModifiedPatient"; | |
367 | |
368 case ChangeType_StablePatient: | |
369 return "StablePatient"; | |
370 | |
371 case ChangeType_StableStudy: | |
372 return "StableStudy"; | |
373 | |
374 case ChangeType_StableSeries: | |
375 return "StableSeries"; | |
376 | |
377 case ChangeType_Deleted: | |
378 return "Deleted"; | |
379 | |
380 case ChangeType_NewChildInstance: | |
381 return "NewChildInstance"; | |
382 | |
383 case ChangeType_UpdatedAttachment: | |
384 return "UpdatedAttachment"; | |
385 | |
386 case ChangeType_UpdatedMetadata: | |
387 return "UpdatedMetadata"; | |
388 | |
389 default: | |
390 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
391 } | |
392 } | |
393 | |
394 | |
395 const char* EnumerationToString(Verbosity verbosity) | |
396 { | |
397 switch (verbosity) | |
398 { | |
399 case Verbosity_Default: | |
400 return "default"; | |
401 | |
402 case Verbosity_Verbose: | |
403 return "verbose"; | |
404 | |
405 case Verbosity_Trace: | |
406 return "trace"; | |
407 | |
408 default: | |
409 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
410 } | |
411 } | |
412 | |
413 | |
414 bool IsUserMetadata(MetadataType metadata) | |
415 { | |
416 return (metadata >= MetadataType_StartUser && | |
417 metadata <= MetadataType_EndUser); | |
418 } | |
419 | |
420 | |
421 void GetTransferSyntaxGroup(std::set<DicomTransferSyntax>& target, | |
422 TransferSyntaxGroup source) | |
423 { | |
424 target.clear(); | |
425 | |
426 switch (source) | |
427 { | |
428 // Transfer syntaxes supported since Orthanc 0.7.2 | |
429 case TransferSyntaxGroup_Deflated: | |
430 target.insert(DicomTransferSyntax_DeflatedLittleEndianExplicit); | |
431 break; | |
432 | |
433 case TransferSyntaxGroup_Jpeg: | |
434 target.insert(DicomTransferSyntax_JPEGProcess1); | |
435 target.insert(DicomTransferSyntax_JPEGProcess2_4); | |
436 target.insert(DicomTransferSyntax_JPEGProcess3_5); | |
437 target.insert(DicomTransferSyntax_JPEGProcess6_8); | |
438 target.insert(DicomTransferSyntax_JPEGProcess7_9); | |
439 target.insert(DicomTransferSyntax_JPEGProcess10_12); | |
440 target.insert(DicomTransferSyntax_JPEGProcess11_13); | |
441 target.insert(DicomTransferSyntax_JPEGProcess14); | |
442 target.insert(DicomTransferSyntax_JPEGProcess15); | |
443 target.insert(DicomTransferSyntax_JPEGProcess16_18); | |
444 target.insert(DicomTransferSyntax_JPEGProcess17_19); | |
445 target.insert(DicomTransferSyntax_JPEGProcess20_22); | |
446 target.insert(DicomTransferSyntax_JPEGProcess21_23); | |
447 target.insert(DicomTransferSyntax_JPEGProcess24_26); | |
448 target.insert(DicomTransferSyntax_JPEGProcess25_27); | |
449 target.insert(DicomTransferSyntax_JPEGProcess28); | |
450 target.insert(DicomTransferSyntax_JPEGProcess29); | |
451 target.insert(DicomTransferSyntax_JPEGProcess14SV1); | |
452 break; | |
453 | |
454 case TransferSyntaxGroup_Jpeg2000: | |
455 target.insert(DicomTransferSyntax_JPEG2000); | |
456 target.insert(DicomTransferSyntax_JPEG2000LosslessOnly); | |
457 target.insert(DicomTransferSyntax_JPEG2000Multicomponent); | |
458 target.insert(DicomTransferSyntax_JPEG2000MulticomponentLosslessOnly); | |
459 break; | |
460 | |
461 case TransferSyntaxGroup_JpegLossless: | |
462 target.insert(DicomTransferSyntax_JPEGLSLossless); | |
463 target.insert(DicomTransferSyntax_JPEGLSLossy); | |
464 break; | |
465 | |
466 case TransferSyntaxGroup_Jpip: | |
467 target.insert(DicomTransferSyntax_JPIPReferenced); | |
468 target.insert(DicomTransferSyntax_JPIPReferencedDeflate); | |
469 break; | |
470 | |
471 case TransferSyntaxGroup_Mpeg2: | |
472 target.insert(DicomTransferSyntax_MPEG2MainProfileAtMainLevel); | |
473 target.insert(DicomTransferSyntax_MPEG2MainProfileAtHighLevel); | |
474 break; | |
475 | |
476 case TransferSyntaxGroup_Rle: | |
477 target.insert(DicomTransferSyntax_RLELossless); | |
478 break; | |
479 | |
480 case TransferSyntaxGroup_Mpeg4: | |
481 // New in Orthanc 1.6.0 | |
482 target.insert(DicomTransferSyntax_MPEG4BDcompatibleHighProfileLevel4_1); | |
483 target.insert(DicomTransferSyntax_MPEG4HighProfileLevel4_1); | |
484 target.insert(DicomTransferSyntax_MPEG4HighProfileLevel4_2_For2DVideo); | |
485 target.insert(DicomTransferSyntax_MPEG4HighProfileLevel4_2_For3DVideo); | |
486 target.insert(DicomTransferSyntax_MPEG4StereoHighProfileLevel4_2); | |
487 break; | |
488 | |
489 case TransferSyntaxGroup_H265: | |
490 // New in Orthanc 1.9.0 | |
491 target.insert(DicomTransferSyntax_HEVCMainProfileLevel5_1); | |
492 target.insert(DicomTransferSyntax_HEVCMain10ProfileLevel5_1); | |
493 break; | |
494 | |
495 default: | |
496 throw OrthancException(ErrorCode_ParameterOutOfRange); | |
497 } | |
498 } | |
499 } |