1
|
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 *
|
|
6 * This program is free software: you can redistribute it and/or
|
|
7 * modify it under the terms of the GNU General Public License as
|
|
8 * published by the Free Software Foundation, either version 3 of the
|
|
9 * License, or (at your option) any later version.
|
|
10 *
|
|
11 * In addition, as a special exception, the copyright holders of this
|
|
12 * program give permission to link the code of its release with the
|
|
13 * OpenSSL project's "OpenSSL" library (or with modified versions of it
|
|
14 * that use the same license as the "OpenSSL" library), and distribute
|
|
15 * the linked executables. You must obey the GNU General Public License
|
|
16 * in all respects for all of the code used other than "OpenSSL". If you
|
|
17 * modify file(s) with this exception, you may extend this exception to
|
|
18 * your version of the file(s), but you are not obligated to do so. If
|
|
19 * you do not wish to do so, delete this exception statement from your
|
|
20 * version. If you delete this exception statement from all source files
|
|
21 * in the program, then also delete it here.
|
|
22 *
|
|
23 * This program is distributed in the hope that it will be useful, but
|
|
24 * WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
25 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
26 * General Public License for more details.
|
|
27 *
|
|
28 * You should have received a copy of the GNU General Public License
|
|
29 * along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
30 **/
|
|
31
|
|
32
|
|
33 #include "PrecompiledHeadersServer.h"
|
|
34 #include "ServerEnumerations.h"
|
|
35
|
|
36 #include "../Core/OrthancException.h"
|
|
37 #include "../Core/EnumerationDictionary.h"
|
|
38 #include "../Core/Logging.h"
|
|
39 #include "../Core/Toolbox.h"
|
|
40
|
|
41 #include <boost/thread.hpp>
|
|
42
|
|
43 namespace Orthanc
|
|
44 {
|
|
45 typedef std::map<FileContentType, std::string> MimeTypes;
|
|
46
|
|
47 static boost::mutex enumerationsMutex_;
|
|
48 static Toolbox::EnumerationDictionary<MetadataType> dictMetadataType_;
|
|
49 static Toolbox::EnumerationDictionary<FileContentType> dictContentType_;
|
|
50 static MimeTypes mimeTypes_;
|
|
51
|
|
52 void InitializeServerEnumerations()
|
|
53 {
|
|
54 boost::mutex::scoped_lock lock(enumerationsMutex_);
|
|
55
|
|
56 dictMetadataType_.Clear();
|
|
57 dictContentType_.Clear();
|
|
58
|
|
59 dictMetadataType_.Add(MetadataType_Instance_IndexInSeries, "IndexInSeries");
|
|
60 dictMetadataType_.Add(MetadataType_Instance_ReceptionDate, "ReceptionDate");
|
|
61 dictMetadataType_.Add(MetadataType_Instance_RemoteAet, "RemoteAET");
|
|
62 dictMetadataType_.Add(MetadataType_Series_ExpectedNumberOfInstances, "ExpectedNumberOfInstances");
|
|
63 dictMetadataType_.Add(MetadataType_ModifiedFrom, "ModifiedFrom");
|
|
64 dictMetadataType_.Add(MetadataType_AnonymizedFrom, "AnonymizedFrom");
|
|
65 dictMetadataType_.Add(MetadataType_LastUpdate, "LastUpdate");
|
|
66 dictMetadataType_.Add(MetadataType_Instance_Origin, "Origin");
|
|
67
|
|
68 dictContentType_.Add(FileContentType_Dicom, "dicom");
|
|
69 dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json");
|
|
70 }
|
|
71
|
|
72 void RegisterUserMetadata(int metadata,
|
|
73 const std::string& name)
|
|
74 {
|
|
75 boost::mutex::scoped_lock lock(enumerationsMutex_);
|
|
76
|
|
77 MetadataType type = static_cast<MetadataType>(metadata);
|
|
78
|
|
79 if (metadata < 0 ||
|
|
80 !IsUserMetadata(type))
|
|
81 {
|
|
82 LOG(ERROR) << "A user content type must have index between "
|
|
83 << static_cast<int>(MetadataType_StartUser) << " and "
|
|
84 << static_cast<int>(MetadataType_EndUser) << ", but \""
|
|
85 << name << "\" has index " << metadata;
|
|
86
|
|
87 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
88 }
|
|
89
|
|
90 if (dictMetadataType_.Contains(type))
|
|
91 {
|
|
92 LOG(ERROR) << "Cannot associate user content type \""
|
|
93 << name << "\" with index " << metadata
|
|
94 << ", as this index is already used";
|
|
95
|
|
96 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
97 }
|
|
98
|
|
99 dictMetadataType_.Add(type, name);
|
|
100 }
|
|
101
|
|
102 std::string EnumerationToString(MetadataType type)
|
|
103 {
|
|
104 // This function MUST return a "std::string" and not "const
|
|
105 // char*", as the result is not a static string
|
|
106 boost::mutex::scoped_lock lock(enumerationsMutex_);
|
|
107 return dictMetadataType_.Translate(type);
|
|
108 }
|
|
109
|
|
110 MetadataType StringToMetadata(const std::string& str)
|
|
111 {
|
|
112 boost::mutex::scoped_lock lock(enumerationsMutex_);
|
|
113 return dictMetadataType_.Translate(str);
|
|
114 }
|
|
115
|
|
116 void RegisterUserContentType(int contentType,
|
|
117 const std::string& name,
|
|
118 const std::string& mime)
|
|
119 {
|
|
120 boost::mutex::scoped_lock lock(enumerationsMutex_);
|
|
121
|
|
122 FileContentType type = static_cast<FileContentType>(contentType);
|
|
123
|
|
124 if (contentType < 0 ||
|
|
125 !IsUserContentType(type))
|
|
126 {
|
|
127 LOG(ERROR) << "A user content type must have index between "
|
|
128 << static_cast<int>(FileContentType_StartUser) << " and "
|
|
129 << static_cast<int>(FileContentType_EndUser) << ", but \""
|
|
130 << name << "\" has index " << contentType;
|
|
131
|
|
132 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
133 }
|
|
134
|
|
135 if (dictContentType_.Contains(type))
|
|
136 {
|
|
137 LOG(ERROR) << "Cannot associate user content type \""
|
|
138 << name << "\" with index " << contentType
|
|
139 << ", as this index is already used";
|
|
140
|
|
141 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
142 }
|
|
143
|
|
144 dictContentType_.Add(type, name);
|
|
145 mimeTypes_[type] = mime;
|
|
146 }
|
|
147
|
|
148 std::string EnumerationToString(FileContentType type)
|
|
149 {
|
|
150 // This function MUST return a "std::string" and not "const
|
|
151 // char*", as the result is not a static string
|
|
152 boost::mutex::scoped_lock lock(enumerationsMutex_);
|
|
153 return dictContentType_.Translate(type);
|
|
154 }
|
|
155
|
|
156 std::string GetFileContentMime(FileContentType type)
|
|
157 {
|
|
158 if (type >= FileContentType_StartUser &&
|
|
159 type <= FileContentType_EndUser)
|
|
160 {
|
|
161 boost::mutex::scoped_lock lock(enumerationsMutex_);
|
|
162
|
|
163 MimeTypes::const_iterator it = mimeTypes_.find(type);
|
|
164 if (it != mimeTypes_.end())
|
|
165 {
|
|
166 return it->second;
|
|
167 }
|
|
168 }
|
|
169
|
|
170 switch (type)
|
|
171 {
|
|
172 case FileContentType_Dicom:
|
|
173 return "application/dicom";
|
|
174
|
|
175 case FileContentType_DicomAsJson:
|
|
176 return "application/json";
|
|
177
|
|
178 default:
|
|
179 return "application/octet-stream";
|
|
180 }
|
|
181 }
|
|
182
|
|
183 FileContentType StringToContentType(const std::string& str)
|
|
184 {
|
|
185 boost::mutex::scoped_lock lock(enumerationsMutex_);
|
|
186 return dictContentType_.Translate(str);
|
|
187 }
|
|
188
|
|
189 std::string GetBasePath(ResourceType type,
|
|
190 const std::string& publicId)
|
|
191 {
|
|
192 switch (type)
|
|
193 {
|
|
194 case ResourceType_Patient:
|
|
195 return "/patients/" + publicId;
|
|
196
|
|
197 case ResourceType_Study:
|
|
198 return "/studies/" + publicId;
|
|
199
|
|
200 case ResourceType_Series:
|
|
201 return "/series/" + publicId;
|
|
202
|
|
203 case ResourceType_Instance:
|
|
204 return "/instances/" + publicId;
|
|
205
|
|
206 default:
|
|
207 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
208 }
|
|
209 }
|
|
210
|
|
211 const char* EnumerationToString(SeriesStatus status)
|
|
212 {
|
|
213 switch (status)
|
|
214 {
|
|
215 case SeriesStatus_Complete:
|
|
216 return "Complete";
|
|
217
|
|
218 case SeriesStatus_Missing:
|
|
219 return "Missing";
|
|
220
|
|
221 case SeriesStatus_Inconsistent:
|
|
222 return "Inconsistent";
|
|
223
|
|
224 case SeriesStatus_Unknown:
|
|
225 return "Unknown";
|
|
226
|
|
227 default:
|
|
228 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
229 }
|
|
230 }
|
|
231
|
|
232 const char* EnumerationToString(StoreStatus status)
|
|
233 {
|
|
234 switch (status)
|
|
235 {
|
|
236 case StoreStatus_Success:
|
|
237 return "Success";
|
|
238
|
|
239 case StoreStatus_AlreadyStored:
|
|
240 return "AlreadyStored";
|
|
241
|
|
242 case StoreStatus_Failure:
|
|
243 return "Failure";
|
|
244
|
|
245 case StoreStatus_FilteredOut:
|
|
246 return "FilteredOut";
|
|
247
|
|
248 default:
|
|
249 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
250 }
|
|
251 }
|
|
252
|
|
253
|
|
254 const char* EnumerationToString(ChangeType type)
|
|
255 {
|
|
256 switch (type)
|
|
257 {
|
|
258 case ChangeType_CompletedSeries:
|
|
259 return "CompletedSeries";
|
|
260
|
|
261 case ChangeType_NewInstance:
|
|
262 return "NewInstance";
|
|
263
|
|
264 case ChangeType_NewPatient:
|
|
265 return "NewPatient";
|
|
266
|
|
267 case ChangeType_NewSeries:
|
|
268 return "NewSeries";
|
|
269
|
|
270 case ChangeType_NewStudy:
|
|
271 return "NewStudy";
|
|
272
|
|
273 case ChangeType_AnonymizedStudy:
|
|
274 return "AnonymizedStudy";
|
|
275
|
|
276 case ChangeType_AnonymizedSeries:
|
|
277 return "AnonymizedSeries";
|
|
278
|
|
279 case ChangeType_ModifiedStudy:
|
|
280 return "ModifiedStudy";
|
|
281
|
|
282 case ChangeType_ModifiedSeries:
|
|
283 return "ModifiedSeries";
|
|
284
|
|
285 case ChangeType_AnonymizedPatient:
|
|
286 return "AnonymizedPatient";
|
|
287
|
|
288 case ChangeType_ModifiedPatient:
|
|
289 return "ModifiedPatient";
|
|
290
|
|
291 case ChangeType_StablePatient:
|
|
292 return "StablePatient";
|
|
293
|
|
294 case ChangeType_StableStudy:
|
|
295 return "StableStudy";
|
|
296
|
|
297 case ChangeType_StableSeries:
|
|
298 return "StableSeries";
|
|
299
|
|
300 case ChangeType_Deleted:
|
|
301 return "Deleted";
|
|
302
|
|
303 case ChangeType_NewChildInstance:
|
|
304 return "NewChildInstance";
|
|
305
|
|
306 case ChangeType_UpdatedAttachment:
|
|
307 return "UpdatedAttachment";
|
|
308
|
|
309 case ChangeType_UpdatedMetadata:
|
|
310 return "UpdatedMetadata";
|
|
311
|
|
312 default:
|
|
313 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
314 }
|
|
315 }
|
|
316
|
|
317
|
|
318 const char* EnumerationToString(ModalityManufacturer manufacturer)
|
|
319 {
|
|
320 switch (manufacturer)
|
|
321 {
|
|
322 case ModalityManufacturer_Generic:
|
|
323 return "Generic";
|
|
324
|
|
325 case ModalityManufacturer_StoreScp:
|
|
326 return "StoreScp";
|
|
327
|
|
328 case ModalityManufacturer_ClearCanvas:
|
|
329 return "ClearCanvas";
|
|
330
|
|
331 case ModalityManufacturer_MedInria:
|
|
332 return "MedInria";
|
|
333
|
|
334 case ModalityManufacturer_Dcm4Chee:
|
|
335 return "Dcm4Chee";
|
|
336
|
|
337 case ModalityManufacturer_SyngoVia:
|
|
338 return "SyngoVia";
|
|
339
|
|
340 case ModalityManufacturer_AgfaImpax:
|
|
341 return "AgfaImpax";
|
|
342
|
|
343 case ModalityManufacturer_EFilm2:
|
|
344 return "EFilm2";
|
|
345
|
|
346 case ModalityManufacturer_Vitrea:
|
|
347 return "Vitrea";
|
|
348
|
|
349 default:
|
|
350 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
351 }
|
|
352 }
|
|
353
|
|
354
|
|
355 const char* EnumerationToString(DicomRequestType type)
|
|
356 {
|
|
357 switch (type)
|
|
358 {
|
|
359 case DicomRequestType_Echo:
|
|
360 return "Echo";
|
|
361 break;
|
|
362
|
|
363 case DicomRequestType_Find:
|
|
364 return "Find";
|
|
365 break;
|
|
366
|
|
367 case DicomRequestType_Get:
|
|
368 return "Get";
|
|
369 break;
|
|
370
|
|
371 case DicomRequestType_Move:
|
|
372 return "Move";
|
|
373 break;
|
|
374
|
|
375 case DicomRequestType_Store:
|
|
376 return "Store";
|
|
377 break;
|
|
378
|
|
379 default:
|
|
380 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
381 }
|
|
382 }
|
|
383
|
|
384
|
|
385
|
|
386 ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer)
|
|
387 {
|
|
388 if (manufacturer == "Generic")
|
|
389 {
|
|
390 return ModalityManufacturer_Generic;
|
|
391 }
|
|
392 else if (manufacturer == "ClearCanvas")
|
|
393 {
|
|
394 return ModalityManufacturer_ClearCanvas;
|
|
395 }
|
|
396 else if (manufacturer == "StoreScp")
|
|
397 {
|
|
398 return ModalityManufacturer_StoreScp;
|
|
399 }
|
|
400 else if (manufacturer == "MedInria")
|
|
401 {
|
|
402 return ModalityManufacturer_MedInria;
|
|
403 }
|
|
404 else if (manufacturer == "Dcm4Chee")
|
|
405 {
|
|
406 return ModalityManufacturer_Dcm4Chee;
|
|
407 }
|
|
408 else if (manufacturer == "SyngoVia")
|
|
409 {
|
|
410 return ModalityManufacturer_SyngoVia;
|
|
411 }
|
|
412 else if (manufacturer == "AgfaImpax")
|
|
413 {
|
|
414 return ModalityManufacturer_AgfaImpax;
|
|
415 }
|
|
416 else if (manufacturer == "Vitrea")
|
|
417 {
|
|
418 return ModalityManufacturer_Vitrea;
|
|
419 }
|
|
420 else if (manufacturer == "EFilm2")
|
|
421 {
|
|
422 return ModalityManufacturer_EFilm2;
|
|
423 }
|
|
424 else
|
|
425 {
|
|
426 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
427 }
|
|
428 }
|
|
429
|
|
430
|
|
431 const char* EnumerationToString(TransferSyntax syntax)
|
|
432 {
|
|
433 switch (syntax)
|
|
434 {
|
|
435 case TransferSyntax_Deflated:
|
|
436 return "Deflated";
|
|
437
|
|
438 case TransferSyntax_Jpeg:
|
|
439 return "JPEG";
|
|
440
|
|
441 case TransferSyntax_Jpeg2000:
|
|
442 return "JPEG2000";
|
|
443
|
|
444 case TransferSyntax_JpegLossless:
|
|
445 return "JPEG Lossless";
|
|
446
|
|
447 case TransferSyntax_Jpip:
|
|
448 return "JPIP";
|
|
449
|
|
450 case TransferSyntax_Mpeg2:
|
|
451 return "MPEG2";
|
|
452
|
|
453 case TransferSyntax_Rle:
|
|
454 return "RLE";
|
|
455
|
|
456 default:
|
|
457 throw OrthancException(ErrorCode_ParameterOutOfRange);
|
|
458 }
|
|
459 }
|
|
460
|
|
461
|
|
462 bool IsUserMetadata(MetadataType metadata)
|
|
463 {
|
|
464 return (metadata >= MetadataType_StartUser &&
|
|
465 metadata <= MetadataType_EndUser);
|
|
466 }
|
|
467 }
|