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 }