[med-svn] [orthanc] 01/04: New upstream version 1.2.0+dfsg
Sebastien Jodogne
jodogne-guest at moszumanska.debian.org
Tue Dec 13 20:17:27 UTC 2016
This is an automated email from the git hooks/post-receive script.
jodogne-guest pushed a commit to branch master
in repository orthanc.
commit 2fdcb0555749510d6304a512a31fb0192ded2e59
Author: jodogne-guest <s.jodogne at gmail.com>
Date: Tue Dec 13 20:39:39 2016 +0100
New upstream version 1.2.0+dfsg
---
.hg_archival.txt | 6 +-
CMakeLists.txt | 41 +-
Core/Cache/SharedArchive.cpp | 5 +-
Core/DicomFormat/DicomArray.h | 2 +-
Core/DicomFormat/DicomImageInformation.h | 2 +-
Core/DicomFormat/DicomMap.h | 2 +-
Core/DicomFormat/DicomTag.h | 2 +
Core/DicomFormat/DicomValue.cpp | 2 +-
Core/DicomFormat/DicomValue.h | 7 +-
Core/Enumerations.cpp | 20 +-
Core/Enumerations.h | 8 +-
Core/FileStorage/FilesystemStorage.cpp | 66 +-
Core/FileStorage/FilesystemStorage.h | 2 +-
Core/FileStorage/StorageAccessor.cpp | 4 +-
Core/HttpClient.cpp | 84 +-
Core/HttpClient.h | 24 +
Core/HttpServer/FilesystemHttpHandler.cpp | 5 +-
Core/HttpServer/FilesystemHttpSender.h | 4 +-
Core/HttpServer/HttpOutput.cpp | 3 +-
Core/HttpServer/HttpOutput.h | 9 +-
Core/HttpServer/HttpStreamTranscoder.h | 1 +
Core/HttpServer/IHttpHandler.h | 2 +-
Core/HttpServer/MongooseServer.cpp | 153 +-
Core/Images/Font.cpp | 3 +-
Core/{Pkcs11.h => Images/IImageWriter.cpp} | 30 +-
Core/Images/IImageWriter.h | 16 +-
.../Semaphore.cpp => Images/Image.cpp} | 38 +-
Core/Images/Image.h | 10 +-
Core/Images/ImageAccessor.cpp | 18 +
Core/Images/ImageAccessor.h | 2 +
Core/Images/ImageBuffer.cpp | 14 +-
Core/Images/ImageBuffer.h | 5 +-
Core/Images/ImageProcessing.cpp | 76 +
Core/Images/ImageProcessing.h | 6 +
Core/Images/JpegReader.cpp | 14 +-
Core/Images/JpegReader.h | 6 +
Core/Images/JpegWriter.cpp | 11 +-
Core/Images/JpegWriter.h | 2 +
Core/Images/PngReader.cpp | 11 +-
Core/Images/PngReader.h | 6 +
Core/Images/PngWriter.cpp | 9 +-
Core/Images/PngWriter.h | 2 +
Core/Logging.cpp | 197 +-
Core/Logging.h | 16 +
Core/Lua/LuaContext.cpp | 4 +
Core/Lua/LuaFunctionCall.cpp | 22 +
Core/Lua/LuaFunctionCall.h | 7 +
Core/MultiThreading/BagOfTasksProcessor.cpp | 41 +-
Core/MultiThreading/BagOfTasksProcessor.h | 13 +-
Core/MultiThreading/ReaderWriterLock.cpp | 5 +-
Core/MultiThreading/RunnableWorkersPool.cpp | 26 +-
Core/MultiThreading/RunnableWorkersPool.h | 2 +-
Core/MultiThreading/Semaphore.cpp | 4 -
Core/MultiThreading/Semaphore.h | 18 +
Core/MultiThreading/SharedMessageQueue.cpp | 20 +
Core/MultiThreading/SharedMessageQueue.h | 2 +
Core/OrthancException.h | 2 +-
Core/Pkcs11.cpp | 12 +-
Core/Pkcs11.h | 18 +-
Core/PrecompiledHeaders.h | 3 +-
Core/RestApi/RestApi.cpp | 2 +-
Core/RestApi/RestApiOutput.cpp | 7 +-
Core/SystemToolbox.cpp | 539 ++++
Core/{OrthancException.h => SystemToolbox.h} | 98 +-
Core/{Uuid.h => TemporaryFile.cpp} | 82 +-
Core/{Images/JpegReader.h => TemporaryFile.h} | 31 +-
Core/Toolbox.cpp | 641 ++---
Core/Toolbox.h | 105 +-
Core/Uuid.cpp | 162 --
Core/WebServiceParameters.cpp | 12 +-
Core/WebServiceParameters.h | 6 +
DarwinCompilation.txt | 6 +-
INSTALL | 15 +-
LinuxCompilation.txt | 43 +-
NEWS | 72 +-
OrthancExplorer/explorer.html | 34 +-
OrthancExplorer/explorer.js | 82 +-
OrthancExplorer/file-upload.js | 5 +
OrthancExplorer/query-retrieve.js | 616 ++--
OrthancServer/DatabaseWrapper.cpp | 9 +-
OrthancServer/DicomDirWriter.cpp | 8 +-
OrthancServer/DicomInstanceToStore.cpp | 36 +-
OrthancServer/DicomInstanceToStore.h | 2 +
OrthancServer/DicomModification.cpp | 38 +-
OrthancServer/DicomModification.h | 2 +
OrthancServer/DicomProtocol/DicomFindAnswers.cpp | 117 +-
OrthancServer/DicomProtocol/DicomFindAnswers.h | 28 +-
OrthancServer/DicomProtocol/DicomServer.cpp | 14 +-
OrthancServer/DicomProtocol/DicomServer.h | 6 +-
.../DicomProtocol/DicomUserConnection.cpp | 115 +-
OrthancServer/DicomProtocol/DicomUserConnection.h | 21 +
OrthancServer/DicomProtocol/IMoveRequestHandler.h | 8 +-
OrthancServer/FromDcmtkBridge.cpp | 395 ++-
OrthancServer/FromDcmtkBridge.h | 95 +-
OrthancServer/Internals/CommandDispatcher.cpp | 41 +-
OrthancServer/Internals/CommandDispatcher.h | 19 +-
OrthancServer/Internals/DicomFrameIndex.cpp | 3 +-
OrthancServer/Internals/DicomImageDecoder.cpp | 20 +-
OrthancServer/Internals/DicomImageDecoder.h | 9 +
OrthancServer/Internals/FindScp.cpp | 72 +-
OrthancServer/Internals/MoveScp.cpp | 46 +-
OrthancServer/Internals/StoreScp.cpp | 13 +-
OrthancServer/LuaScripting.cpp | 5 +-
OrthancServer/OrthancFindRequestHandler.cpp | 124 +-
OrthancServer/OrthancInitialization.cpp | 107 +-
OrthancServer/OrthancInitialization.h | 23 +
OrthancServer/OrthancMoveRequestHandler.cpp | 55 +-
OrthancServer/OrthancMoveRequestHandler.h | 6 +-
.../OrthancRestApi/OrthancRestAnonymizeModify.cpp | 15 +-
.../OrthancRestApi/OrthancRestArchive.cpp | 10 +-
.../OrthancRestApi/OrthancRestModalities.cpp | 120 +-
.../OrthancRestApi/OrthancRestResources.cpp | 127 +-
OrthancServer/OrthancRestApi/OrthancRestSystem.cpp | 33 +-
OrthancServer/ParsedDicomFile.cpp | 114 +-
OrthancServer/ParsedDicomFile.h | 33 +-
OrthancServer/QueryRetrieveHandler.cpp | 54 +-
OrthancServer/Scheduler/CallSystemCommand.cpp | 8 +-
OrthancServer/Scheduler/ServerJob.cpp | 4 +-
OrthancServer/Scheduler/ServerScheduler.cpp | 7 +-
OrthancServer/Scheduler/ServerScheduler.h | 2 +-
OrthancServer/Scheduler/StorePeerCommand.cpp | 2 +-
OrthancServer/Scheduler/StoreScuCommand.cpp | 18 +-
OrthancServer/Scheduler/StoreScuCommand.h | 8 +-
OrthancServer/Search/HierarchicalMatcher.cpp | 4 +-
OrthancServer/Search/LookupIdentifierQuery.cpp | 134 +-
OrthancServer/Search/LookupIdentifierQuery.h | 20 +-
OrthancServer/Search/LookupResource.cpp | 10 +-
OrthancServer/ServerContext.cpp | 104 +-
OrthancServer/ServerContext.h | 32 +-
OrthancServer/ServerEnumerations.cpp | 2 +
OrthancServer/ServerEnumerations.h | 4 +-
OrthancServer/ServerIndex.cpp | 149 +-
OrthancServer/ServerIndex.h | 8 +
OrthancServer/ServerIndexChange.h | 4 +-
OrthancServer/ServerToolbox.cpp | 190 +-
OrthancServer/ServerToolbox.h | 25 +-
OrthancServer/ToDcmtkBridge.cpp | 18 -
OrthancServer/ToDcmtkBridge.h | 2 -
OrthancServer/main.cpp | 75 +-
Plugins/Engine/IPluginServiceProvider.h | 2 +-
Plugins/Engine/OrthancPluginDatabase.cpp | 2 +-
Plugins/Engine/OrthancPluginDatabase.h | 2 +-
Plugins/Engine/OrthancPlugins.cpp | 101 +-
Plugins/Engine/OrthancPlugins.h | 7 +-
Plugins/Engine/PluginsEnumerations.cpp | 2 +-
Plugins/Engine/PluginsEnumerations.h | 2 +-
Plugins/Engine/PluginsErrorDictionary.cpp | 2 +-
Plugins/Engine/PluginsErrorDictionary.h | 2 +-
Plugins/Engine/PluginsManager.cpp | 2 +-
Plugins/Engine/PluginsManager.h | 2 +-
Plugins/Engine/SharedLibrary.cpp | 2 +-
Plugins/Engine/SharedLibrary.h | 4 +-
Plugins/Include/orthanc/OrthancCPlugin.h | 207 +-
Plugins/Samples/Basic/Plugin.c | 44 +-
Plugins/Samples/Common/DicomDatasetReader.cpp | 122 +
.../Samples/Common/DicomDatasetReader.h | 30 +-
.../Samples/Common/DicomPath.cpp | 77 +-
.../Samples/Common/DicomPath.h | 94 +-
.../Samples/Common/DicomTag.cpp | 115 +-
Plugins/Samples/Common/DicomTag.h | 95 +
Plugins/Samples/Common/FullOrthancDataset.cpp | 196 ++
.../Samples/Common/FullOrthancDataset.h | 36 +-
.../Samples/Common/IDicomDataset.h | 24 +-
.../Samples/Common/IOrthancConnection.cpp | 78 +-
.../Common/IOrthancConnection.h} | 72 +-
.../Samples/Common/OrthancHttpConnection.cpp | 107 +-
.../Common/OrthancHttpConnection.h} | 53 +-
.../Samples/Common/OrthancPluginConnection.cpp | 105 +-
.../Common/OrthancPluginConnection.h} | 50 +-
Plugins/Samples/Common/OrthancPluginCppWrapper.cpp | 383 ++-
Plugins/Samples/Common/OrthancPluginCppWrapper.h | 226 +-
Plugins/Samples/Common/OrthancPlugins.cmake | 5 +-
.../Samples/Common/SimplifiedOrthancDataset.cpp | 156 +
.../Samples/Common/SimplifiedOrthancDataset.h | 36 +-
Plugins/Samples/DatabasePlugin/CMakeLists.txt | 7 +-
Plugins/Samples/ModalityWorklists/CMakeLists.txt | 1 +
Plugins/Samples/ModalityWorklists/Plugin.cpp | 256 +-
Plugins/Samples/ModalityWorklists/README | 57 +-
Plugins/Samples/ServeFolders/CMakeLists.txt | 3 +
Plugins/Samples/ServeFolders/Plugin.cpp | 412 +--
Plugins/Samples/ServeFolders/README | 53 +-
README | 10 +-
Resources/CMake/BoostConfiguration.cmake | 46 +-
Resources/CMake/Compiler.cmake | 29 +-
Resources/CMake/DcmtkConfiguration.cmake | 44 +-
Resources/CMake/DownloadPackage.cmake | 22 +-
Resources/CMake/GoogleTestConfiguration.cmake | 29 +-
Resources/CMake/JsonCppConfiguration.cmake | 2 +-
Resources/CMake/LibCurlConfiguration.cmake | 27 +-
Resources/CMake/LibIconvConfiguration.cmake | 4 +-
Resources/CMake/LibJpegConfiguration.cmake | 4 +-
Resources/CMake/LibP11Configuration.cmake | 4 +-
Resources/CMake/LibPngConfiguration.cmake | 4 +-
Resources/CMake/LuaConfiguration.cmake | 2 +-
Resources/CMake/MongooseConfiguration.cmake | 4 +-
Resources/CMake/OpenSslConfiguration.cmake | 7 +-
Resources/CMake/PugixmlConfiguration.cmake | 8 +-
Resources/CMake/SQLiteConfiguration.cmake | 2 +-
Resources/CMake/ZlibConfiguration.cmake | 6 +-
Resources/Configuration.json | 47 +-
Resources/DicomConformanceStatement.txt | 2 +-
Resources/EmbedResources.py | 4 +
Resources/ErrorCodes.json | 7 +-
Resources/Orthanc.doxygen | 2354 +++++++++------
Resources/OrthancPlugin.doxygen | 2359 +++++++++------
.../dcmtk-3.6.0-dulparse-vulnerability.patch | 29 +
Resources/Patches/dcmtk-3.6.1-private.dic | 3040 ++++++++++++++++++++
Resources/Patches/dcmtk.txt | 9 +
.../Samples/Python/ArchiveStudiesInTimeRange.py | 16 +-
Resources/Samples/Python/AutoClassify.py | 14 +-
Resources/Samples/Python/DownloadAnonymized.py | 5 +-
Resources/Samples/Tools/CMakeLists.txt | 10 +-
Resources/Samples/Tools/RecoverCompressedFile.cpp | 6 +-
.../Samples/WebApplications/DrawingDicomizer.js | 4 +-
Resources/ThirdParty/VisualStudio/stdint.h | 506 ++--
Resources/ThirdParty/base64/base64.cpp | 256 +-
Resources/ThirdParty/base64/base64.h | 8 +-
THANKS | 65 -
TODO | 152 +
UnitTestsSources/DicomMapTests.cpp | 3 +-
UnitTestsSources/FileStorageTests.cpp | 13 +-
UnitTestsSources/FromDcmtkTests.cpp | 361 ++-
UnitTestsSources/ImageTests.cpp | 20 +-
UnitTestsSources/JpegLosslessTests.cpp | 2 +-
UnitTestsSources/LuaTests.cpp | 4 +-
UnitTestsSources/MultiThreadingTests.cpp | 9 +-
UnitTestsSources/PluginsTests.cpp | 2 +-
UnitTestsSources/RestApiTests.cpp | 15 +-
UnitTestsSources/SQLiteTests.cpp | 4 +-
UnitTestsSources/ServerIndexTests.cpp | 23 +-
UnitTestsSources/StreamTests.cpp | 15 +-
UnitTestsSources/UnitTestsMain.cpp | 65 +-
UnitTestsSources/VersionsTests.cpp | 8 +-
233 files changed, 13358 insertions(+), 6041 deletions(-)
diff --git a/.hg_archival.txt b/.hg_archival.txt
index fa815d1..68a52ba 100644
--- a/.hg_archival.txt
+++ b/.hg_archival.txt
@@ -1,5 +1,5 @@
repo: 3959d33612ccaadc0d4d707227fbed09ac35e5fe
-node: 8fdeb348f72be7848a1b227a77a7a6adc7153286
-branch: Orthanc-1.1.0
+node: 2bdc29af95895479178be61a219977e861c90645
+branch: Orthanc-1.2.0
latesttag: null
-latesttagdistance: 1779
+latesttagdistance: 1946
diff --git a/CMakeLists.txt b/CMakeLists.txt
index a0a3fe3..5b75105 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 2.8)
project(Orthanc)
# Version of the build, should always be "mainline" except in release branches
-set(ORTHANC_VERSION "1.1.0")
+set(ORTHANC_VERSION "1.2.0")
# Version of the database schema. History:
# * Orthanc 0.1.0 -> Orthanc 0.3.0 = no versioning
@@ -32,8 +32,8 @@ SET(ENABLE_PLUGINS ON CACHE BOOL "Enable plugins")
SET(BUILD_SERVE_FOLDERS ON CACHE BOOL "Whether to build the ServeFolders plugin")
SET(BUILD_MODALITY_WORKLISTS ON CACHE BOOL "Whether to build the sample plugin to serve modality worklists")
SET(BUILD_RECOVER_COMPRESSED_FILE ON CACHE BOOL "Whether to build the companion tool to recover files compressed using Orthanc")
-SET(USE_DCMTK_361 OFF CACHE BOOL "Use forthcoming DCMTK version 3.6.1 in static builds (instead of 3.6.0)")
SET(ENABLE_PKCS11 OFF CACHE BOOL "Enable PKCS#11 for HTTPS client authentication using hardware security modules and smart cards")
+SET(ENABLE_PROFILING OFF CACHE BOOL "Whether to enable the generation of profiling information with gprof")
# Advanced parameters to fine-tune linking against system libraries
SET(USE_SYSTEM_JSONCPP ON CACHE BOOL "Use the system version of JsonCpp")
@@ -51,8 +51,10 @@ SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib")
SET(USE_SYSTEM_PUGIXML ON CACHE BOOL "Use the system version of Pugixml")
SET(USE_SYSTEM_LIBP11 OFF CACHE BOOL "Use the system version of libp11 (PKCS#11 wrapper library)")
-# Experimental options
+# Advanced parameters
SET(USE_PUGIXML ON CACHE BOOL "Use the Pugixml parser (turn off only for debug)")
+SET(USE_DCMTK_361 OFF CACHE BOOL "Use forthcoming DCMTK version 3.6.1 in static builds (instead of 3.6.0)")
+SET(USE_DCMTK_361_PRIVATE_DIC ON CACHE BOOL "Use the dictionary of private tags from DCMTK 3.6.1 in static builds (which is more up-to-date)")
# Distribution-specific settings
SET(USE_GTEST_DEBIAN_SOURCE_PACKAGE OFF CACHE BOOL "Use the sources of Google Test shipped with libgtest-dev (Debian only)")
@@ -130,6 +132,8 @@ set(ORTHANC_CORE_SOURCES
Core/MultiThreading/SharedMessageQueue.cpp
Core/Images/Font.cpp
Core/Images/FontRegistry.cpp
+ Core/Images/IImageWriter.cpp
+ Core/Images/Image.cpp
Core/Images/ImageAccessor.cpp
Core/Images/ImageBuffer.cpp
Core/Images/ImageProcessing.cpp
@@ -144,8 +148,9 @@ set(ORTHANC_CORE_SOURCES
Core/SQLite/StatementId.cpp
Core/SQLite/StatementReference.cpp
Core/SQLite/Transaction.cpp
+ Core/SystemToolbox.cpp
+ Core/TemporaryFile.cpp
Core/Toolbox.cpp
- Core/Uuid.cpp
Core/WebServiceParameters.cpp
Core/Lua/LuaContext.cpp
Core/Lua/LuaFunctionCall.cpp
@@ -306,31 +311,31 @@ include(${CMAKE_SOURCE_DIR}/Resources/CMake/DcmtkConfiguration.cmake)
if (ENABLE_SSL)
- add_definitions(-DORTHANC_SSL_ENABLED=1)
+ add_definitions(-DORTHANC_ENABLE_SSL=1)
include(${CMAKE_SOURCE_DIR}/Resources/CMake/OpenSslConfiguration.cmake)
else()
- add_definitions(-DORTHANC_SSL_ENABLED=0)
+ add_definitions(-DORTHANC_ENABLE_SSL=0)
endif()
if (ENABLE_JPEG)
- add_definitions(-DORTHANC_JPEG_ENABLED=1)
+ add_definitions(-DORTHANC_ENABLE_JPEG=1)
else()
- add_definitions(-DORTHANC_JPEG_ENABLED=0)
+ add_definitions(-DORTHANC_ENABLE_JPEG=0)
endif()
if (ENABLE_JPEG_LOSSLESS)
- add_definitions(-DORTHANC_JPEG_LOSSLESS_ENABLED=1)
+ add_definitions(-DORTHANC_ENABLE_JPEG_LOSSLESS=1)
else()
- add_definitions(-DORTHANC_JPEG_LOSSLESS_ENABLED=0)
+ add_definitions(-DORTHANC_ENABLE_JPEG_LOSSLESS=0)
endif()
if (ENABLE_PLUGINS)
- add_definitions(-DORTHANC_PLUGINS_ENABLED=1)
+ add_definitions(-DORTHANC_ENABLE_PLUGINS=1)
else()
- add_definitions(-DORTHANC_PLUGINS_ENABLED=0)
+ add_definitions(-DORTHANC_ENABLE_PLUGINS=0)
endif()
@@ -338,13 +343,13 @@ if (ENABLE_PKCS11)
if (ENABLE_SSL)
include(${CMAKE_SOURCE_DIR}/Resources/CMake/LibP11Configuration.cmake)
- add_definitions(-DORTHANC_PKCS11_ENABLED=1)
+ add_definitions(-DORTHANC_ENABLE_PKCS11=1)
list(APPEND ORTHANC_CORE_SOURCES Core/Pkcs11.cpp)
else()
message(FATAL_ERROR "OpenSSL is required to enable PKCS#11")
endif()
else()
- add_definitions(-DORTHANC_PKCS11_ENABLED=0)
+ add_definitions(-DORTHANC_ENABLE_PKCS11=0)
endif()
@@ -404,11 +409,15 @@ include_directories(${CMAKE_SOURCE_DIR}/Plugins/Include)
add_definitions(
-DORTHANC_VERSION="${ORTHANC_VERSION}"
-DORTHANC_DATABASE_VERSION=${ORTHANC_DATABASE_VERSION}
+ -DORTHANC_BUILD_UNIT_TESTS=1
+ -DORTHANC_ENABLE_BASE64=1
-DORTHANC_ENABLE_LOGGING=1
+ -DORTHANC_ENABLE_MD5=1
-DORTHANC_MAXIMUM_TAG_LENGTH=256
- -DORTHANC_BUILD_UNIT_TESTS=1
+ -DORTHANC_SANDBOXED=0
# Macros for the plugins
+ -DHAS_ORTHANC_EXCEPTION=0
-DMODALITY_WORKLISTS_VERSION="${ORTHANC_VERSION}"
-DSERVE_FOLDERS_VERSION="${ORTHANC_VERSION}"
)
@@ -546,6 +555,7 @@ if (ENABLE_PLUGINS AND BUILD_SERVE_FOLDERS)
${BOOST_SOURCES}
${JSONCPP_SOURCES}
Plugins/Samples/ServeFolders/Plugin.cpp
+ Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
${SERVE_FOLDERS_RESOURCES}
)
@@ -588,6 +598,7 @@ if (ENABLE_PLUGINS AND BUILD_MODALITY_WORKLISTS)
add_library(ModalityWorklists SHARED
${BOOST_SOURCES}
${JSONCPP_SOURCES}
+ Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
Plugins/Samples/ModalityWorklists/Plugin.cpp
${MODALITY_WORKLISTS_RESOURCES}
)
diff --git a/Core/Cache/SharedArchive.cpp b/Core/Cache/SharedArchive.cpp
index 93303e8..b3cafb5 100644
--- a/Core/Cache/SharedArchive.cpp
+++ b/Core/Cache/SharedArchive.cpp
@@ -33,8 +33,7 @@
#include "../PrecompiledHeaders.h"
#include "SharedArchive.h"
-
-#include "../Uuid.h"
+#include "../SystemToolbox.h"
namespace Orthanc
@@ -100,7 +99,7 @@ namespace Orthanc
RemoveInternal(oldest);
}
- std::string id = Toolbox::GenerateUuid();
+ std::string id = SystemToolbox::GenerateUuid();
RemoveInternal(id); // Should never be useful because of UUID
archive_[id] = obj;
lru_.Add(id);
diff --git a/Core/DicomFormat/DicomArray.h b/Core/DicomFormat/DicomArray.h
index a223685..97a7d9c 100644
--- a/Core/DicomFormat/DicomArray.h
+++ b/Core/DicomFormat/DicomArray.h
@@ -47,7 +47,7 @@ namespace Orthanc
Elements elements_;
public:
- DicomArray(const DicomMap& map);
+ explicit DicomArray(const DicomMap& map);
~DicomArray();
diff --git a/Core/DicomFormat/DicomImageInformation.h b/Core/DicomFormat/DicomImageInformation.h
index 568e6e3..e27db09 100644
--- a/Core/DicomFormat/DicomImageInformation.h
+++ b/Core/DicomFormat/DicomImageInformation.h
@@ -57,7 +57,7 @@ namespace Orthanc
PhotometricInterpretation photometric_;
public:
- DicomImageInformation(const DicomMap& values);
+ explicit DicomImageInformation(const DicomMap& values);
unsigned int GetWidth() const
{
diff --git a/Core/DicomFormat/DicomMap.h b/Core/DicomFormat/DicomMap.h
index 58e50b8..160363f 100644
--- a/Core/DicomFormat/DicomMap.h
+++ b/Core/DicomFormat/DicomMap.h
@@ -47,7 +47,7 @@ namespace Orthanc
private:
friend class DicomArray;
friend class FromDcmtkBridge;
- friend class ToDcmtkBridge;
+ friend class ParsedDicomFile;
typedef std::map<DicomTag, DicomValue*> Map;
diff --git a/Core/DicomFormat/DicomTag.h b/Core/DicomFormat/DicomTag.h
index 25f4259..bf971ca 100644
--- a/Core/DicomFormat/DicomTag.h
+++ b/Core/DicomFormat/DicomTag.h
@@ -100,6 +100,7 @@ namespace Orthanc
static const DicomTag DICOM_TAG_SERIES_INSTANCE_UID(0x0020, 0x000e);
static const DicomTag DICOM_TAG_STUDY_INSTANCE_UID(0x0020, 0x000d);
static const DicomTag DICOM_TAG_PIXEL_DATA(0x7fe0, 0x0010);
+ static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010);
static const DicomTag DICOM_TAG_IMAGE_INDEX(0x0054, 0x1330);
static const DicomTag DICOM_TAG_INSTANCE_NUMBER(0x0020, 0x0013);
@@ -127,6 +128,7 @@ namespace Orthanc
static const DicomTag DICOM_TAG_TEMPORAL_POSITION_IDENTIFIER(0x0020, 0x0100);
// Tags for C-FIND and C-MOVE
+ static const DicomTag DICOM_TAG_MESSAGE_ID(0x0000, 0x0110);
static const DicomTag DICOM_TAG_SPECIFIC_CHARACTER_SET(0x0008, 0x0005);
static const DicomTag DICOM_TAG_QUERY_RETRIEVE_LEVEL(0x0008, 0x0052);
static const DicomTag DICOM_TAG_MODALITIES_IN_STUDY(0x0008, 0x0061);
diff --git a/Core/DicomFormat/DicomValue.cpp b/Core/DicomFormat/DicomValue.cpp
index 32a17b5..2a4c2f2 100644
--- a/Core/DicomFormat/DicomValue.cpp
+++ b/Core/DicomFormat/DicomValue.cpp
@@ -81,7 +81,7 @@ namespace Orthanc
}
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
void DicomValue::FormatDataUriScheme(std::string& target,
const std::string& mime) const
{
diff --git a/Core/DicomFormat/DicomValue.h b/Core/DicomFormat/DicomValue.h
index ad0ec54..c4844b7 100644
--- a/Core/DicomFormat/DicomValue.h
+++ b/Core/DicomFormat/DicomValue.h
@@ -35,6 +35,11 @@
#include <string>
#include <boost/noncopyable.hpp>
+#if !defined(ORTHANC_ENABLE_BASE64)
+# error The macro ORTHANC_ENABLE_BASE64 must be defined
+#endif
+
+
namespace Orthanc
{
class DicomValue : public boost::noncopyable
@@ -78,7 +83,7 @@ namespace Orthanc
DicomValue* Clone() const;
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
void FormatDataUriScheme(std::string& target,
const std::string& mime) const;
diff --git a/Core/Enumerations.cpp b/Core/Enumerations.cpp
index e600828..19057b4 100644
--- a/Core/Enumerations.cpp
+++ b/Core/Enumerations.cpp
@@ -64,7 +64,7 @@ namespace Orthanc
return "Parameter out of range";
case ErrorCode_NotEnoughMemory:
- return "Not enough memory";
+ return "The server hosting Orthanc is running out of memory";
case ErrorCode_BadParameterType:
return "Bad type for a parameter";
@@ -156,6 +156,9 @@ namespace Orthanc
case ErrorCode_NotAcceptable:
return "Cannot send a response which is acceptable according to the Accept HTTP header";
+ case ErrorCode_NullPointer:
+ return "Cannot handle a NULL pointer";
+
case ErrorCode_SQLiteNotOpened:
return "SQLite: The database is not opened";
@@ -733,6 +736,9 @@ namespace Orthanc
case PixelFormat_RGBA32:
return "RGBA32";
+ case PixelFormat_BGRA32:
+ return "BGRA32";
+
case PixelFormat_Grayscale8:
return "Grayscale (unsigned 8bpp)";
@@ -1061,6 +1067,7 @@ namespace Orthanc
return 3;
case PixelFormat_RGBA32:
+ case PixelFormat_BGRA32:
return 4;
case PixelFormat_Float32:
@@ -1076,15 +1083,18 @@ namespace Orthanc
bool GetDicomEncoding(Encoding& encoding,
const char* specificCharacterSet)
{
- std::string s = specificCharacterSet;
+ std::string s = Toolbox::StripSpaces(specificCharacterSet);
Toolbox::ToUpperCase(s);
// http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2
// https://github.com/dcm4che/dcm4che/blob/master/dcm4che-core/src/main/java/org/dcm4che3/data/SpecificCharacterSet.java
if (s == "ISO_IR 6" ||
- s == "ISO_IR 192" ||
s == "ISO 2022 IR 6")
{
+ encoding = Encoding_Ascii;
+ }
+ else if (s == "ISO_IR 192")
+ {
encoding = Encoding_Utf8;
}
else if (s == "ISO_IR 100" ||
@@ -1231,8 +1241,10 @@ namespace Orthanc
// http://dicom.nema.org/medical/dicom/current/output/html/part03.html#sect_C.12.1.1.2
switch (encoding)
{
- case Encoding_Utf8:
case Encoding_Ascii:
+ return "ISO_IR 6";
+
+ case Encoding_Utf8:
return "ISO_IR 192";
case Encoding_Latin1:
diff --git a/Core/Enumerations.h b/Core/Enumerations.h
index 7eef119..9b18661 100644
--- a/Core/Enumerations.h
+++ b/Core/Enumerations.h
@@ -52,7 +52,7 @@ namespace Orthanc
ErrorCode_Plugin = 1 /*!< Error encountered within the plugin engine */,
ErrorCode_NotImplemented = 2 /*!< Not implemented yet */,
ErrorCode_ParameterOutOfRange = 3 /*!< Parameter out of range */,
- ErrorCode_NotEnoughMemory = 4 /*!< Not enough memory */,
+ ErrorCode_NotEnoughMemory = 4 /*!< The server hosting Orthanc is running out of memory */,
ErrorCode_BadParameterType = 5 /*!< Bad type for a parameter */,
ErrorCode_BadSequenceOfCalls = 6 /*!< Bad sequence of calls */,
ErrorCode_InexistentItem = 7 /*!< Accessing an inexistent item */,
@@ -83,6 +83,7 @@ namespace Orthanc
ErrorCode_StorageAreaPlugin = 32 /*!< Error in the plugin implementing a custom storage area */,
ErrorCode_EmptyRequest = 33 /*!< The request is empty */,
ErrorCode_NotAcceptable = 34 /*!< Cannot send a response which is acceptable according to the Accept HTTP header */,
+ ErrorCode_NullPointer = 35 /*!< Cannot handle a NULL pointer */,
ErrorCode_SQLiteNotOpened = 1000 /*!< SQLite: The database is not opened */,
ErrorCode_SQLiteAlreadyOpened = 1001 /*!< SQLite: Connection is already open */,
ErrorCode_SQLiteCannotOpen = 1002 /*!< SQLite: Unable to open the database */,
@@ -195,7 +196,10 @@ namespace Orthanc
* {summary}{Graylevel, floating-point image.}
* {description}{The image is graylevel. Each pixel is floating-point and stored in 4 bytes.}
**/
- PixelFormat_Float32 = 6
+ PixelFormat_Float32 = 6,
+
+ // This is the memory layout for Cairo
+ PixelFormat_BGRA32 = 7
};
diff --git a/Core/FileStorage/FilesystemStorage.cpp b/Core/FileStorage/FilesystemStorage.cpp
index e282065..668ab20 100644
--- a/Core/FileStorage/FilesystemStorage.cpp
+++ b/Core/FileStorage/FilesystemStorage.cpp
@@ -39,7 +39,7 @@
#include "../Logging.h"
#include "../OrthancException.h"
#include "../Toolbox.h"
-#include "../Uuid.h"
+#include "../SystemToolbox.h"
#include <boost/filesystem/fstream.hpp>
@@ -83,14 +83,40 @@ namespace Orthanc
//root_ = boost::filesystem::absolute(root).string();
root_ = root;
- Toolbox::MakeDirectory(root);
+ SystemToolbox::MakeDirectory(root);
}
+
+
+ static const char* GetDescriptionInternal(FileContentType content)
+ {
+ // This function is for logging only (internal use), a more
+ // fully-featured version is available in ServerEnumerations.cpp
+ switch (content)
+ {
+ case FileContentType_Unknown:
+ return "Unknown";
+
+ case FileContentType_Dicom:
+ return "DICOM";
+
+ case FileContentType_DicomAsJson:
+ return "JSON summary of DICOM";
+
+ default:
+ return "User-defined";
+ }
+ }
+
+
void FilesystemStorage::Create(const std::string& uuid,
const void* content,
size_t size,
- FileContentType /*type*/)
+ FileContentType type)
{
+ LOG(INFO) << "Creating attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type)
+ << "\" type (size: " << (size / (1024 * 1024) + 1) << "MB)";
+
boost::filesystem::path path;
path = GetPath(uuid);
@@ -117,33 +143,19 @@ namespace Orthanc
}
}
- boost::filesystem::ofstream f;
- f.open(path, std::ofstream::out | std::ios::binary);
- if (!f.good())
- {
- throw OrthancException(ErrorCode_FileStorageCannotWrite);
- }
-
- if (size != 0)
- {
- f.write(static_cast<const char*>(content), size);
- if (!f.good())
- {
- f.close();
- throw OrthancException(ErrorCode_FileStorageCannotWrite);
- }
- }
-
- f.close();
+ SystemToolbox::WriteFile(content, size, path.string());
}
void FilesystemStorage::Read(std::string& content,
const std::string& uuid,
- FileContentType /*type*/)
+ FileContentType type)
{
+ LOG(INFO) << "Reading attachment \"" << uuid << "\" of \"" << GetDescriptionInternal(type)
+ << "\" content type";
+
content.clear();
- Toolbox::ReadFile(content, GetPath(uuid).string());
+ SystemToolbox::ReadFile(content, GetPath(uuid).string());
}
@@ -165,7 +177,7 @@ namespace Orthanc
{
for (fs::recursive_directory_iterator current(root_), end; current != end ; ++current)
{
- if (Toolbox::IsRegularFile(current->path().string()))
+ if (SystemToolbox::IsRegularFile(current->path().string()))
{
try
{
@@ -211,11 +223,9 @@ namespace Orthanc
void FilesystemStorage::Remove(const std::string& uuid,
- FileContentType /*type*/)
+ FileContentType type)
{
-#if ORTHANC_ENABLE_GOOGLE_LOG == 1
- LOG(INFO) << "Deleting file " << uuid;
-#endif
+ LOG(INFO) << "Deleting attachment \"" << uuid << "\" of type " << static_cast<int>(type);
namespace fs = boost::filesystem;
diff --git a/Core/FileStorage/FilesystemStorage.h b/Core/FileStorage/FilesystemStorage.h
index d003bc5..a7f52cf 100644
--- a/Core/FileStorage/FilesystemStorage.h
+++ b/Core/FileStorage/FilesystemStorage.h
@@ -52,7 +52,7 @@ namespace Orthanc
boost::filesystem::path GetPath(const std::string& uuid) const;
public:
- FilesystemStorage(std::string root);
+ explicit FilesystemStorage(std::string root);
virtual void Create(const std::string& uuid,
const void* content,
diff --git a/Core/FileStorage/StorageAccessor.cpp b/Core/FileStorage/StorageAccessor.cpp
index a202d60..d3342dd 100644
--- a/Core/FileStorage/StorageAccessor.cpp
+++ b/Core/FileStorage/StorageAccessor.cpp
@@ -36,6 +36,8 @@
#include "../Compression/ZlibCompressor.h"
#include "../OrthancException.h"
#include "../HttpServer/HttpStreamTranscoder.h"
+#include "../Toolbox.h"
+#include "../SystemToolbox.h"
namespace Orthanc
{
@@ -45,7 +47,7 @@ namespace Orthanc
CompressionType compression,
bool storeMd5)
{
- std::string uuid = Toolbox::GenerateUuid();
+ std::string uuid = SystemToolbox::GenerateUuid();
std::string md5;
diff --git a/Core/HttpClient.cpp b/Core/HttpClient.cpp
index 1c98f8e..70392ff 100644
--- a/Core/HttpClient.cpp
+++ b/Core/HttpClient.cpp
@@ -37,6 +37,7 @@
#include "OrthancException.h"
#include "Logging.h"
#include "ChunkedBuffer.h"
+#include "SystemToolbox.h"
#include <string.h>
#include <curl/curl.h>
@@ -44,7 +45,17 @@
#include <boost/thread/mutex.hpp>
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
+// For OpenSSL initialization and finalization
+# include <openssl/conf.h>
+# include <openssl/engine.h>
+# include <openssl/err.h>
+# include <openssl/evp.h>
+# include <openssl/ssl.h>
+#endif
+
+
+#if ORTHANC_ENABLE_PKCS11 == 1
# include "Pkcs11.h"
#endif
@@ -151,7 +162,7 @@ namespace Orthanc
return timeout_;
}
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
bool IsPkcs11Initialized()
{
boost::mutex::scoped_lock lock(mutex_);
@@ -307,10 +318,10 @@ namespace Orthanc
url_ = "";
method_ = HttpMethod_Get;
lastStatus_ = HttpStatus_200_Ok;
- isVerbose_ = false;
+ SetVerbose(false);
timeout_ = GlobalParameters::GetInstance().GetDefaultTimeout();
GlobalParameters::GetInstance().GetDefaultProxy(proxy_);
- GlobalParameters::GetInstance().GetSslConfiguration(verifyPeers_, caCertificates_);
+ GlobalParameters::GetInstance().GetSslConfiguration(verifyPeers_, caCertificates_);
}
@@ -318,7 +329,8 @@ namespace Orthanc
pimpl_(new PImpl),
verifyPeers_(true),
pkcs11Enabled_(false),
- headersToLowerCase_(true)
+ headersToLowerCase_(true),
+ redirectionFollowed_(true)
{
Setup();
}
@@ -328,7 +340,8 @@ namespace Orthanc
const std::string& uri) :
pimpl_(new PImpl),
verifyPeers_(true),
- headersToLowerCase_(true)
+ headersToLowerCase_(true),
+ redirectionFollowed_(true)
{
Setup();
@@ -423,7 +436,7 @@ namespace Orthanc
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_HEADERDATA, &headerParameters));
}
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
// Setup HTTPS-related options
if (verifyPeers_)
@@ -449,7 +462,7 @@ namespace Orthanc
if (pkcs11Enabled_)
{
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
if (GlobalParameters::GetInstance().IsPkcs11Initialized())
{
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLENGINE, Pkcs11::GetEngineIdentifier()));
@@ -468,7 +481,7 @@ namespace Orthanc
}
else if (!clientCertificateFile_.empty())
{
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERTTYPE, "PEM"));
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_SSLCERT, clientCertificateFile_.c_str()));
@@ -497,9 +510,18 @@ namespace Orthanc
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_NOBODY, 0L));
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_CUSTOMREQUEST, NULL));
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDS, NULL));
- CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0));
+ CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_POSTFIELDSIZE, 0L));
CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_PROXY, NULL));
+ if (redirectionFollowed_)
+ {
+ CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 1L));
+ }
+ else
+ {
+ CheckCode(curl_easy_setopt(pimpl_->curl_, CURLOPT_FOLLOWLOCATION, 0L));
+ }
+
// Set timeouts
if (timeout_ <= 0)
{
@@ -650,7 +672,7 @@ namespace Orthanc
void HttpClient::ConfigureSsl(bool httpsVerifyPeers,
const std::string& httpsVerifyCertificates)
{
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
if (httpsVerifyPeers)
{
if (httpsVerifyCertificates.empty())
@@ -675,13 +697,11 @@ namespace Orthanc
void HttpClient::GlobalInitialize()
{
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
CheckCode(curl_global_init(CURL_GLOBAL_ALL));
#else
CheckCode(curl_global_init(CURL_GLOBAL_ALL & ~CURL_GLOBAL_SSL));
#endif
-
- CheckCode(curl_global_init(CURL_GLOBAL_DEFAULT));
}
@@ -689,7 +709,7 @@ namespace Orthanc
{
curl_global_cleanup();
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
Pkcs11::Finalize();
#endif
}
@@ -754,14 +774,14 @@ namespace Orthanc
throw OrthancException(ErrorCode_ParameterOutOfRange);
}
- if (!Toolbox::IsRegularFile(certificateFile))
+ if (!SystemToolbox::IsRegularFile(certificateFile))
{
LOG(ERROR) << "Cannot open certificate file: " << certificateFile;
throw OrthancException(ErrorCode_InexistentFile);
}
if (!certificateKeyFile.empty() &&
- !Toolbox::IsRegularFile(certificateKeyFile))
+ !SystemToolbox::IsRegularFile(certificateKeyFile))
{
LOG(ERROR) << "Cannot open key file: " << certificateKeyFile;
throw OrthancException(ErrorCode_InexistentFile);
@@ -777,7 +797,7 @@ namespace Orthanc
const std::string& pin,
bool verbose)
{
-#if ORTHANC_PKCS11_ENABLED == 1
+#if ORTHANC_ENABLE_PKCS11 == 1
LOG(INFO) << "Initializing PKCS#11 using " << module
<< (pin.empty() ? " (no PIN provided)" : " (PIN is provided)");
GlobalParameters::GetInstance().InitializePkcs11(module, pin, verbose);
@@ -786,4 +806,32 @@ namespace Orthanc
throw OrthancException(ErrorCode_InternalError);
#endif
}
+
+
+ void HttpClient::InitializeOpenSsl()
+ {
+#if ORTHANC_ENABLE_SSL == 1
+ // https://wiki.openssl.org/index.php/Library_Initialization
+ SSL_library_init();
+ SSL_load_error_strings();
+ OpenSSL_add_all_algorithms();
+ ERR_load_crypto_strings();
+#endif
+ }
+
+
+ void HttpClient::FinalizeOpenSsl()
+ {
+ #if ORTHANC_ENABLE_SSL == 1
+ // Finalize OpenSSL
+ // https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
+ FIPS_mode_set(0);
+ ENGINE_cleanup();
+ CONF_modules_unload(1);
+ EVP_cleanup();
+ CRYPTO_cleanup_all_ex_data();
+ ERR_remove_state(0);
+ ERR_free_strings();
+#endif
+ }
}
diff --git a/Core/HttpClient.h b/Core/HttpClient.h
index 2576644..1b80f33 100644
--- a/Core/HttpClient.h
+++ b/Core/HttpClient.h
@@ -39,6 +39,15 @@
#include <boost/shared_ptr.hpp>
#include <json/json.h>
+#if !defined(ORTHANC_ENABLE_SSL)
+# error The macro ORTHANC_ENABLE_SSL must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_PKCS11)
+# error The macro ORTHANC_ENABLE_PKCS11 must be defined
+#endif
+
+
namespace Orthanc
{
class HttpClient
@@ -67,6 +76,7 @@ namespace Orthanc
std::string clientCertificateKeyPassword_;
bool pkcs11Enabled_;
bool headersToLowerCase_;
+ bool redirectionFollowed_;
void Setup();
@@ -243,10 +253,24 @@ namespace Orthanc
return headersToLowerCase_;
}
+ void SetRedirectionFollowed(bool follow)
+ {
+ redirectionFollowed_ = follow;
+ }
+
+ bool IsRedirectionFollowed() const
+ {
+ return redirectionFollowed_;
+ }
+
static void GlobalInitialize();
static void GlobalFinalize();
+ static void InitializeOpenSsl();
+
+ static void FinalizeOpenSsl();
+
static void InitializePkcs11(const std::string& module,
const std::string& pin,
bool verbose);
diff --git a/Core/HttpServer/FilesystemHttpHandler.cpp b/Core/HttpServer/FilesystemHttpHandler.cpp
index 84fe5cf..33909f3 100644
--- a/Core/HttpServer/FilesystemHttpHandler.cpp
+++ b/Core/HttpServer/FilesystemHttpHandler.cpp
@@ -34,6 +34,7 @@
#include "FilesystemHttpHandler.h"
#include "../OrthancException.h"
+#include "../SystemToolbox.h"
#include "FilesystemHttpSender.h"
#include <boost/filesystem.hpp>
@@ -95,7 +96,7 @@ namespace Orthanc
#endif
std::string h = Toolbox::FlattenUri(uri) + "/" + f;
- if (Toolbox::IsRegularFile(it->path().string()))
+ if (SystemToolbox::IsRegularFile(it->path().string()))
{
s += "<li><a href=\"" + h + "\">" + f + "</a></li>";
}
@@ -158,7 +159,7 @@ namespace Orthanc
p /= uri[i];
}
- if (Toolbox::IsRegularFile(p.string()))
+ if (SystemToolbox::IsRegularFile(p.string()))
{
FilesystemHttpSender sender(p);
output.Answer(sender); // TODO COMPRESSION
diff --git a/Core/HttpServer/FilesystemHttpSender.h b/Core/HttpServer/FilesystemHttpSender.h
index 367835f..8e09595 100644
--- a/Core/HttpServer/FilesystemHttpSender.h
+++ b/Core/HttpServer/FilesystemHttpSender.h
@@ -50,12 +50,12 @@ namespace Orthanc
void Initialize(const boost::filesystem::path& path);
public:
- FilesystemHttpSender(const std::string& path)
+ explicit FilesystemHttpSender(const std::string& path)
{
Initialize(path);
}
- FilesystemHttpSender(const boost::filesystem::path& path)
+ explicit FilesystemHttpSender(const boost::filesystem::path& path)
{
Initialize(path);
}
diff --git a/Core/HttpServer/HttpOutput.cpp b/Core/HttpServer/HttpOutput.cpp
index 7e6bc34..3e0862e 100644
--- a/Core/HttpServer/HttpOutput.cpp
+++ b/Core/HttpServer/HttpOutput.cpp
@@ -35,6 +35,7 @@
#include "../Logging.h"
#include "../OrthancException.h"
+#include "../SystemToolbox.h"
#include "../Toolbox.h"
#include "../Compression/GzipCompressor.h"
#include "../Compression/ZlibCompressor.h"
@@ -438,7 +439,7 @@ namespace Orthanc
header += *it;
}
- multipartBoundary_ = Toolbox::GenerateUuid();
+ multipartBoundary_ = SystemToolbox::GenerateUuid();
multipartContentType_ = contentType;
header += "Content-Type: multipart/" + subType + "; type=" + contentType + "; boundary=" + multipartBoundary_ + "\r\n\r\n";
diff --git a/Core/HttpServer/HttpOutput.h b/Core/HttpServer/HttpOutput.h
index ea0e889..ff08bf1 100644
--- a/Core/HttpServer/HttpOutput.h
+++ b/Core/HttpServer/HttpOutput.h
@@ -32,13 +32,14 @@
#pragma once
-#include <list>
-#include <string>
-#include <stdint.h>
#include "../Enumerations.h"
#include "IHttpOutputStream.h"
#include "IHttpStreamAnswer.h"
-#include "../Uuid.h"
+
+#include <list>
+#include <string>
+#include <stdint.h>
+#include <map>
namespace Orthanc
{
diff --git a/Core/HttpServer/HttpStreamTranscoder.h b/Core/HttpServer/HttpStreamTranscoder.h
index 6afe583..0647eda 100644
--- a/Core/HttpServer/HttpStreamTranscoder.h
+++ b/Core/HttpServer/HttpStreamTranscoder.h
@@ -61,6 +61,7 @@ namespace Orthanc
sourceCompression_(compression),
bytesToSkip_(0),
skipped_(0),
+ currentChunkOffset_(0),
ready_(false)
{
}
diff --git a/Core/HttpServer/IHttpHandler.h b/Core/HttpServer/IHttpHandler.h
index f99cbb5..0bc7f55 100644
--- a/Core/HttpServer/IHttpHandler.h
+++ b/Core/HttpServer/IHttpHandler.h
@@ -32,7 +32,7 @@
#pragma once
-#include "../Enumerations.h"
+#include "../Toolbox.h"
#include "HttpOutput.h"
#include <map>
diff --git a/Core/HttpServer/MongooseServer.cpp b/Core/HttpServer/MongooseServer.cpp
index 8270e76..01b7a55 100644
--- a/Core/HttpServer/MongooseServer.cpp
+++ b/Core/HttpServer/MongooseServer.cpp
@@ -49,7 +49,11 @@
#include <stdio.h>
#include <boost/thread.hpp>
-#if ORTHANC_SSL_ENABLED == 1
+#if !defined(ORTHANC_ENABLE_SSL)
+# error The macro ORTHANC_ENABLE_SSL must be defined
+#endif
+
+#if ORTHANC_ENABLE_SSL == 1
#include <openssl/opensslv.h>
#endif
@@ -575,16 +579,14 @@ namespace Orthanc
}
- static void InternalCallback(struct mg_connection *connection,
+ static void InternalCallback(HttpOutput& output /* out */,
+ HttpMethod& method /* out */,
+ MongooseServer& server,
+ struct mg_connection *connection,
const struct mg_request_info *request)
{
- MongooseServer* that = reinterpret_cast<MongooseServer*>(request->user_data);
-
- MongooseOutputStream stream(connection);
- HttpOutput output(stream, that->IsKeepAliveEnabled());
-
// Check remote calls
- if (!that->IsRemoteAccessAllowed() &&
+ if (!server.IsRemoteAccessAllowed() &&
request->remote_ip != LOCALHOST)
{
output.SendUnauthorized(ORTHANC_REALM);
@@ -604,7 +606,7 @@ namespace Orthanc
VLOG(1) << "HTTP header: [" << name << "]: [" << value << "]";
}
- if (that->IsHttpCompressionEnabled())
+ if (server.IsHttpCompressionEnabled())
{
ConfigureHttpCompression(output, headers);
}
@@ -619,7 +621,7 @@ namespace Orthanc
// Compute the HTTP method, taking method faking into consideration
- HttpMethod method = HttpMethod_Get;
+ method = HttpMethod_Get;
if (!ExtractMethod(method, request, headers, argumentsGET))
{
output.SendStatus(HttpStatus_400_BadRequest);
@@ -628,7 +630,8 @@ namespace Orthanc
// Authenticate this connection
- if (that->IsAuthenticationEnabled() && !IsAccessGranted(*that, headers))
+ if (server.IsAuthenticationEnabled() &&
+ !IsAccessGranted(server, headers))
{
output.SendUnauthorized(ORTHANC_REALM);
return;
@@ -645,7 +648,7 @@ namespace Orthanc
std::string username = GetAuthenticatedUsername(headers);
- const IIncomingHttpRequestFilter *filter = that->GetIncomingHttpRequestFilter();
+ const IIncomingHttpRequestFilter *filter = server.GetIncomingHttpRequestFilter();
if (filter != NULL)
{
if (!filter->IsAllowed(method, request->uri, remoteIp, username.c_str(), headers))
@@ -679,7 +682,7 @@ namespace Orthanc
if (contentType.size() >= multipartLength &&
!memcmp(contentType.c_str(), multipart, multipartLength))
{
- status = ParseMultipartPost(body, connection, headers, contentType, that->GetChunkStore());
+ status = ParseMultipartPost(body, connection, headers, contentType, server.GetChunkStore());
}
else
{
@@ -713,7 +716,7 @@ namespace Orthanc
{
Toolbox::SplitUriComponents(uri, request->uri);
}
- catch (OrthancException)
+ catch (OrthancException&)
{
output.SendStatus(HttpStatus_400_BadRequest);
return;
@@ -722,56 +725,100 @@ namespace Orthanc
LOG(INFO) << EnumerationToString(method) << " " << Toolbox::FlattenUri(uri);
+ bool found = false;
+
+ if (server.HasHandler())
+ {
+ found = server.GetHandler().Handle(output, RequestOrigin_RestApi, remoteIp, username.c_str(),
+ method, uri, headers, argumentsGET, body.c_str(), body.size());
+ }
+
+ if (!found)
+ {
+ throw OrthancException(ErrorCode_UnknownResource);
+ }
+ }
+
+ static void ProtectedCallback(struct mg_connection *connection,
+ const struct mg_request_info *request)
+ {
try
{
- bool found = false;
+ MongooseServer* server = reinterpret_cast<MongooseServer*>(request->user_data);
+
+ if (server == NULL)
+ {
+ MongooseOutputStream stream(connection);
+ HttpOutput output(stream, false /* assume no keep-alive */);
+ output.SendStatus(HttpStatus_500_InternalServerError);
+ return;
+ }
+
+ MongooseOutputStream stream(connection);
+ HttpOutput output(stream, server->IsKeepAliveEnabled());
+ HttpMethod method = HttpMethod_Get;
try
{
- if (that->HasHandler())
+ try
{
- found = that->GetHandler().Handle(output, RequestOrigin_RestApi, remoteIp, username.c_str(),
- method, uri, headers, argumentsGET, body.c_str(), body.size());
+ InternalCallback(output, method, *server, connection, request);
+ }
+ catch (OrthancException&)
+ {
+ throw; // Pass the exception to the main handler below
+ }
+ // Now convert native exceptions as OrthancException
+ catch (boost::bad_lexical_cast&)
+ {
+ LOG(ERROR) << "Syntax error in some user-supplied data";
+ throw OrthancException(ErrorCode_BadParameterType);
+ }
+ catch (std::runtime_error&)
+ {
+ // Presumably an error while parsing the JSON body
+ throw OrthancException(ErrorCode_BadRequest);
+ }
+ catch (std::bad_alloc&)
+ {
+ LOG(ERROR) << "The server hosting Orthanc is running out of memory";
+ throw OrthancException(ErrorCode_NotEnoughMemory);
+ }
+ catch (...)
+ {
+ LOG(ERROR) << "An unhandled exception was generated inside the HTTP server";
+ throw OrthancException(ErrorCode_InternalError);
}
}
- catch (boost::bad_lexical_cast&)
- {
- throw OrthancException(ErrorCode_BadParameterType);
- }
- catch (std::runtime_error&)
+ catch (OrthancException& e)
{
- // Presumably an error while parsing the JSON body
- throw OrthancException(ErrorCode_BadRequest);
- }
+ assert(server != NULL);
- if (!found)
- {
- throw OrthancException(ErrorCode_UnknownResource);
- }
- }
- catch (OrthancException& e)
- {
- // Using this candidate handler results in an exception
- try
- {
- if (that->GetExceptionFormatter() == NULL)
+ // Using this candidate handler results in an exception
+ try
{
- LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
- output.SendStatus(e.GetHttpStatus());
+ if (server->GetExceptionFormatter() == NULL)
+ {
+ LOG(ERROR) << "Exception in the HTTP handler: " << e.What();
+ output.SendStatus(e.GetHttpStatus());
+ }
+ else
+ {
+ server->GetExceptionFormatter()->Format(output, e, method, request->uri);
+ }
}
- else
+ catch (OrthancException&)
{
- that->GetExceptionFormatter()->Format(output, e, method, request->uri);
+ // An exception here reflects the fact that the status code
+ // was already set by the HTTP handler.
}
}
- catch (OrthancException&)
- {
- // An exception here reflects the fact that the status code
- // was already set by the HTTP handler.
- }
-
- return;
+ }
+ catch (...)
+ {
+ // We should never arrive at this point, where it is even impossible to send an answer
+ LOG(ERROR) << "Catastrophic error inside the HTTP server, giving up";
}
}
@@ -783,7 +830,7 @@ namespace Orthanc
{
if (event == MG_NEW_REQUEST)
{
- InternalCallback(connection, request);
+ ProtectedCallback(connection, request);
// Mark as processed
return (void*) "";
@@ -799,7 +846,7 @@ namespace Orthanc
{
struct mg_request_info *request = mg_get_request_info(connection);
- InternalCallback(connection, request);
+ ProtectedCallback(connection, request);
return 1; // Do not let Mongoose handle the request by itself
}
@@ -831,7 +878,7 @@ namespace Orthanc
httpCompression_ = true;
exceptionFormatter_ = NULL;
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
// Check for the Heartbleed exploit
// https://en.wikipedia.org/wiki/OpenSSL#Heartbleed_bug
if (OPENSSL_VERSION_NUMBER < 0x1000107fL /* openssl-1.0.1g */ &&
@@ -932,7 +979,7 @@ namespace Orthanc
{
Stop();
-#if ORTHANC_SSL_ENABLED == 0
+#if ORTHANC_ENABLE_SSL == 0
if (enabled)
{
throw OrthancException(ErrorCode_SslDisabled);
@@ -951,7 +998,7 @@ namespace Orthanc
{
Stop();
keepAlive_ = enabled;
- LOG(WARNING) << "HTTP keep alive is " << (enabled ? "enabled" : "disabled");
+ LOG(INFO) << "HTTP keep alive is " << (enabled ? "enabled" : "disabled");
}
diff --git a/Core/Images/Font.cpp b/Core/Images/Font.cpp
index 5253ea2..873d690 100644
--- a/Core/Images/Font.cpp
+++ b/Core/Images/Font.cpp
@@ -33,6 +33,7 @@
#include "../PrecompiledHeaders.h"
#include "Font.h"
+#include "../SystemToolbox.h"
#include "../Toolbox.h"
#include "../OrthancException.h"
@@ -135,7 +136,7 @@ namespace Orthanc
void Font::LoadFromFile(const std::string& path)
{
std::string font;
- Toolbox::ReadFile(font, path);
+ SystemToolbox::ReadFile(font, path);
LoadFromMemory(font);
}
diff --git a/Core/Pkcs11.h b/Core/Images/IImageWriter.cpp
similarity index 71%
copy from Core/Pkcs11.h
copy to Core/Images/IImageWriter.cpp
index 3a56c74..b215080 100644
--- a/Core/Pkcs11.h
+++ b/Core/Images/IImageWriter.cpp
@@ -30,27 +30,25 @@
**/
-#pragma once
+#include "IImageWriter.h"
-#if ORTHANC_PKCS11_ENABLED != 1 || ORTHANC_SSL_ENABLED != 1
-# error This file cannot be used if OpenSSL or PKCS#11 support is disabled
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
#endif
-
-#include <string>
-
namespace Orthanc
{
- namespace Pkcs11
+#if ORTHANC_SANDBOXED == 0
+ void IImageWriter::WriteToFileInternal(const std::string& path,
+ unsigned int width,
+ unsigned int height,
+ unsigned int pitch,
+ PixelFormat format,
+ const void* buffer)
{
- const char* GetEngineIdentifier();
-
- bool IsInitialized();
-
- void Initialize(const std::string& module,
- const std::string& pin,
- bool verbose);
-
- void Finalize();
+ std::string compressed;
+ WriteToMemoryInternal(compressed, width, height, pitch, format, buffer);
+ SystemToolbox::WriteFile(compressed, path);
}
+#endif
}
diff --git a/Core/Images/IImageWriter.h b/Core/Images/IImageWriter.h
index d8c446d..ca27010 100644
--- a/Core/Images/IImageWriter.h
+++ b/Core/Images/IImageWriter.h
@@ -33,10 +33,13 @@
#pragma once
#include "ImageAccessor.h"
-#include "../Toolbox.h"
#include <boost/noncopyable.hpp>
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
namespace Orthanc
{
class IImageWriter : public boost::noncopyable
@@ -49,17 +52,14 @@ namespace Orthanc
PixelFormat format,
const void* buffer) = 0;
+#if ORTHANC_SANDBOXED == 0
virtual void WriteToFileInternal(const std::string& path,
unsigned int width,
unsigned int height,
unsigned int pitch,
PixelFormat format,
- const void* buffer)
- {
- std::string compressed;
- WriteToMemoryInternal(compressed, width, height, pitch, format, buffer);
- Toolbox::WriteFile(compressed, path);
- }
+ const void* buffer);
+#endif
public:
virtual ~IImageWriter()
@@ -73,11 +73,13 @@ namespace Orthanc
accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
}
+#if ORTHANC_SANDBOXED == 0
virtual void WriteToFile(const std::string& path,
const ImageAccessor& accessor)
{
WriteToFileInternal(path, accessor.GetWidth(), accessor.GetHeight(),
accessor.GetPitch(), accessor.GetFormat(), accessor.GetConstBuffer());
}
+#endif
};
}
diff --git a/Core/MultiThreading/Semaphore.cpp b/Core/Images/Image.cpp
similarity index 71%
copy from Core/MultiThreading/Semaphore.cpp
copy to Core/Images/Image.cpp
index 4de6cb8..4212f6d 100644
--- a/Core/MultiThreading/Semaphore.cpp
+++ b/Core/Images/Image.cpp
@@ -30,39 +30,29 @@
**/
-#include "../PrecompiledHeaders.h"
-#include "Semaphore.h"
+#include "Image.h"
-#include "../OrthancException.h"
+#include "ImageProcessing.h"
+#include <memory>
namespace Orthanc
{
- Semaphore::Semaphore(unsigned int count) : count_(count)
+ Image::Image(PixelFormat format,
+ unsigned int width,
+ unsigned int height,
+ bool forceMinimalPitch) :
+ image_(format, width, height, forceMinimalPitch)
{
- if (count == 0)
- {
- throw OrthancException(ErrorCode_ParameterOutOfRange);
- }
+ ImageAccessor accessor = image_.GetAccessor();
+ AssignWritable(format, width, height, accessor.GetPitch(), accessor.GetBuffer());
}
- void Semaphore::Release()
- {
- boost::mutex::scoped_lock lock(mutex_);
-
- count_++;
- condition_.notify_one();
- }
- void Semaphore::Acquire()
+ Image* Image::Clone(const ImageAccessor& source)
{
- boost::mutex::scoped_lock lock(mutex_);
-
- while (count_ == 0)
- {
- condition_.wait(lock);
- }
-
- count_++;
+ std::auto_ptr<Image> target(new Image(source.GetFormat(), source.GetWidth(), source.GetHeight(), false));
+ ImageProcessing::Copy(*target, source);
+ return target.release();
}
}
diff --git a/Core/Images/Image.h b/Core/Images/Image.h
index 16877f0..eba83c7 100644
--- a/Core/Images/Image.h
+++ b/Core/Images/Image.h
@@ -45,11 +45,9 @@ namespace Orthanc
public:
Image(PixelFormat format,
unsigned int width,
- unsigned int height) :
- image_(format, width, height)
- {
- ImageAccessor accessor = image_.GetAccessor();
- AssignWritable(format, width, height, accessor.GetPitch(), accessor.GetBuffer());
- }
+ unsigned int height,
+ bool forceMinimalPitch);
+
+ static Image* Clone(const ImageAccessor& source);
};
}
diff --git a/Core/Images/ImageAccessor.cpp b/Core/Images/ImageAccessor.cpp
index bd7a05a..eff8623 100644
--- a/Core/Images/ImageAccessor.cpp
+++ b/Core/Images/ImageAccessor.cpp
@@ -275,4 +275,22 @@ namespace Orthanc
return result;
}
+
+ void ImageAccessor::SetFormat(PixelFormat format)
+ {
+ if (readOnly_)
+ {
+#if ORTHANC_ENABLE_LOGGING == 1
+ LOG(ERROR) << "Trying to modify the format of a read-only image";
+#endif
+ throw OrthancException(ErrorCode_ReadOnly);
+ }
+
+ if (::Orthanc::GetBytesPerPixel(format) != ::Orthanc::GetBytesPerPixel(format_))
+ {
+ throw OrthancException(ErrorCode_IncompatibleImageFormat);
+ }
+
+ format_ = format;
+ }
}
diff --git a/Core/Images/ImageAccessor.h b/Core/Images/ImageAccessor.h
index 02d86d4..77e79c2 100644
--- a/Core/Images/ImageAccessor.h
+++ b/Core/Images/ImageAccessor.h
@@ -125,5 +125,7 @@ namespace Orthanc
unsigned int y,
unsigned int width,
unsigned int height) const;
+
+ void SetFormat(PixelFormat format);
};
}
diff --git a/Core/Images/ImageBuffer.cpp b/Core/Images/ImageBuffer.cpp
index a932e47..71364dc 100644
--- a/Core/Images/ImageBuffer.cpp
+++ b/Core/Images/ImageBuffer.cpp
@@ -87,7 +87,9 @@ namespace Orthanc
ImageBuffer::ImageBuffer(PixelFormat format,
unsigned int width,
- unsigned int height)
+ unsigned int height,
+ bool forceMinimalPitch) :
+ forceMinimalPitch_(forceMinimalPitch)
{
Initialize();
SetWidth(width);
@@ -158,16 +160,6 @@ namespace Orthanc
}
- void ImageBuffer::SetMinimalPitchForced(bool force)
- {
- if (force != forceMinimalPitch_)
- {
- changed_ = true;
- forceMinimalPitch_ = force;
- }
- }
-
-
void ImageBuffer::AcquireOwnership(ImageBuffer& other)
{
// Remove the content of the current image
diff --git a/Core/Images/ImageBuffer.h b/Core/Images/ImageBuffer.h
index 381269e..21b1b15 100644
--- a/Core/Images/ImageBuffer.h
+++ b/Core/Images/ImageBuffer.h
@@ -61,7 +61,8 @@ namespace Orthanc
public:
ImageBuffer(PixelFormat format,
unsigned int width,
- unsigned int height);
+ unsigned int height,
+ bool forceMinimalPitch);
ImageBuffer()
{
@@ -108,8 +109,6 @@ namespace Orthanc
return forceMinimalPitch_;
}
- void SetMinimalPitchForced(bool force);
-
void AcquireOwnership(ImageBuffer& other);
};
}
diff --git a/Core/Images/ImageProcessing.cpp b/Core/Images/ImageProcessing.cpp
index a9405b1..23c9fee 100644
--- a/Core/Images/ImageProcessing.cpp
+++ b/Core/Images/ImageProcessing.cpp
@@ -519,6 +519,27 @@ namespace Orthanc
return;
}
+ if (target.GetFormat() == PixelFormat_BGRA32 &&
+ source.GetFormat() == PixelFormat_RGB24)
+ {
+ for (unsigned int y = 0; y < source.GetHeight(); y++)
+ {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(source.GetConstRow(y));
+ uint8_t* q = reinterpret_cast<uint8_t*>(target.GetRow(y));
+ for (unsigned int x = 0; x < source.GetWidth(); x++)
+ {
+ q[0] = p[2];
+ q[1] = p[1];
+ q[2] = p[0];
+ q[3] = 255;
+ p += 3;
+ q += 4;
+ }
+ }
+
+ return;
+ }
+
throw OrthancException(ErrorCode_NotImplemented);
}
@@ -552,6 +573,61 @@ namespace Orthanc
}
+ void ImageProcessing::Set(ImageAccessor& image,
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue,
+ uint8_t alpha)
+ {
+ uint8_t p[4];
+ unsigned int size;
+
+ switch (image.GetFormat())
+ {
+ case PixelFormat_RGBA32:
+ p[0] = red;
+ p[1] = green;
+ p[2] = blue;
+ p[3] = alpha;
+ size = 4;
+ break;
+
+ case PixelFormat_BGRA32:
+ p[0] = blue;
+ p[1] = green;
+ p[2] = red;
+ p[3] = alpha;
+ size = 4;
+ break;
+
+ case PixelFormat_RGB24:
+ p[0] = red;
+ p[1] = green;
+ p[2] = blue;
+ size = 3;
+ break;
+
+ default:
+ throw OrthancException(ErrorCode_NotImplemented);
+ }
+
+ for (unsigned int y = 0; y < image.GetHeight(); y++)
+ {
+ uint8_t* q = reinterpret_cast<uint8_t*>(image.GetRow(y));
+
+ for (unsigned int x = 0; x < image.GetWidth(); x++)
+ {
+ for (unsigned int i = 0; i < size; i++)
+ {
+ q[i] = p[i];
+ }
+
+ q += size;
+ }
+ }
+ }
+
+
void ImageProcessing::ShiftRight(ImageAccessor& image,
unsigned int shift)
{
diff --git a/Core/Images/ImageProcessing.h b/Core/Images/ImageProcessing.h
index 9c4ab81..45176b5 100644
--- a/Core/Images/ImageProcessing.h
+++ b/Core/Images/ImageProcessing.h
@@ -50,6 +50,12 @@ namespace Orthanc
static void Set(ImageAccessor& image,
int64_t value);
+ static void Set(ImageAccessor& image,
+ uint8_t red,
+ uint8_t green,
+ uint8_t blue,
+ uint8_t alpha);
+
static void ShiftRight(ImageAccessor& target,
unsigned int shift);
diff --git a/Core/Images/JpegReader.cpp b/Core/Images/JpegReader.cpp
index 9ddcb37..9d6ea08 100644
--- a/Core/Images/JpegReader.cpp
+++ b/Core/Images/JpegReader.cpp
@@ -36,7 +36,11 @@
#include "JpegErrorManager.h"
#include "../OrthancException.h"
#include "../Logging.h"
-#include "../Toolbox.h"
+
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
+#endif
+
namespace Orthanc
{
@@ -94,9 +98,10 @@ namespace Orthanc
}
+#if ORTHANC_SANDBOXED == 0
void JpegReader::ReadFromFile(const std::string& filename)
{
- FILE* fp = Toolbox::OpenFile(filename, FileMode_ReadBinary);
+ FILE* fp = SystemToolbox::OpenFile(filename, FileMode_ReadBinary);
if (!fp)
{
throw OrthancException(ErrorCode_InexistentFile);
@@ -112,7 +117,7 @@ namespace Orthanc
{
jpeg_destroy_decompress(&cinfo);
fclose(fp);
- LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
+ LOG(ERROR) << "Error during JPEG decoding: " << jerr.GetMessage();
throw OrthancException(ErrorCode_InternalError);
}
@@ -135,6 +140,7 @@ namespace Orthanc
jpeg_destroy_decompress(&cinfo);
fclose(fp);
}
+#endif
void JpegReader::ReadFromMemory(const void* buffer,
@@ -149,7 +155,7 @@ namespace Orthanc
if (setjmp(jerr.GetJumpBuffer()))
{
jpeg_destroy_decompress(&cinfo);
- LOG(ERROR) << "Error during JPEG encoding: " << jerr.GetMessage();
+ LOG(ERROR) << "Error during JPEG decoding: " << jerr.GetMessage();
throw OrthancException(ErrorCode_InternalError);
}
diff --git a/Core/Images/JpegReader.h b/Core/Images/JpegReader.h
index 5cb5551..978058c 100644
--- a/Core/Images/JpegReader.h
+++ b/Core/Images/JpegReader.h
@@ -37,6 +37,10 @@
#include <string>
#include <boost/noncopyable.hpp>
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
namespace Orthanc
{
class JpegReader :
@@ -47,7 +51,9 @@ namespace Orthanc
std::string content_;
public:
+#if ORTHANC_SANDBOXED == 0
void ReadFromFile(const std::string& filename);
+#endif
void ReadFromMemory(const void* buffer,
size_t size);
diff --git a/Core/Images/JpegWriter.cpp b/Core/Images/JpegWriter.cpp
index 86f9d3c..6ce0d63 100644
--- a/Core/Images/JpegWriter.cpp
+++ b/Core/Images/JpegWriter.cpp
@@ -35,9 +35,12 @@
#include "../OrthancException.h"
#include "../Logging.h"
-
#include "JpegErrorManager.h"
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
+#endif
+
#include <stdlib.h>
#include <vector>
@@ -102,7 +105,7 @@ namespace Orthanc
void JpegWriter::SetQuality(uint8_t quality)
{
- if (quality <= 0 || quality > 100)
+ if (quality == 0 || quality > 100)
{
throw OrthancException(ErrorCode_ParameterOutOfRange);
}
@@ -111,6 +114,7 @@ namespace Orthanc
}
+#if ORTHANC_SANDBOXED == 0
void JpegWriter::WriteToFileInternal(const std::string& filename,
unsigned int width,
unsigned int height,
@@ -118,7 +122,7 @@ namespace Orthanc
PixelFormat format,
const void* buffer)
{
- FILE* fp = Toolbox::OpenFile(filename, FileMode_WriteBinary);
+ FILE* fp = SystemToolbox::OpenFile(filename, FileMode_WriteBinary);
if (fp == NULL)
{
throw OrthancException(ErrorCode_CannotWriteFile);
@@ -154,6 +158,7 @@ namespace Orthanc
fclose(fp);
}
+#endif
void JpegWriter::WriteToMemoryInternal(std::string& jpeg,
diff --git a/Core/Images/JpegWriter.h b/Core/Images/JpegWriter.h
index 5d18af3..ffb6098 100644
--- a/Core/Images/JpegWriter.h
+++ b/Core/Images/JpegWriter.h
@@ -46,12 +46,14 @@ namespace Orthanc
PixelFormat format,
const void* buffer);
+#if ORTHANC_SANDBOXED == 0
virtual void WriteToMemoryInternal(std::string& jpeg,
unsigned int width,
unsigned int height,
unsigned int pitch,
PixelFormat format,
const void* buffer);
+#endif
private:
uint8_t quality_;
diff --git a/Core/Images/PngReader.cpp b/Core/Images/PngReader.cpp
index b93aee0..8315ca7 100644
--- a/Core/Images/PngReader.cpp
+++ b/Core/Images/PngReader.cpp
@@ -36,11 +36,16 @@
#include "../OrthancException.h"
#include "../Toolbox.h"
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
+#endif
+
#include <png.h>
#include <string.h> // For memcpy()
namespace Orthanc
{
+#if ORTHANC_SANDBOXED == 0
namespace
{
struct FileRabi
@@ -49,7 +54,7 @@ namespace Orthanc
FileRabi(const char* filename)
{
- fp_ = Toolbox::OpenFile(filename, FileMode_ReadBinary);
+ fp_ = SystemToolbox::OpenFile(filename, FileMode_ReadBinary);
if (!fp_)
{
throw OrthancException(ErrorCode_InexistentFile);
@@ -65,6 +70,7 @@ namespace Orthanc
}
};
}
+#endif
struct PngReader::PngRabi
@@ -206,6 +212,8 @@ namespace Orthanc
AssignWritable(format, width, height, pitch, &data_[0]);
}
+
+#if ORTHANC_SANDBOXED == 0
void PngReader::ReadFromFile(const std::string& filename)
{
FileRabi f(filename.c_str());
@@ -230,6 +238,7 @@ namespace Orthanc
Read(rabi);
}
+#endif
namespace
diff --git a/Core/Images/PngReader.h b/Core/Images/PngReader.h
index b6ad811..fd18d26 100644
--- a/Core/Images/PngReader.h
+++ b/Core/Images/PngReader.h
@@ -41,6 +41,10 @@
#include <boost/shared_ptr.hpp>
#include <boost/noncopyable.hpp>
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
namespace Orthanc
{
class PngReader :
@@ -59,7 +63,9 @@ namespace Orthanc
public:
PngReader();
+#if ORTHANC_SANDBOXED == 0
void ReadFromFile(const std::string& filename);
+#endif
void ReadFromMemory(const void* buffer,
size_t size);
diff --git a/Core/Images/PngWriter.cpp b/Core/Images/PngWriter.cpp
index 8a2d66a..5603bcf 100644
--- a/Core/Images/PngWriter.cpp
+++ b/Core/Images/PngWriter.cpp
@@ -40,6 +40,10 @@
#include "../ChunkedBuffer.h"
#include "../Toolbox.h"
+#if ORTHANC_SANDBOXED == 0
+# include "../SystemToolbox.h"
+#endif
+
// http://www.libpng.org/pub/png/libpng-1.2.5-manual.html#section-4
// http://zarb.org/~gc/html/libpng.html
@@ -202,6 +206,7 @@ namespace Orthanc
}
+#if ORTHANC_SANDBOXED == 0
void PngWriter::WriteToFileInternal(const std::string& filename,
unsigned int width,
unsigned int height,
@@ -211,7 +216,7 @@ namespace Orthanc
{
Prepare(width, height, pitch, format, buffer);
- FILE* fp = Toolbox::OpenFile(filename, FileMode_WriteBinary);
+ FILE* fp = SystemToolbox::OpenFile(filename, FileMode_WriteBinary);
if (!fp)
{
throw OrthancException(ErrorCode_CannotWriteFile);
@@ -229,7 +234,7 @@ namespace Orthanc
fclose(fp);
}
-
+#endif
static void MemoryCallback(png_structp png_ptr,
diff --git a/Core/Images/PngWriter.h b/Core/Images/PngWriter.h
index 591112f..7d8b87f 100644
--- a/Core/Images/PngWriter.h
+++ b/Core/Images/PngWriter.h
@@ -48,12 +48,14 @@ namespace Orthanc
PixelFormat format,
const void* buffer);
+#if ORTHANC_SANDBOXED == 0
virtual void WriteToMemoryInternal(std::string& png,
unsigned int width,
unsigned int height,
unsigned int pitch,
PixelFormat format,
const void* buffer);
+#endif
private:
struct PImpl;
diff --git a/Core/Logging.cpp b/Core/Logging.cpp
index 7bce92b..cffdb5b 100644
--- a/Core/Logging.cpp
+++ b/Core/Logging.cpp
@@ -83,6 +83,7 @@ namespace Orthanc
#include "OrthancException.h"
#include "Enumerations.h"
#include "Toolbox.h"
+#include "SystemToolbox.h"
#include <fstream>
#include <boost/filesystem.hpp>
@@ -150,7 +151,7 @@ namespace Orthanc
boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
boost::filesystem::path root(directory);
- boost::filesystem::path exe(Toolbox::GetPathToExecutable());
+ boost::filesystem::path exe(SystemToolbox::GetPathToExecutable());
if (!boost::filesystem::exists(root) ||
!boost::filesystem::is_directory(root))
@@ -166,7 +167,7 @@ namespace Orthanc
now.time_of_day().hours(),
now.time_of_day().minutes(),
now.time_of_day().seconds(),
- Toolbox::GetProcessId());
+ SystemToolbox::GetProcessId());
std::string programName = exe.filename().replace_extension("").string();
@@ -318,113 +319,123 @@ namespace Orthanc
return;
}
- LogLevel l = StringToLogLevel(level);
-
- if ((l == LogLevel_Info && !loggingContext_->infoEnabled_) ||
- (l == LogLevel_Trace && !loggingContext_->traceEnabled_))
+ try
{
- // This logging level is disabled, directly exit and unlock
- // the mutex to speed-up things. The stream is set to "/dev/null"
+ LogLevel l = StringToLogLevel(level);
+
+ if ((l == LogLevel_Info && !loggingContext_->infoEnabled_) ||
+ (l == LogLevel_Trace && !loggingContext_->traceEnabled_))
+ {
+ // This logging level is disabled, directly exit and unlock
+ // the mutex to speed-up things. The stream is set to "/dev/null"
+ lock_.unlock();
+ return;
+ }
+
+ // Compute the header of the line, temporary release the lock as
+ // this is a time-consuming operation
lock_.unlock();
- return;
- }
+ std::string header;
- // Compute the header of the line, temporary release the lock as
- // this is a time-consuming operation
- lock_.unlock();
- std::string header;
+ {
+ boost::filesystem::path path(file);
+ boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
+ boost::posix_time::time_duration duration = now.time_of_day();
+
+ /**
+ From Google Log documentation:
+
+ "Log lines have this form:
+
+ Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
+
+ where the fields are defined as follows:
+
+ L A single character, representing the log level (eg 'I' for INFO)
+ mm The month (zero padded; ie May is '05')
+ dd The day (zero padded)
+ hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
+ threadid The space-padded thread ID as returned by GetTID() (this matches the PID on Linux)
+ file The file name
+ line The line number
+ msg The user-supplied message"
+
+ In this implementation, "threadid" is not printed.
+ **/
+
+ char date[32];
+ sprintf(date, "%c%02d%02d %02d:%02d:%02d.%06d ",
+ level[0],
+ now.date().month().as_number(),
+ now.date().day().as_number(),
+ duration.hours(),
+ duration.minutes(),
+ duration.seconds(),
+ static_cast<int>(duration.fractional_seconds()));
+
+ header = std::string(date) + path.filename().string() + ":" + boost::lexical_cast<std::string>(line) + "] ";
+ }
- {
- boost::filesystem::path path(file);
- boost::posix_time::ptime now = boost::posix_time::microsec_clock::local_time();
- boost::posix_time::time_duration duration = now.time_of_day();
-
- /**
- From Google Log documentation:
-
- "Log lines have this form:
-
- Lmmdd hh:mm:ss.uuuuuu threadid file:line] msg...
-
- where the fields are defined as follows:
-
- L A single character, representing the log level (eg 'I' for INFO)
- mm The month (zero padded; ie May is '05')
- dd The day (zero padded)
- hh:mm:ss.uuuuuu Time in hours, minutes and fractional seconds
- threadid The space-padded thread ID as returned by GetTID() (this matches the PID on Linux)
- file The file name
- line The line number
- msg The user-supplied message"
-
- In this implementation, "threadid" is not printed.
- **/
-
- char date[32];
- sprintf(date, "%c%02d%02d %02d:%02d:%02d.%06d ",
- level[0],
- now.date().month().as_number(),
- now.date().day().as_number(),
- duration.hours(),
- duration.minutes(),
- duration.seconds(),
- static_cast<int>(duration.fractional_seconds()));
-
- header = std::string(date) + path.filename().string() + ":" + boost::lexical_cast<std::string>(line) + "] ";
- }
+ // The header is computed, we now re-lock the mutex to access
+ // the stream objects. Pay attention that "loggingContext_",
+ // "infoEnabled_" or "traceEnabled_" might have changed while
+ // the mutex was unlocked.
+ lock_.lock();
- // The header is computed, we now re-lock the mutex to access
- // the stream objects. Pay attention that "loggingContext_",
- // "infoEnabled_" or "traceEnabled_" might have changed while
- // the mutex was unlocked.
- lock_.lock();
+ if (loggingContext_.get() == NULL)
+ {
+ fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
+ return;
+ }
- if (loggingContext_.get() == NULL)
- {
- fprintf(stderr, "ERROR: Trying to log a message after the finalization of the logging engine\n");
- return;
- }
+ switch (l)
+ {
+ case LogLevel_Error:
+ stream_ = loggingContext_->error_;
+ break;
- switch (l)
- {
- case LogLevel_Error:
- stream_ = loggingContext_->error_;
- break;
+ case LogLevel_Warning:
+ stream_ = loggingContext_->warning_;
+ break;
- case LogLevel_Warning:
- stream_ = loggingContext_->warning_;
- break;
+ case LogLevel_Info:
+ if (loggingContext_->infoEnabled_)
+ {
+ stream_ = loggingContext_->info_;
+ }
- case LogLevel_Info:
- if (loggingContext_->infoEnabled_)
- {
- stream_ = loggingContext_->info_;
- }
+ break;
- break;
+ case LogLevel_Trace:
+ if (loggingContext_->traceEnabled_)
+ {
+ stream_ = loggingContext_->info_;
+ }
- case LogLevel_Trace:
- if (loggingContext_->traceEnabled_)
- {
- stream_ = loggingContext_->info_;
- }
+ break;
- break;
+ default:
+ throw OrthancException(ErrorCode_InternalError);
+ }
- default:
- throw OrthancException(ErrorCode_InternalError);
- }
+ if (stream_ == &null_)
+ {
+ // The logging is disabled for this level. The stream is the
+ // "null_" member of this object, so we can release the global
+ // mutex.
+ lock_.unlock();
+ }
- if (stream_ == &null_)
- {
- // The logging is disabled for this level. The stream is the
- // "null_" member of this object, so we can release the global
- // mutex.
- lock_.unlock();
+ (*stream_) << header;
+ }
+ catch (...)
+ {
+ // Something is going really wrong, probably running out of
+ // memory. Fallback to a degraded mode.
+ stream_ = loggingContext_->error_;
+ (*stream_) << "E???? ??:??:??.?????? ] ";
}
-
- (*stream_) << header;
}
diff --git a/Core/Logging.h b/Core/Logging.h
index 7318246..abec83f 100644
--- a/Core/Logging.h
+++ b/Core/Logging.h
@@ -34,6 +34,10 @@
#include <iostream>
+#if !defined(ORTHANC_ENABLE_LOGGING)
+# error The macro ORTHANC_ENABLE_LOGGING must be defined
+#endif
+
namespace Orthanc
{
namespace Logging
@@ -66,6 +70,12 @@ namespace Orthanc
{
return *this;
}
+
+ // This overload fixes build problems with Visual Studio 2015
+ std::ostream& operator<< (const char* message)
+ {
+ return *this;
+ }
};
}
}
@@ -104,6 +114,12 @@ namespace Orthanc
{
return (*stream_) << message;
}
+
+ // This overload fixes build problems with Visual Studio 2015
+ std::ostream& operator<< (const char* message)
+ {
+ return (*stream_) << message;
+ }
};
}
}
diff --git a/Core/Lua/LuaContext.cpp b/Core/Lua/LuaContext.cpp
index cc6b710..e6a7d63 100644
--- a/Core/Lua/LuaContext.cpp
+++ b/Core/Lua/LuaContext.cpp
@@ -497,6 +497,10 @@ namespace Orthanc
// Lua can convert most types to strings by default.
result = std::string(lua_tostring(lua_, top));
}
+ else if (lua_isboolean(lua_, top))
+ {
+ result = lua_toboolean(lua_, top) ? true : false;
+ }
else
{
LOG(WARNING) << "Unsupported Lua type when returning Json";
diff --git a/Core/Lua/LuaFunctionCall.cpp b/Core/Lua/LuaFunctionCall.cpp
index 1e9c941..a52afe6 100644
--- a/Core/Lua/LuaFunctionCall.cpp
+++ b/Core/Lua/LuaFunctionCall.cpp
@@ -166,4 +166,26 @@ namespace Orthanc
PushJson(json);
}
+
+
+ void LuaFunctionCall::PushDicom(const DicomMap& dicom)
+ {
+ DicomArray a(dicom);
+ PushDicom(a);
+ }
+
+
+ void LuaFunctionCall::PushDicom(const DicomArray& dicom)
+ {
+ Json::Value value = Json::objectValue;
+
+ for (size_t i = 0; i < dicom.GetSize(); i++)
+ {
+ const DicomValue& v = dicom.GetElement(i).GetValue();
+ std::string s = (v.IsNull() || v.IsBinary()) ? "" : v.GetContent();
+ value[dicom.GetElement(i).GetTag().Format()] = s;
+ }
+
+ PushJson(value);
+ }
}
diff --git a/Core/Lua/LuaFunctionCall.h b/Core/Lua/LuaFunctionCall.h
index 3dff4f1..a4cdc38 100644
--- a/Core/Lua/LuaFunctionCall.h
+++ b/Core/Lua/LuaFunctionCall.h
@@ -34,6 +34,9 @@
#include "LuaContext.h"
+#include "../DicomFormat/DicomArray.h"
+#include "../DicomFormat/DicomMap.h"
+
#include <json/json.h>
namespace Orthanc
@@ -64,6 +67,10 @@ namespace Orthanc
void PushStringMap(const std::map<std::string, std::string>& value);
+ void PushDicom(const DicomMap& dicom);
+
+ void PushDicom(const DicomArray& dicom);
+
void Execute()
{
ExecuteInternal(0);
diff --git a/Core/MultiThreading/BagOfTasksProcessor.cpp b/Core/MultiThreading/BagOfTasksProcessor.cpp
index dc2034f..c409f1c 100644
--- a/Core/MultiThreading/BagOfTasksProcessor.cpp
+++ b/Core/MultiThreading/BagOfTasksProcessor.cpp
@@ -33,8 +33,10 @@
#include "../PrecompiledHeaders.h"
#include "BagOfTasksProcessor.h"
+#include "../Logging.h"
#include "../OrthancException.h"
+#include <stdio.h>
namespace Orthanc
{
@@ -58,12 +60,19 @@ namespace Orthanc
{
return command_->Execute();
}
- catch (OrthancException&)
+ catch (OrthancException& e)
{
+ LOG(ERROR) << "Exception while processing a bag of tasks: " << e.What();
return false;
}
- catch (std::runtime_error&)
+ catch (std::runtime_error& e)
{
+ LOG(ERROR) << "Runtime exception while processing a bag of tasks: " << e.what();
+ return false;
+ }
+ catch (...)
+ {
+ LOG(ERROR) << "Native exception while processing a bag of tasks";
return false;
}
}
@@ -75,6 +84,20 @@ namespace Orthanc
};
+ void BagOfTasksProcessor::SignalProgress(Task& task,
+ Bag& bag)
+ {
+ assert(bag.done_ < bag.size_);
+
+ bag.done_ += 1;
+
+ if (bag.done_ == bag.size_)
+ {
+ exitStatus_[task.GetBag()] = (bag.status_ == BagStatus_Running);
+ bagFinished_.notify_all();
+ }
+ }
+
void BagOfTasksProcessor::Worker(BagOfTasksProcessor* that)
{
while (that->continue_)
@@ -93,8 +116,9 @@ namespace Orthanc
if (bag->second.status_ != BagStatus_Running)
{
- // This bag of task has failed or is tagged as canceled, do nothing
- bag->second.done_ += 1;
+ // Do not execute this task, as its parent bag of tasks
+ // has failed or is tagged as canceled
+ that->SignalProgress(task, bag->second);
continue;
}
}
@@ -112,14 +136,7 @@ namespace Orthanc
bag->second.status_ = BagStatus_Failed;
}
- assert(bag->second.done_ < bag->second.size_);
- bag->second.done_ += 1;
-
- if (bag->second.done_ == bag->second.size_)
- {
- that->exitStatus_[task.GetBag()] = (bag->second.status_ == BagStatus_Running);
- that->bagFinished_.notify_all();
- }
+ that->SignalProgress(task, bag->second);
}
}
}
diff --git a/Core/MultiThreading/BagOfTasksProcessor.h b/Core/MultiThreading/BagOfTasksProcessor.h
index 51c0ff1..a0dff6e 100644
--- a/Core/MultiThreading/BagOfTasksProcessor.h
+++ b/Core/MultiThreading/BagOfTasksProcessor.h
@@ -64,10 +64,10 @@ namespace Orthanc
{
}
- Bag(size_t size) :
- size_(size),
- done_(0),
- status_(BagStatus_Running)
+ explicit Bag(size_t size) :
+ size_(size),
+ done_(0),
+ status_(BagStatus_Running)
{
}
};
@@ -97,6 +97,9 @@ namespace Orthanc
float GetProgress(int64_t bag);
+ void SignalProgress(Task& task,
+ Bag& bag);
+
public:
class Handle : public boost::noncopyable
{
@@ -137,7 +140,7 @@ namespace Orthanc
};
- BagOfTasksProcessor(size_t countThreads);
+ explicit BagOfTasksProcessor(size_t countThreads);
~BagOfTasksProcessor();
diff --git a/Core/MultiThreading/ReaderWriterLock.cpp b/Core/MultiThreading/ReaderWriterLock.cpp
index a2c6acb..25bc231 100644
--- a/Core/MultiThreading/ReaderWriterLock.cpp
+++ b/Core/MultiThreading/ReaderWriterLock.cpp
@@ -59,7 +59,7 @@ namespace Orthanc
}
public:
- ReaderLockable(boost::shared_mutex& lock) : lock_(lock)
+ explicit ReaderLockable(boost::shared_mutex& lock) : lock_(lock)
{
}
};
@@ -82,10 +82,9 @@ namespace Orthanc
}
public:
- WriterLockable(boost::shared_mutex& lock) : lock_(lock)
+ explicit WriterLockable(boost::shared_mutex& lock) : lock_(lock)
{
}
-
};
}
diff --git a/Core/MultiThreading/RunnableWorkersPool.cpp b/Core/MultiThreading/RunnableWorkersPool.cpp
index 30c67e6..f688e91 100644
--- a/Core/MultiThreading/RunnableWorkersPool.cpp
+++ b/Core/MultiThreading/RunnableWorkersPool.cpp
@@ -52,25 +52,33 @@ namespace Orthanc
{
while (that->continue_)
{
- std::auto_ptr<IDynamicObject> obj(that->queue_.Dequeue(100));
- if (obj.get() != NULL)
+ try
{
- try
+ std::auto_ptr<IDynamicObject> obj(that->queue_.Dequeue(100));
+ if (obj.get() != NULL)
{
IRunnableBySteps& runnable = *dynamic_cast<IRunnableBySteps*>(obj.get());
-
+
bool wishToContinue = runnable.Step();
-
+
if (wishToContinue)
{
// The runnable wishes to continue, reinsert it at the beginning of the queue
that->queue_.Enqueue(obj.release());
}
}
- catch (OrthancException& e)
- {
- LOG(ERROR) << "Exception in a pool of working threads: " << e.What();
- }
+ }
+ catch (OrthancException& e)
+ {
+ LOG(ERROR) << "Exception while handling some runnable object: " << e.What();
+ }
+ catch (std::bad_alloc&)
+ {
+ LOG(ERROR) << "Not enough memory to handle some runnable object";
+ }
+ catch (...)
+ {
+ LOG(ERROR) << "Native exception while handling some runnable object";
}
}
}
diff --git a/Core/MultiThreading/RunnableWorkersPool.h b/Core/MultiThreading/RunnableWorkersPool.h
index bde1edc..9bd2a2b 100644
--- a/Core/MultiThreading/RunnableWorkersPool.h
+++ b/Core/MultiThreading/RunnableWorkersPool.h
@@ -47,7 +47,7 @@ namespace Orthanc
void Stop();
public:
- RunnableWorkersPool(size_t countWorkers);
+ explicit RunnableWorkersPool(size_t countWorkers);
~RunnableWorkersPool();
diff --git a/Core/MultiThreading/Semaphore.cpp b/Core/MultiThreading/Semaphore.cpp
index 4de6cb8..82d5aa5 100644
--- a/Core/MultiThreading/Semaphore.cpp
+++ b/Core/MultiThreading/Semaphore.cpp
@@ -40,10 +40,6 @@ namespace Orthanc
{
Semaphore::Semaphore(unsigned int count) : count_(count)
{
- if (count == 0)
- {
- throw OrthancException(ErrorCode_ParameterOutOfRange);
- }
}
void Semaphore::Release()
diff --git a/Core/MultiThreading/Semaphore.h b/Core/MultiThreading/Semaphore.h
index 7bd6376..31e1392 100644
--- a/Core/MultiThreading/Semaphore.h
+++ b/Core/MultiThreading/Semaphore.h
@@ -50,5 +50,23 @@ namespace Orthanc
void Release();
void Acquire();
+
+ class Locker : public boost::noncopyable
+ {
+ private:
+ Semaphore& that_;
+
+ public:
+ explicit Locker(Semaphore& that) :
+ that_(that)
+ {
+ that_.Acquire();
+ }
+
+ ~Locker()
+ {
+ that_.Release();
+ }
+ };
};
}
diff --git a/Core/MultiThreading/SharedMessageQueue.cpp b/Core/MultiThreading/SharedMessageQueue.cpp
index 34508ae..0c1a727 100644
--- a/Core/MultiThreading/SharedMessageQueue.cpp
+++ b/Core/MultiThreading/SharedMessageQueue.cpp
@@ -185,4 +185,24 @@ namespace Orthanc
boost::mutex::scoped_lock lock(mutex_);
isFifo_ = false;
}
+
+ void SharedMessageQueue::Clear()
+ {
+ boost::mutex::scoped_lock lock(mutex_);
+
+ if (queue_.empty())
+ {
+ return;
+ }
+ else
+ {
+ while (!queue_.empty())
+ {
+ std::auto_ptr<IDynamicObject> message(queue_.front());
+ queue_.pop_front();
+ }
+
+ emptied_.notify_all();
+ }
+ }
}
diff --git a/Core/MultiThreading/SharedMessageQueue.h b/Core/MultiThreading/SharedMessageQueue.h
index 71728c0..211b774 100644
--- a/Core/MultiThreading/SharedMessageQueue.h
+++ b/Core/MultiThreading/SharedMessageQueue.h
@@ -78,5 +78,7 @@ namespace Orthanc
void SetFifoPolicy();
void SetLifoPolicy();
+
+ void Clear();
};
}
diff --git a/Core/OrthancException.h b/Core/OrthancException.h
index 5afa41f..d5544dd 100644
--- a/Core/OrthancException.h
+++ b/Core/OrthancException.h
@@ -45,7 +45,7 @@ namespace Orthanc
HttpStatus httpStatus_;
public:
- OrthancException(ErrorCode errorCode) :
+ explicit OrthancException(ErrorCode errorCode) :
errorCode_(errorCode),
httpStatus_(ConvertErrorCodeToHttpStatus(errorCode))
{
diff --git a/Core/Pkcs11.cpp b/Core/Pkcs11.cpp
index d0ed318..613a464 100644
--- a/Core/Pkcs11.cpp
+++ b/Core/Pkcs11.cpp
@@ -33,10 +33,6 @@
#include "PrecompiledHeaders.h"
#include "Pkcs11.h"
-#if ORTHANC_PKCS11_ENABLED != 1 || ORTHANC_SSL_ENABLED != 1
-# error This file cannot be used if OpenSSL or PKCS#11 support is disabled
-#endif
-
#if defined(OPENSSL_NO_RSA) || defined(OPENSSL_NO_EC) || defined(OPENSSL_NO_ECDSA) || defined(OPENSSL_NO_ECDH)
# error OpenSSL was compiled without support for RSA, EC, ECDSA or ECDH
@@ -45,12 +41,12 @@
#include "Logging.h"
#include "OrthancException.h"
-#include "Toolbox.h"
+#include "SystemToolbox.h"
extern "C"
{
-#include <libp11/engine.h> // This is P11's "engine.h"
-#include <libp11/libp11.h>
+# include <libp11/engine.h> // This is P11's "engine.h"
+# include <libp11/libp11.h>
}
#include <openssl/engine.h>
@@ -261,7 +257,7 @@ namespace Orthanc
}
if (module.empty() ||
- !Toolbox::IsRegularFile(module))
+ !SystemToolbox::IsRegularFile(module))
{
LOG(ERROR) << "The PKCS#11 module must be a path to one shared library (DLL or .so)";
throw OrthancException(ErrorCode_InexistentFile);
diff --git a/Core/Pkcs11.h b/Core/Pkcs11.h
index 3a56c74..f2e1cba 100644
--- a/Core/Pkcs11.h
+++ b/Core/Pkcs11.h
@@ -32,7 +32,23 @@
#pragma once
-#if ORTHANC_PKCS11_ENABLED != 1 || ORTHANC_SSL_ENABLED != 1
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_PKCS11)
+# error The macro ORTHANC_ENABLE_PKCS11 must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_SSL)
+# error The macro ORTHANC_ENABLE_SSL must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+# error This file cannot be used in sandboxed environments
+#endif
+
+#if ORTHANC_ENABLE_PKCS11 != 1 || ORTHANC_ENABLE_SSL != 1
# error This file cannot be used if OpenSSL or PKCS#11 support is disabled
#endif
diff --git a/Core/PrecompiledHeaders.h b/Core/PrecompiledHeaders.h
index e22f012..1422e30 100644
--- a/Core/PrecompiledHeaders.h
+++ b/Core/PrecompiledHeaders.h
@@ -48,7 +48,7 @@
#include <json/value.h>
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
#include <pugixml.hpp>
#endif
@@ -56,6 +56,5 @@
#include "Logging.h"
#include "OrthancException.h"
#include "Toolbox.h"
-#include "Uuid.h"
#endif
diff --git a/Core/RestApi/RestApi.cpp b/Core/RestApi/RestApi.cpp
index c314582..f9e6fa7 100644
--- a/Core/RestApi/RestApi.cpp
+++ b/Core/RestApi/RestApi.cpp
@@ -185,7 +185,7 @@ namespace Orthanc
{
RestApiOutput wrappedOutput(output, method);
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
{
// Look if the client wishes XML answers instead of JSON
// http://www.w3.org/Protocols/HTTP/HTRQ_Headers.html#z3
diff --git a/Core/RestApi/RestApiOutput.cpp b/Core/RestApi/RestApiOutput.cpp
index 0d137b9..c9901c4 100644
--- a/Core/RestApi/RestApiOutput.cpp
+++ b/Core/RestApi/RestApiOutput.cpp
@@ -35,6 +35,7 @@
#include "../Logging.h"
#include "../OrthancException.h"
+#include "../Toolbox.h"
#include <boost/lexical_cast.hpp>
@@ -91,10 +92,10 @@ namespace Orthanc
if (convertJsonToXml_)
{
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
std::string s;
Toolbox::JsonToXml(s, value);
- output_.SetContentType("application/xml");
+ output_.SetContentType("application/xml; charset=utf-8");
output_.Answer(s);
#else
LOG(ERROR) << "Orthanc was compiled without XML support";
@@ -104,7 +105,7 @@ namespace Orthanc
else
{
Json::StyledWriter writer;
- output_.SetContentType("application/json");
+ output_.SetContentType("application/json; charset=utf-8");
output_.Answer(writer.write(value));
}
diff --git a/Core/SystemToolbox.cpp b/Core/SystemToolbox.cpp
new file mode 100644
index 0000000..e22a006
--- /dev/null
+++ b/Core/SystemToolbox.cpp
@@ -0,0 +1,539 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "PrecompiledHeaders.h"
+#include "SystemToolbox.h"
+
+
+#if BOOST_HAS_DATE_TIME == 1
+# include <boost/date_time/posix_time/posix_time.hpp>
+#endif
+
+
+#if defined(_WIN32)
+# include <windows.h>
+# include <process.h> // For "_spawnvp()" and "_getpid()"
+#else
+# include <unistd.h> // For "execvp()"
+# include <sys/wait.h> // For "waitpid()"
+#endif
+
+
+#if defined(__APPLE__) && defined(__MACH__)
+# include <mach-o/dyld.h> /* _NSGetExecutablePath */
+# include <limits.h> /* PATH_MAX */
+#endif
+
+
+#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+# include <limits.h> /* PATH_MAX */
+# include <signal.h>
+# include <unistd.h>
+#endif
+
+
+// Inclusions for UUID
+// http://stackoverflow.com/a/1626302
+
+extern "C"
+{
+#ifdef WIN32
+# include <rpc.h>
+#else
+# include <uuid/uuid.h>
+#endif
+}
+
+
+#include "Logging.h"
+#include "OrthancException.h"
+#include "Toolbox.h"
+
+#include <boost/filesystem.hpp>
+#include <boost/filesystem/fstream.hpp>
+
+
+namespace Orthanc
+{
+ static bool finish_;
+ static ServerBarrierEvent barrierEvent_;
+
+#if defined(_WIN32)
+ static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType)
+ {
+ // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
+ finish_ = true;
+ return true;
+ }
+#else
+ static void SignalHandler(int signal)
+ {
+ if (signal == SIGHUP)
+ {
+ barrierEvent_ = ServerBarrierEvent_Reload;
+ }
+
+ finish_ = true;
+ }
+#endif
+
+
+ static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag)
+ {
+#if defined(_WIN32)
+ SetConsoleCtrlHandler(ConsoleControlHandler, true);
+#else
+ signal(SIGINT, SignalHandler);
+ signal(SIGQUIT, SignalHandler);
+ signal(SIGTERM, SignalHandler);
+ signal(SIGHUP, SignalHandler);
+#endif
+
+ // Active loop that awakens every 100ms
+ finish_ = false;
+ barrierEvent_ = ServerBarrierEvent_Stop;
+ while (!(*stopFlag || finish_))
+ {
+ Toolbox::USleep(100 * 1000);
+ }
+
+#if defined(_WIN32)
+ SetConsoleCtrlHandler(ConsoleControlHandler, false);
+#else
+ signal(SIGINT, NULL);
+ signal(SIGQUIT, NULL);
+ signal(SIGTERM, NULL);
+ signal(SIGHUP, NULL);
+#endif
+
+ return barrierEvent_;
+ }
+
+
+ ServerBarrierEvent SystemToolbox::ServerBarrier(const bool& stopFlag)
+ {
+ return ServerBarrierInternal(&stopFlag);
+ }
+
+
+ ServerBarrierEvent SystemToolbox::ServerBarrier()
+ {
+ const bool stopFlag = false;
+ return ServerBarrierInternal(&stopFlag);
+ }
+
+
+ static std::streamsize GetStreamSize(std::istream& f)
+ {
+ // http://www.cplusplus.com/reference/iostream/istream/tellg/
+ f.seekg(0, std::ios::end);
+ std::streamsize size = f.tellg();
+ f.seekg(0, std::ios::beg);
+
+ return size;
+ }
+
+
+ void SystemToolbox::ReadFile(std::string& content,
+ const std::string& path)
+ {
+ if (!IsRegularFile(path))
+ {
+ LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
+ throw OrthancException(ErrorCode_RegularFileExpected);
+ }
+
+ boost::filesystem::ifstream f;
+ f.open(path, std::ifstream::in | std::ifstream::binary);
+ if (!f.good())
+ {
+ throw OrthancException(ErrorCode_InexistentFile);
+ }
+
+ std::streamsize size = GetStreamSize(f);
+ content.resize(size);
+ if (size != 0)
+ {
+ f.read(reinterpret_cast<char*>(&content[0]), size);
+ }
+
+ f.close();
+ }
+
+
+ bool SystemToolbox::ReadHeader(std::string& header,
+ const std::string& path,
+ size_t headerSize)
+ {
+ if (!IsRegularFile(path))
+ {
+ LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
+ throw OrthancException(ErrorCode_RegularFileExpected);
+ }
+
+ boost::filesystem::ifstream f;
+ f.open(path, std::ifstream::in | std::ifstream::binary);
+ if (!f.good())
+ {
+ throw OrthancException(ErrorCode_InexistentFile);
+ }
+
+ bool full = true;
+
+ {
+ std::streamsize size = GetStreamSize(f);
+ if (size <= 0)
+ {
+ headerSize = 0;
+ full = false;
+ }
+ else if (static_cast<size_t>(size) < headerSize)
+ {
+ headerSize = size; // Truncate to the size of the file
+ full = false;
+ }
+ }
+
+ header.resize(headerSize);
+ if (headerSize != 0)
+ {
+ f.read(reinterpret_cast<char*>(&header[0]), headerSize);
+ }
+
+ f.close();
+
+ return full;
+ }
+
+
+ void SystemToolbox::WriteFile(const void* content,
+ size_t size,
+ const std::string& path)
+ {
+ boost::filesystem::ofstream f;
+ f.open(path, std::ofstream::out | std::ofstream::binary);
+ if (!f.good())
+ {
+ throw OrthancException(ErrorCode_CannotWriteFile);
+ }
+
+ if (size != 0)
+ {
+ f.write(reinterpret_cast<const char*>(content), size);
+
+ if (!f.good())
+ {
+ f.close();
+ throw OrthancException(ErrorCode_FileStorageCannotWrite);
+ }
+ }
+
+ f.close();
+ }
+
+
+ void SystemToolbox::WriteFile(const std::string& content,
+ const std::string& path)
+ {
+ WriteFile(content.size() > 0 ? content.c_str() : NULL,
+ content.size(), path);
+ }
+
+
+ void SystemToolbox::RemoveFile(const std::string& path)
+ {
+ if (boost::filesystem::exists(path))
+ {
+ if (IsRegularFile(path))
+ {
+ boost::filesystem::remove(path);
+ }
+ else
+ {
+ throw OrthancException(ErrorCode_RegularFileExpected);
+ }
+ }
+ }
+
+
+ uint64_t SystemToolbox::GetFileSize(const std::string& path)
+ {
+ try
+ {
+ return static_cast<uint64_t>(boost::filesystem::file_size(path));
+ }
+ catch (boost::filesystem::filesystem_error&)
+ {
+ throw OrthancException(ErrorCode_InexistentFile);
+ }
+ }
+
+
+ void SystemToolbox::MakeDirectory(const std::string& path)
+ {
+ if (boost::filesystem::exists(path))
+ {
+ if (!boost::filesystem::is_directory(path))
+ {
+ throw OrthancException(ErrorCode_DirectoryOverFile);
+ }
+ }
+ else
+ {
+ if (!boost::filesystem::create_directories(path))
+ {
+ throw OrthancException(ErrorCode_MakeDirectory);
+ }
+ }
+ }
+
+
+ bool SystemToolbox::IsExistingFile(const std::string& path)
+ {
+ return boost::filesystem::exists(path);
+ }
+
+
+#if defined(_WIN32)
+ static std::string GetPathToExecutableInternal()
+ {
+ // Yes, this is ugly, but there is no simple way to get the
+ // required buffer size, so we use a big constant
+ std::vector<char> buffer(32768);
+ /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1));
+ return std::string(&buffer[0]);
+ }
+
+#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+ static std::string GetPathToExecutableInternal()
+ {
+ std::vector<char> buffer(PATH_MAX + 1);
+ ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
+ if (bytes == 0)
+ {
+ throw OrthancException(ErrorCode_PathToExecutable);
+ }
+
+ return std::string(&buffer[0]);
+ }
+
+#elif defined(__APPLE__) && defined(__MACH__)
+ static std::string GetPathToExecutableInternal()
+ {
+ char pathbuf[PATH_MAX + 1];
+ unsigned int bufsize = static_cast<int>(sizeof(pathbuf));
+
+ _NSGetExecutablePath( pathbuf, &bufsize);
+
+ return std::string(pathbuf);
+ }
+
+#else
+#error Support your platform here
+#endif
+
+
+ std::string SystemToolbox::GetPathToExecutable()
+ {
+ boost::filesystem::path p(GetPathToExecutableInternal());
+ return boost::filesystem::absolute(p).string();
+ }
+
+
+ std::string SystemToolbox::GetDirectoryOfExecutable()
+ {
+ boost::filesystem::path p(GetPathToExecutableInternal());
+ return boost::filesystem::absolute(p.parent_path()).string();
+ }
+
+
+ void SystemToolbox::ExecuteSystemCommand(const std::string& command,
+ const std::vector<std::string>& arguments)
+ {
+ // Convert the arguments as a C array
+ std::vector<char*> args(arguments.size() + 2);
+
+ args.front() = const_cast<char*>(command.c_str());
+
+ for (size_t i = 0; i < arguments.size(); i++)
+ {
+ args[i + 1] = const_cast<char*>(arguments[i].c_str());
+ }
+
+ args.back() = NULL;
+
+ int status;
+
+#if defined(_WIN32)
+ // http://msdn.microsoft.com/en-us/library/275khfab.aspx
+ status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0]));
+
+#else
+ int pid = fork();
+
+ if (pid == -1)
+ {
+ // Error in fork()
+#if ORTHANC_ENABLE_LOGGING == 1
+ LOG(ERROR) << "Cannot fork a child process";
+#endif
+
+ throw OrthancException(ErrorCode_SystemCommand);
+ }
+ else if (pid == 0)
+ {
+ // Execute the system command in the child process
+ execvp(command.c_str(), &args[0]);
+
+ // We should never get here
+ _exit(1);
+ }
+ else
+ {
+ // Wait for the system command to exit
+ waitpid(pid, &status, 0);
+ }
+#endif
+
+ if (status != 0)
+ {
+#if ORTHANC_ENABLE_LOGGING == 1
+ LOG(ERROR) << "System command failed with status code " << status;
+#endif
+
+ throw OrthancException(ErrorCode_SystemCommand);
+ }
+ }
+
+
+ int SystemToolbox::GetProcessId()
+ {
+#if defined(_WIN32)
+ return static_cast<int>(_getpid());
+#else
+ return static_cast<int>(getpid());
+#endif
+ }
+
+
+ bool SystemToolbox::IsRegularFile(const std::string& path)
+ {
+ namespace fs = boost::filesystem;
+
+ try
+ {
+ if (fs::exists(path))
+ {
+ fs::file_status status = fs::status(path);
+ return (status.type() == boost::filesystem::regular_file ||
+ status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11
+ }
+ }
+ catch (fs::filesystem_error&)
+ {
+ }
+
+ return false;
+ }
+
+
+ FILE* SystemToolbox::OpenFile(const std::string& path,
+ FileMode mode)
+ {
+#if defined(_WIN32)
+ // TODO Deal with special characters by converting to the current locale
+#endif
+
+ const char* m;
+ switch (mode)
+ {
+ case FileMode_ReadBinary:
+ m = "rb";
+ break;
+
+ case FileMode_WriteBinary:
+ m = "wb";
+ break;
+
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+
+ return fopen(path.c_str(), m);
+ }
+
+
+ std::string SystemToolbox::GenerateUuid()
+ {
+#ifdef WIN32
+ UUID uuid;
+ UuidCreate ( &uuid );
+
+ unsigned char * str;
+ UuidToStringA ( &uuid, &str );
+
+ std::string s( ( char* ) str );
+
+ RpcStringFreeA ( &str );
+#else
+ uuid_t uuid;
+ uuid_generate_random ( uuid );
+ char s[37];
+ uuid_unparse ( uuid, s );
+#endif
+ return s;
+ }
+
+
+#if BOOST_HAS_DATE_TIME == 1
+ std::string SystemToolbox::GetNowIsoString()
+ {
+ boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+ return boost::posix_time::to_iso_string(now);
+ }
+
+ void SystemToolbox::GetNowDicom(std::string& date,
+ std::string& time)
+ {
+ boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
+ tm tm = boost::posix_time::to_tm(now);
+
+ char s[32];
+ sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+ date.assign(s);
+
+ // TODO milliseconds
+ sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
+ time.assign(s);
+ }
+#endif
+}
diff --git a/Core/OrthancException.h b/Core/SystemToolbox.h
similarity index 52%
copy from Core/OrthancException.h
copy to Core/SystemToolbox.h
index 5afa41f..e62b529 100644
--- a/Core/OrthancException.h
+++ b/Core/SystemToolbox.h
@@ -32,45 +32,71 @@
#pragma once
-#include <stdint.h>
-#include <string>
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+# error The namespace SystemToolbox cannot be used in sandboxed environments
+#endif
+
#include "Enumerations.h"
+#include <vector>
+#include <string>
+#include <stdint.h>
+
namespace Orthanc
{
- class OrthancException
+ namespace SystemToolbox
{
- protected:
- ErrorCode errorCode_;
- HttpStatus httpStatus_;
-
- public:
- OrthancException(ErrorCode errorCode) :
- errorCode_(errorCode),
- httpStatus_(ConvertErrorCodeToHttpStatus(errorCode))
- {
- }
-
- OrthancException(ErrorCode errorCode,
- HttpStatus httpStatus) :
- errorCode_(errorCode),
- httpStatus_(httpStatus)
- {
- }
-
- ErrorCode GetErrorCode() const
- {
- return errorCode_;
- }
-
- HttpStatus GetHttpStatus() const
- {
- return httpStatus_;
- }
-
- const char* What() const
- {
- return EnumerationToString(errorCode_);
- }
- };
+ ServerBarrierEvent ServerBarrier(const bool& stopFlag);
+
+ ServerBarrierEvent ServerBarrier();
+
+ void ReadFile(std::string& content,
+ const std::string& path);
+
+ bool ReadHeader(std::string& header,
+ const std::string& path,
+ size_t headerSize);
+
+ void WriteFile(const void* content,
+ size_t size,
+ const std::string& path);
+
+ void WriteFile(const std::string& content,
+ const std::string& path);
+
+ void RemoveFile(const std::string& path);
+
+ uint64_t GetFileSize(const std::string& path);
+
+ void MakeDirectory(const std::string& path);
+
+ bool IsExistingFile(const std::string& path);
+
+ std::string GetPathToExecutable();
+
+ std::string GetDirectoryOfExecutable();
+
+ void ExecuteSystemCommand(const std::string& command,
+ const std::vector<std::string>& arguments);
+
+ int GetProcessId();
+
+ bool IsRegularFile(const std::string& path);
+
+ FILE* OpenFile(const std::string& path,
+ FileMode mode);
+
+ std::string GenerateUuid();
+
+#if BOOST_HAS_DATE_TIME == 1
+ std::string GetNowIsoString();
+
+ void GetNowDicom(std::string& date,
+ std::string& time);
+#endif
+ }
}
diff --git a/Core/Uuid.h b/Core/TemporaryFile.cpp
similarity index 58%
rename from Core/Uuid.h
rename to Core/TemporaryFile.cpp
index 88819a3..955489b 100644
--- a/Core/Uuid.h
+++ b/Core/TemporaryFile.cpp
@@ -30,57 +30,65 @@
**/
-#pragma once
-
-#include <string>
-
-/**
- * GUID vs. UUID
- * The simple answer is: no difference, they are the same thing. Treat
- * them as a 16 byte (128 bits) value that is used as a unique
- * value. In Microsoft-speak they are called GUIDs, but call them
- * UUIDs when not using Microsoft-speak.
- * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid
- **/
+#include "PrecompiledHeaders.h"
+#include "TemporaryFile.h"
+#include "SystemToolbox.h"
#include "Toolbox.h"
+#include <boost/filesystem.hpp>
+
namespace Orthanc
{
- namespace Toolbox
+ static std::string CreateTemporaryPath(const char* extension)
{
- std::string GenerateUuid();
-
- bool IsUuid(const std::string& str);
+#if BOOST_HAS_FILESYSTEM_V3 == 1
+ boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path();
+#elif defined(__linux__)
+ boost::filesystem::path tmpDir("/tmp");
+#else
+#error Support your platform here
+#endif
- bool StartsWithUuid(const std::string& str);
+ // We use UUID to create unique path to temporary files
+ std::string filename = "Orthanc-" + Orthanc::SystemToolbox::GenerateUuid();
- class TemporaryFile
+ if (extension != NULL)
{
- private:
- std::string path_;
+ filename.append(extension);
+ }
- public:
- TemporaryFile();
+ tmpDir /= filename;
+ return tmpDir.string();
+ }
- TemporaryFile(const char* extension);
- ~TemporaryFile();
+ TemporaryFile::TemporaryFile() :
+ path_(CreateTemporaryPath(NULL))
+ {
+ }
- const std::string& GetPath() const
- {
- return path_;
- }
- void Write(const std::string& content)
- {
- Toolbox::WriteFile(content, path_);
- }
+ TemporaryFile::TemporaryFile(const char* extension) :
+ path_(CreateTemporaryPath(extension))
+ {
+ }
- void Read(std::string& content) const
- {
- Toolbox::ReadFile(content, path_);
- }
- };
+
+ TemporaryFile::~TemporaryFile()
+ {
+ boost::filesystem::remove(path_);
+ }
+
+
+ void TemporaryFile::Write(const std::string& content)
+ {
+ SystemToolbox::WriteFile(content, path_);
+ }
+
+
+ void TemporaryFile::Read(std::string& content) const
+ {
+ SystemToolbox::ReadFile(content, path_);
}
}
diff --git a/Core/Images/JpegReader.h b/Core/TemporaryFile.h
similarity index 77%
copy from Core/Images/JpegReader.h
copy to Core/TemporaryFile.h
index 5cb5551..1dd4f73 100644
--- a/Core/Images/JpegReader.h
+++ b/Core/TemporaryFile.h
@@ -32,26 +32,37 @@
#pragma once
-#include "ImageAccessor.h"
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
+#if ORTHANC_SANDBOXED == 1
+# error The class TemporaryFile cannot be used in sandboxed environments
+#endif
#include <string>
-#include <boost/noncopyable.hpp>
namespace Orthanc
{
- class JpegReader :
- public ImageAccessor,
- public boost::noncopyable
+ class TemporaryFile
{
private:
- std::string content_;
+ std::string path_;
public:
- void ReadFromFile(const std::string& filename);
+ TemporaryFile();
+
+ TemporaryFile(const char* extension);
+
+ ~TemporaryFile();
+
+ const std::string& GetPath() const
+ {
+ return path_;
+ }
- void ReadFromMemory(const void* buffer,
- size_t size);
+ void Write(const std::string& content);
- void ReadFromMemory(const std::string& buffer);
+ void Read(std::string& content) const;
};
}
diff --git a/Core/Toolbox.cpp b/Core/Toolbox.cpp
index 4990204..cb9bcb2 100644
--- a/Core/Toolbox.cpp
+++ b/Core/Toolbox.cpp
@@ -36,57 +36,31 @@
#include "OrthancException.h"
#include "Logging.h"
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/locale.hpp>
+#include <boost/uuid/sha1.hpp>
+
#include <string>
#include <stdint.h>
#include <string.h>
-#include <boost/filesystem.hpp>
-#include <boost/filesystem/fstream.hpp>
-#include <boost/uuid/sha1.hpp>
-#include <boost/lexical_cast.hpp>
#include <algorithm>
#include <ctype.h>
-#if BOOST_HAS_DATE_TIME == 1
-#include <boost/date_time/posix_time/posix_time.hpp>
-#endif
-
#if BOOST_HAS_REGEX == 1
-#include <boost/regex.hpp>
-#endif
-
-#if defined(_WIN32)
-#include <windows.h>
-#include <process.h> // For "_spawnvp()" and "_getpid()"
-#else
-#include <unistd.h> // For "execvp()"
-#include <sys/wait.h> // For "waitpid()"
-#endif
-
-#if defined(__APPLE__) && defined(__MACH__)
-#include <mach-o/dyld.h> /* _NSGetExecutablePath */
-#include <limits.h> /* PATH_MAX */
-#endif
-
-#if defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
-#include <limits.h> /* PATH_MAX */
-#include <signal.h>
-#include <unistd.h>
+# include <boost/regex.hpp>
#endif
#if BOOST_HAS_LOCALE != 1
-#error Since version 0.7.6, Orthanc entirely relies on boost::locale
+# error Since version 0.7.6, Orthanc entirely relies on boost::locale
#endif
-#include <boost/locale.hpp>
-
-
-#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
-#include "../Resources/ThirdParty/md5/md5.h"
+#if ORTHANC_ENABLE_MD5 == 1
+# include "../Resources/ThirdParty/md5/md5.h"
#endif
-
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
-#include "../Resources/ThirdParty/base64/base64.h"
+#if ORTHANC_ENABLE_BASE64 == 1
+# include "../Resources/ThirdParty/base64/base64.h"
#endif
@@ -103,42 +77,24 @@ extern "C"
#endif
-#if ORTHANC_PUGIXML_ENABLED == 1
-#include "ChunkedBuffer.h"
-#include <pugixml.hpp>
+#if defined(_WIN32)
+# include <windows.h> // For ::Sleep
#endif
-namespace Orthanc
-{
- static bool finish_;
- static ServerBarrierEvent barrierEvent_;
-
-#if defined(_WIN32)
- static BOOL WINAPI ConsoleControlHandler(DWORD dwCtrlType)
- {
- // http://msdn.microsoft.com/en-us/library/ms683242(v=vs.85).aspx
- finish_ = true;
- return true;
- }
-#else
- static void SignalHandler(int signal)
- {
- if (signal == SIGHUP)
- {
- barrierEvent_ = ServerBarrierEvent_Reload;
- }
-
- finish_ = true;
- }
+#if ORTHANC_ENABLE_PUGIXML == 1
+# include "ChunkedBuffer.h"
+# include <pugixml.hpp>
#endif
+namespace Orthanc
+{
void Toolbox::USleep(uint64_t microSeconds)
{
#if defined(_WIN32)
::Sleep(static_cast<DWORD>(microSeconds / static_cast<uint64_t>(1000)));
-#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
+#elif defined(__linux__) || defined(__APPLE__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__) || defined(__native_client__)
usleep(microSeconds);
#else
#error Support your platform here
@@ -146,50 +102,6 @@ namespace Orthanc
}
- static ServerBarrierEvent ServerBarrierInternal(const bool* stopFlag)
- {
-#if defined(_WIN32)
- SetConsoleCtrlHandler(ConsoleControlHandler, true);
-#else
- signal(SIGINT, SignalHandler);
- signal(SIGQUIT, SignalHandler);
- signal(SIGTERM, SignalHandler);
- signal(SIGHUP, SignalHandler);
-#endif
-
- // Active loop that awakens every 100ms
- finish_ = false;
- barrierEvent_ = ServerBarrierEvent_Stop;
- while (!(*stopFlag || finish_))
- {
- Toolbox::USleep(100 * 1000);
- }
-
-#if defined(_WIN32)
- SetConsoleCtrlHandler(ConsoleControlHandler, false);
-#else
- signal(SIGINT, NULL);
- signal(SIGQUIT, NULL);
- signal(SIGTERM, NULL);
- signal(SIGHUP, NULL);
-#endif
-
- return barrierEvent_;
- }
-
-
- ServerBarrierEvent Toolbox::ServerBarrier(const bool& stopFlag)
- {
- return ServerBarrierInternal(&stopFlag);
- }
-
- ServerBarrierEvent Toolbox::ServerBarrier()
- {
- const bool stopFlag = false;
- return ServerBarrierInternal(&stopFlag);
- }
-
-
void Toolbox::ToUpperCase(std::string& s)
{
std::transform(s.begin(), s.end(), s.begin(), toupper);
@@ -217,134 +129,6 @@ namespace Orthanc
}
- static std::streamsize GetStreamSize(std::istream& f)
- {
- // http://www.cplusplus.com/reference/iostream/istream/tellg/
- f.seekg(0, std::ios::end);
- std::streamsize size = f.tellg();
- f.seekg(0, std::ios::beg);
-
- return size;
- }
-
-
- void Toolbox::ReadFile(std::string& content,
- const std::string& path)
- {
- if (!IsRegularFile(path))
- {
- LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
- throw OrthancException(ErrorCode_RegularFileExpected);
- }
-
- boost::filesystem::ifstream f;
- f.open(path, std::ifstream::in | std::ifstream::binary);
- if (!f.good())
- {
- throw OrthancException(ErrorCode_InexistentFile);
- }
-
- std::streamsize size = GetStreamSize(f);
- content.resize(size);
- if (size != 0)
- {
- f.read(reinterpret_cast<char*>(&content[0]), size);
- }
-
- f.close();
- }
-
-
- bool Toolbox::ReadHeader(std::string& header,
- const std::string& path,
- size_t headerSize)
- {
- if (!IsRegularFile(path))
- {
- LOG(ERROR) << std::string("The path does not point to a regular file: ") << path;
- throw OrthancException(ErrorCode_RegularFileExpected);
- }
-
- boost::filesystem::ifstream f;
- f.open(path, std::ifstream::in | std::ifstream::binary);
- if (!f.good())
- {
- throw OrthancException(ErrorCode_InexistentFile);
- }
-
- bool full = true;
-
- {
- std::streamsize size = GetStreamSize(f);
- if (size <= 0)
- {
- headerSize = 0;
- full = false;
- }
- else if (static_cast<size_t>(size) < headerSize)
- {
- headerSize = size; // Truncate to the size of the file
- full = false;
- }
- }
-
- header.resize(headerSize);
- if (headerSize != 0)
- {
- f.read(reinterpret_cast<char*>(&header[0]), headerSize);
- }
-
- f.close();
-
- return full;
- }
-
-
- void Toolbox::WriteFile(const void* content,
- size_t size,
- const std::string& path)
- {
- boost::filesystem::ofstream f;
- f.open(path, std::ofstream::binary);
- if (!f.good())
- {
- throw OrthancException(ErrorCode_CannotWriteFile);
- }
-
- if (size != 0)
- {
- f.write(reinterpret_cast<const char*>(content), size);
- }
-
- f.close();
- }
-
-
- void Toolbox::WriteFile(const std::string& content,
- const std::string& path)
- {
- WriteFile(content.size() > 0 ? content.c_str() : NULL,
- content.size(), path);
- }
-
-
- void Toolbox::RemoveFile(const std::string& path)
- {
- if (boost::filesystem::exists(path))
- {
- if (IsRegularFile(path))
- {
- boost::filesystem::remove(path);
- }
- else
- {
- throw OrthancException(ErrorCode_RegularFileExpected);
- }
- }
- }
-
-
-
void Toolbox::SplitUriComponents(UriComponents& components,
const std::string& uri)
{
@@ -512,21 +296,7 @@ namespace Orthanc
}
-
- uint64_t Toolbox::GetFileSize(const std::string& path)
- {
- try
- {
- return static_cast<uint64_t>(boost::filesystem::file_size(path));
- }
- catch (boost::filesystem::filesystem_error&)
- {
- throw OrthancException(ErrorCode_InexistentFile);
- }
- }
-
-
-#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
+#if ORTHANC_ENABLE_MD5 == 1
static char GetHexadecimalCharacter(uint8_t value)
{
assert(value < 16);
@@ -583,7 +353,7 @@ namespace Orthanc
#endif
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
void Toolbox::EncodeBase64(std::string& result,
const std::string& data)
{
@@ -642,60 +412,6 @@ namespace Orthanc
#endif
-
-#if defined(_WIN32)
- static std::string GetPathToExecutableInternal()
- {
- // Yes, this is ugly, but there is no simple way to get the
- // required buffer size, so we use a big constant
- std::vector<char> buffer(32768);
- /*int bytes =*/ GetModuleFileNameA(NULL, &buffer[0], static_cast<DWORD>(buffer.size() - 1));
- return std::string(&buffer[0]);
- }
-
-#elif defined(__linux__) || defined(__FreeBSD_kernel__) || defined(__FreeBSD__)
- static std::string GetPathToExecutableInternal()
- {
- std::vector<char> buffer(PATH_MAX + 1);
- ssize_t bytes = readlink("/proc/self/exe", &buffer[0], buffer.size() - 1);
- if (bytes == 0)
- {
- throw OrthancException(ErrorCode_PathToExecutable);
- }
-
- return std::string(&buffer[0]);
- }
-
-#elif defined(__APPLE__) && defined(__MACH__)
- static std::string GetPathToExecutableInternal()
- {
- char pathbuf[PATH_MAX + 1];
- unsigned int bufsize = static_cast<int>(sizeof(pathbuf));
-
- _NSGetExecutablePath( pathbuf, &bufsize);
-
- return std::string(pathbuf);
- }
-
-#else
-#error Support your platform here
-#endif
-
-
- std::string Toolbox::GetPathToExecutable()
- {
- boost::filesystem::path p(GetPathToExecutableInternal());
- return boost::filesystem::absolute(p).string();
- }
-
-
- std::string Toolbox::GetDirectoryOfExecutable()
- {
- boost::filesystem::path p(GetPathToExecutableInternal());
- return boost::filesystem::absolute(p.parent_path()).string();
- }
-
-
static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding)
{
switch (sourceEncoding)
@@ -820,6 +536,23 @@ namespace Orthanc
}
+ bool Toolbox::IsAsciiString(const void* data,
+ size_t size)
+ {
+ const uint8_t* p = reinterpret_cast<const uint8_t*>(data);
+
+ for (size_t i = 0; i < size; i++, p++)
+ {
+ if (*p > 127 || (*p != 0 && iscntrl(*p)))
+ {
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
std::string Toolbox::ConvertToAscii(const std::string& source)
{
std::string result;
@@ -956,30 +689,6 @@ namespace Orthanc
}
-#if BOOST_HAS_DATE_TIME == 1
- std::string Toolbox::GetNowIsoString()
- {
- boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
- return boost::posix_time::to_iso_string(now);
- }
-
- void Toolbox::GetNowDicom(std::string& date,
- std::string& time)
- {
- boost::posix_time::ptime now = boost::posix_time::second_clock::local_time();
- tm tm = boost::posix_time::to_tm(now);
-
- char s[32];
- sprintf(s, "%04d%02d%02d", tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
- date.assign(s);
-
- // TODO milliseconds
- sprintf(s, "%02d%02d%02d.%06d", tm.tm_hour, tm.tm_min, tm.tm_sec, 0);
- time.assign(s);
- }
-#endif
-
-
std::string Toolbox::StripSpaces(const std::string& source)
{
size_t first = 0;
@@ -1137,32 +846,7 @@ namespace Orthanc
}
- void Toolbox::MakeDirectory(const std::string& path)
- {
- if (boost::filesystem::exists(path))
- {
- if (!boost::filesystem::is_directory(path))
- {
- throw OrthancException(ErrorCode_DirectoryOverFile);
- }
- }
- else
- {
- if (!boost::filesystem::create_directories(path))
- {
- throw OrthancException(ErrorCode_MakeDirectory);
- }
- }
- }
-
-
- bool Toolbox::IsExistingFile(const std::string& path)
- {
- return boost::filesystem::exists(path);
- }
-
-
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
class ChunkedBufferWriter : public pugi::xml_writer
{
private:
@@ -1284,64 +968,6 @@ namespace Orthanc
#endif
- void Toolbox::ExecuteSystemCommand(const std::string& command,
- const std::vector<std::string>& arguments)
- {
- // Convert the arguments as a C array
- std::vector<char*> args(arguments.size() + 2);
-
- args.front() = const_cast<char*>(command.c_str());
-
- for (size_t i = 0; i < arguments.size(); i++)
- {
- args[i + 1] = const_cast<char*>(arguments[i].c_str());
- }
-
- args.back() = NULL;
-
- int status;
-
-#if defined(_WIN32)
- // http://msdn.microsoft.com/en-us/library/275khfab.aspx
- status = static_cast<int>(_spawnvp(_P_OVERLAY, command.c_str(), &args[0]));
-
-#else
- int pid = fork();
-
- if (pid == -1)
- {
- // Error in fork()
-#if ORTHANC_ENABLE_LOGGING == 1
- LOG(ERROR) << "Cannot fork a child process";
-#endif
-
- throw OrthancException(ErrorCode_SystemCommand);
- }
- else if (pid == 0)
- {
- // Execute the system command in the child process
- execvp(command.c_str(), &args[0]);
-
- // We should never get here
- _exit(1);
- }
- else
- {
- // Wait for the system command to exit
- waitpid(pid, &status, 0);
- }
-#endif
-
- if (status != 0)
- {
-#if ORTHANC_ENABLE_LOGGING == 1
- LOG(ERROR) << "System command failed with status code " << status;
-#endif
-
- throw OrthancException(ErrorCode_SystemCommand);
- }
- }
-
bool Toolbox::IsInteger(const std::string& str)
{
@@ -1449,64 +1075,6 @@ namespace Orthanc
return str.compare(0, prefix.size(), prefix) == 0;
}
}
-
-
- int Toolbox::GetProcessId()
- {
-#if defined(_WIN32)
- return static_cast<int>(_getpid());
-#else
- return static_cast<int>(getpid());
-#endif
- }
-
-
- bool Toolbox::IsRegularFile(const std::string& path)
- {
- namespace fs = boost::filesystem;
-
- try
- {
- if (fs::exists(path))
- {
- fs::file_status status = fs::status(path);
- return (status.type() == boost::filesystem::regular_file ||
- status.type() == boost::filesystem::reparse_file); // Fix BitBucket issue #11
- }
- }
- catch (fs::filesystem_error&)
- {
- }
-
- return false;
- }
-
-
- FILE* Toolbox::OpenFile(const std::string& path,
- FileMode mode)
- {
-#if defined(_WIN32)
- // TODO Deal with special characters by converting to the current locale
-#endif
-
- const char* m;
- switch (mode)
- {
- case FileMode_ReadBinary:
- m = "rb";
- break;
-
- case FileMode_WriteBinary:
- m = "wb";
- break;
-
- default:
- throw OrthancException(ErrorCode_ParameterOutOfRange);
- }
-
- return fopen(path.c_str(), m);
- }
-
static bool IsUnreservedCharacter(char c)
@@ -1564,5 +1132,134 @@ namespace Orthanc
target.push_back(b < 10 ? b + '0' : b - 10 + 'A');
}
}
- }
+ }
+
+
+ static bool HasField(const Json::Value& json,
+ const std::string& key,
+ Json::ValueType expectedType)
+ {
+ if (json.type() != Json::objectValue ||
+ !json.isMember(key))
+ {
+ return false;
+ }
+ else if (json[key].type() == expectedType)
+ {
+ return true;
+ }
+ else
+ {
+ throw OrthancException(ErrorCode_BadParameterType);
+ }
+ }
+
+
+ std::string Toolbox::GetJsonStringField(const Json::Value& json,
+ const std::string& key,
+ const std::string& defaultValue)
+ {
+ if (HasField(json, key, Json::stringValue))
+ {
+ return json[key].asString();
+ }
+ else
+ {
+ return defaultValue;
+ }
+ }
+
+
+ bool Toolbox::GetJsonBooleanField(const ::Json::Value& json,
+ const std::string& key,
+ bool defaultValue)
+ {
+ if (HasField(json, key, Json::booleanValue))
+ {
+ return json[key].asBool();
+ }
+ else
+ {
+ return defaultValue;
+ }
+ }
+
+
+ int Toolbox::GetJsonIntegerField(const ::Json::Value& json,
+ const std::string& key,
+ int defaultValue)
+ {
+ if (HasField(json, key, Json::intValue))
+ {
+ return json[key].asInt();
+ }
+ else
+ {
+ return defaultValue;
+ }
+ }
+
+
+ unsigned int Toolbox::GetJsonUnsignedIntegerField(const ::Json::Value& json,
+ const std::string& key,
+ unsigned int defaultValue)
+ {
+ int v = GetJsonIntegerField(json, key, defaultValue);
+
+ if (v < 0)
+ {
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+ else
+ {
+ return static_cast<unsigned int>(v);
+ }
+ }
+
+
+ bool Toolbox::IsUuid(const std::string& str)
+ {
+ if (str.size() != 36)
+ {
+ return false;
+ }
+
+ for (size_t i = 0; i < str.length(); i++)
+ {
+ if (i == 8 || i == 13 || i == 18 || i == 23)
+ {
+ if (str[i] != '-')
+ return false;
+ }
+ else
+ {
+ if (!isalnum(str[i]))
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ bool Toolbox::StartsWithUuid(const std::string& str)
+ {
+ if (str.size() < 36)
+ {
+ return false;
+ }
+
+ if (str.size() == 36)
+ {
+ return IsUuid(str);
+ }
+
+ assert(str.size() > 36);
+ if (!isspace(str[36]))
+ {
+ return false;
+ }
+
+ return IsUuid(str.substr(0, 36));
+ }
}
diff --git a/Core/Toolbox.h b/Core/Toolbox.h
index cb67473..d32777a 100644
--- a/Core/Toolbox.h
+++ b/Core/Toolbox.h
@@ -39,6 +39,35 @@
#include <string>
#include <json/json.h>
+
+#if !defined(ORTHANC_ENABLE_BASE64)
+# error The macro ORTHANC_ENABLE_BASE64 must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_MD5)
+# error The macro ORTHANC_ENABLE_MD5 must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_PUGIXML)
+# error The macro ORTHANC_ENABLE_PUGIXML must be defined
+#endif
+
+#if !defined(BOOST_HAS_REGEX)
+# error The macro BOOST_HAS_REGEX must be defined
+#endif
+
+
+/**
+ * NOTE: GUID vs. UUID
+ * The simple answer is: no difference, they are the same thing. Treat
+ * them as a 16 byte (128 bits) value that is used as a unique
+ * value. In Microsoft-speak they are called GUIDs, but call them
+ * UUIDs when not using Microsoft-speak.
+ * http://stackoverflow.com/questions/246930/is-there-any-difference-between-a-guid-and-a-uuid
+ **/
+
+
+
namespace Orthanc
{
typedef std::vector<std::string> UriComponents;
@@ -49,9 +78,7 @@ namespace Orthanc
namespace Toolbox
{
- ServerBarrierEvent ServerBarrier(const bool& stopFlag);
-
- ServerBarrierEvent ServerBarrier();
+ void USleep(uint64_t microSeconds);
void ToUpperCase(std::string& s); // Inplace version
@@ -63,24 +90,6 @@ namespace Orthanc
void ToLowerCase(std::string& result,
const std::string& source);
- void ReadFile(std::string& content,
- const std::string& path);
-
- bool ReadHeader(std::string& header,
- const std::string& path,
- size_t headerSize);
-
- void WriteFile(const std::string& content,
- const std::string& path);
-
- void WriteFile(const void* content,
- size_t size,
- const std::string& path);
-
- void USleep(uint64_t microSeconds);
-
- void RemoveFile(const std::string& path);
-
void SplitUriComponents(UriComponents& components,
const std::string& uri);
@@ -96,9 +105,7 @@ namespace Orthanc
std::string FlattenUri(const UriComponents& components,
size_t fromLevel = 0);
- uint64_t GetFileSize(const std::string& path);
-
-#if !defined(ORTHANC_ENABLE_MD5) || ORTHANC_ENABLE_MD5 == 1
+#if ORTHANC_ENABLE_MD5 == 1
void ComputeMD5(std::string& result,
const std::string& data);
@@ -119,7 +126,7 @@ namespace Orthanc
bool IsSHA1(const std::string& s);
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
+#if ORTHANC_ENABLE_BASE64 == 1
void DecodeBase64(std::string& result,
const std::string& data);
@@ -137,27 +144,19 @@ namespace Orthanc
const std::string& content);
#endif
- std::string GetPathToExecutable();
-
- std::string GetDirectoryOfExecutable();
-
std::string ConvertToUtf8(const std::string& source,
Encoding sourceEncoding);
std::string ConvertFromUtf8(const std::string& source,
Encoding targetEncoding);
+ bool IsAsciiString(const void* data,
+ size_t size);
+
std::string ConvertToAscii(const std::string& source);
std::string StripSpaces(const std::string& source);
-#if BOOST_HAS_DATE_TIME == 1
- std::string GetNowIsoString();
-
- void GetNowDicom(std::string& date,
- std::string& time);
-#endif
-
// In-place percent-decoding for URL
void UrlDecode(std::string& s);
@@ -171,20 +170,13 @@ namespace Orthanc
const std::string& source,
char separator);
- void MakeDirectory(const std::string& path);
-
- bool IsExistingFile(const std::string& path);
-
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
void JsonToXml(std::string& target,
const Json::Value& source,
const std::string& rootElement = "root",
const std::string& arrayElement = "item");
#endif
- void ExecuteSystemCommand(const std::string& command,
- const std::vector<std::string>& arguments);
-
bool IsInteger(const std::string& str);
void CopyJsonWithoutComments(Json::Value& target,
@@ -193,14 +185,27 @@ namespace Orthanc
bool StartsWith(const std::string& str,
const std::string& prefix);
- int GetProcessId();
+ void UriEncode(std::string& target,
+ const std::string& source);
+
+ std::string GetJsonStringField(const ::Json::Value& json,
+ const std::string& key,
+ const std::string& defaultValue);
- bool IsRegularFile(const std::string& path);
+ bool GetJsonBooleanField(const ::Json::Value& json,
+ const std::string& key,
+ bool defaultValue);
- FILE* OpenFile(const std::string& path,
- FileMode mode);
+ int GetJsonIntegerField(const ::Json::Value& json,
+ const std::string& key,
+ int defaultValue);
- void UriEncode(std::string& target,
- const std::string& source);
+ unsigned int GetJsonUnsignedIntegerField(const ::Json::Value& json,
+ const std::string& key,
+ unsigned int defaultValue);
+
+ bool IsUuid(const std::string& str);
+
+ bool StartsWithUuid(const std::string& str);
}
}
diff --git a/Core/Uuid.cpp b/Core/Uuid.cpp
deleted file mode 100644
index 8681095..0000000
--- a/Core/Uuid.cpp
+++ /dev/null
@@ -1,162 +0,0 @@
-/**
- * Orthanc - A Lightweight, RESTful DICOM Store
- * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
- * Department, University Hospital of Liege, Belgium
- *
- * This program is free software: you can redistribute it and/or
- * modify it under the terms of the GNU General Public License as
- * published by the Free Software Foundation, either version 3 of the
- * License, or (at your option) any later version.
- *
- * In addition, as a special exception, the copyright holders of this
- * program give permission to link the code of its release with the
- * OpenSSL project's "OpenSSL" library (or with modified versions of it
- * that use the same license as the "OpenSSL" library), and distribute
- * the linked executables. You must obey the GNU General Public License
- * in all respects for all of the code used other than "OpenSSL". If you
- * modify file(s) with this exception, you may extend this exception to
- * your version of the file(s), but you are not obligated to do so. If
- * you do not wish to do so, delete this exception statement from your
- * version. If you delete this exception statement from all source files
- * in the program, then also delete it here.
- *
- * This program is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
- * General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see <http://www.gnu.org/licenses/>.
- **/
-
-
-#include "PrecompiledHeaders.h"
-#include "Uuid.h"
-
-// http://stackoverflow.com/a/1626302
-
-extern "C"
-{
-#ifdef WIN32
-#include <rpc.h>
-#else
-#include <uuid/uuid.h>
-#endif
-}
-
-#include <boost/filesystem.hpp>
-
-namespace Orthanc
-{
- namespace Toolbox
- {
- std::string GenerateUuid()
- {
-#ifdef WIN32
- UUID uuid;
- UuidCreate ( &uuid );
-
- unsigned char * str;
- UuidToStringA ( &uuid, &str );
-
- std::string s( ( char* ) str );
-
- RpcStringFreeA ( &str );
-#else
- uuid_t uuid;
- uuid_generate_random ( uuid );
- char s[37];
- uuid_unparse ( uuid, s );
-#endif
- return s;
- }
-
-
- bool IsUuid(const std::string& str)
- {
- if (str.size() != 36)
- {
- return false;
- }
-
- for (size_t i = 0; i < str.length(); i++)
- {
- if (i == 8 || i == 13 || i == 18 || i == 23)
- {
- if (str[i] != '-')
- return false;
- }
- else
- {
- if (!isalnum(str[i]))
- return false;
- }
- }
-
- return true;
- }
-
-
- bool StartsWithUuid(const std::string& str)
- {
- if (str.size() < 36)
- {
- return false;
- }
-
- if (str.size() == 36)
- {
- return IsUuid(str);
- }
-
- assert(str.size() > 36);
- if (!isspace(str[36]))
- {
- return false;
- }
-
- return IsUuid(str.substr(0, 36));
- }
-
-
- static std::string CreateTemporaryPath(const char* extension)
- {
-#if BOOST_HAS_FILESYSTEM_V3 == 1
- boost::filesystem::path tmpDir = boost::filesystem::temp_directory_path();
-#elif defined(__linux__)
- boost::filesystem::path tmpDir("/tmp");
-#else
-#error Support your platform here
-#endif
-
- // We use UUID to create unique path to temporary files
- std::string filename = "Orthanc-" + Orthanc::Toolbox::GenerateUuid();
-
- if (extension != NULL)
- {
- filename.append(extension);
- }
-
- tmpDir /= filename;
- return tmpDir.string();
- }
-
-
- TemporaryFile::TemporaryFile() :
- path_(CreateTemporaryPath(NULL))
- {
- }
-
-
- TemporaryFile::TemporaryFile(const char* extension) :
- path_(CreateTemporaryPath(extension))
- {
- }
-
-
- TemporaryFile::~TemporaryFile()
- {
- boost::filesystem::remove(path_);
- }
- }
-}
diff --git a/Core/WebServiceParameters.cpp b/Core/WebServiceParameters.cpp
index 52e0ea6..cef2e26 100644
--- a/Core/WebServiceParameters.cpp
+++ b/Core/WebServiceParameters.cpp
@@ -37,6 +37,10 @@
#include "../Core/Toolbox.h"
#include "../Core/OrthancException.h"
+#if ORTHANC_SANDBOXED == 0
+# include "../Core/SystemToolbox.h"
+#endif
+
#include <cassert>
namespace Orthanc
@@ -57,6 +61,7 @@ namespace Orthanc
}
+#if ORTHANC_SANDBOXED == 0
void WebServiceParameters::SetClientCertificate(const std::string& certificateFile,
const std::string& certificateKeyFile,
const std::string& certificateKeyPassword)
@@ -66,14 +71,14 @@ namespace Orthanc
throw OrthancException(ErrorCode_ParameterOutOfRange);
}
- if (!Toolbox::IsRegularFile(certificateFile))
+ if (!SystemToolbox::IsRegularFile(certificateFile))
{
LOG(ERROR) << "Cannot open certificate file: " << certificateFile;
throw OrthancException(ErrorCode_InexistentFile);
}
if (!certificateKeyFile.empty() &&
- !Toolbox::IsRegularFile(certificateKeyFile))
+ !SystemToolbox::IsRegularFile(certificateKeyFile))
{
LOG(ERROR) << "Cannot open key file: " << certificateKeyFile;
throw OrthancException(ErrorCode_InexistentFile);
@@ -84,6 +89,7 @@ namespace Orthanc
certificateKeyFile_ = certificateKeyFile;
certificateKeyPassword_ = certificateKeyPassword;
}
+#endif
static void AddTrailingSlash(std::string& url)
@@ -171,12 +177,14 @@ namespace Orthanc
SetUsername(GetStringMember(peer, "Username", ""));
SetPassword(GetStringMember(peer, "Password", ""));
+#if ORTHANC_SANDBOXED == 0
if (peer.isMember("CertificateFile"))
{
SetClientCertificate(GetStringMember(peer, "CertificateFile", ""),
GetStringMember(peer, "CertificateKeyFile", ""),
GetStringMember(peer, "CertificateKeyPassword", ""));
}
+#endif
if (peer.isMember("Pkcs11"))
{
diff --git a/Core/WebServiceParameters.h b/Core/WebServiceParameters.h
index 40d6cf9..b6b373f 100644
--- a/Core/WebServiceParameters.h
+++ b/Core/WebServiceParameters.h
@@ -32,6 +32,10 @@
#pragma once
+#if !defined(ORTHANC_SANDBOXED)
+# error The macro ORTHANC_SANDBOXED must be defined
+#endif
+
#include <string>
#include <json/json.h>
@@ -88,9 +92,11 @@ namespace Orthanc
void ClearClientCertificate();
+#if ORTHANC_SANDBOXED == 0
void SetClientCertificate(const std::string& certificateFile,
const std::string& certificateKeyFile,
const std::string& certificateKeyPassword);
+#endif
const std::string& GetCertificateFile() const
{
diff --git a/DarwinCompilation.txt b/DarwinCompilation.txt
index 2e584a2..62244d7 100644
--- a/DarwinCompilation.txt
+++ b/DarwinCompilation.txt
@@ -31,7 +31,9 @@ Prepare the build with CMake
# cmake -GXcode -DCMAKE_OSX_DEPLOYMENT_TARGET=10.8 -DSTATIC_BUILD=ON -DSTANDALONE_BUILD=ON -DALLOW_DOWNLOADS=ON ~/Orthanc
NB: Adapt the value of "CMAKE_OSX_DEPLOYMENT_TARGET" with respect to
-your version of XCode.
+your version of OS X. This version can obtained by typing:
+
+# sw_vers
Build the Debug version of Orthanc
@@ -47,6 +49,6 @@ Build the Release version of Orthanc
------------------------------------
# xcodebuild -configuration Release
-# ./Debug/UnitTests
+# ./Release/UnitTests
The binaries of Orthanc are located at "~/OrthancBuild/Release/Orthanc".
diff --git a/INSTALL b/INSTALL
index be97597..33762ab 100644
--- a/INSTALL
+++ b/INSTALL
@@ -51,12 +51,17 @@ WARNING 2: If cmake complains about not being able to uncompress
third-party dependencies, delete the "~/Orthanc/ThirdPartyDownloads/"
folder, then restart cmake.
+WARNING 3: If performance is important to you, make sure to add the
+option "-DCMAKE_BUILD_TYPE=Release" when invoking cmake. Indeed, by
+default, run-time debug assertions are enabled, which can seriously
+impact performance, especially if your Orthanc server stores a lot of
+DICOM instances.
-Native Linux Compilation
-------------------------
-See the file "LinuxCompilation.txt".
+Native GNU/Linux Compilation
+----------------------------
+See the file "LinuxCompilation.txt".
Native OS X Compilation
@@ -85,8 +90,8 @@ NOTES:
-Cross-Compilation for Windows under Linux
------------------------------------------
+Cross-Compilation for Windows under GNU/Linux
+---------------------------------------------
To cross-compile Windows binaries under Linux using MinGW, please use
the following command:
diff --git a/LinuxCompilation.txt b/LinuxCompilation.txt
index 15e7bb2..8c075cb 100644
--- a/LinuxCompilation.txt
+++ b/LinuxCompilation.txt
@@ -1,17 +1,17 @@
This file is a complement to "INSTALL", which contains instructions
-that are specific to Linux.
+that are specific to GNU/Linux.
-Static linking for Linux
-========================
+Static linking for GNU/Linux
+============================
-The most simple way of building Orthanc under Linux consists in
+The most simple way of building Orthanc under GNU/Linux consists in
statically linking against all the third-party dependencies. In this
case, the system-wide libraries will not be used. The build tool
(CMake) will download the sources of all the required packages and
automatically compile them.
-This process should work on any Linux distribution, provided that a
+This process should work on any GNU/Linux distribution, provided that a
C/C++ compiler ("build-essential" in Debian-based systems), the Python
interpreter, CMake, the "unzip" system tool, and the development
package for libuuid ("uuid-dev" in Debian) are installed.
@@ -47,14 +47,14 @@ then run cmake again.
Note 3- To build the documentation, you will have to install doxyen.
-Use system-wide libraries under Linux
-=====================================
+Use system-wide libraries under GNU/Linux
+=========================================
-Under Linux, by default, Orthanc links against the shared libraries of
-your system (the "STATIC_BUILD" option is set to "OFF"). This greatly
-speeds up the compilation. This is also required when building
-packages for Linux distributions. Because using system libraries is
-the default behavior, you just have to use:
+Under GNU/Linux, by default, Orthanc links against the shared
+libraries of your system (the "STATIC_BUILD" option is set to
+"OFF"). This greatly speeds up the compilation. This is also required
+when building packages for GNU/Linux distributions. Because using
+system libraries is the default behavior, you just have to use:
# cd ~/OrthancBuild
# cmake -DCMAKE_BUILD_TYPE=Debug ~/Orthanc
@@ -62,13 +62,14 @@ the default behavior, you just have to use:
Note that to build the documentation, you will have to install doxyen.
-However, on some Linux distributions, it is still required to download
-and static link against some third-party dependencies, e.g. when the
-system-wide library is not shipped or is outdated. Because of
-difference in the packaging of the various Linux distribution, it is
-also sometimes required to fine-tune some options.
+However, on some GNU/Linux distributions, it is still required to
+download and static link against some third-party dependencies,
+e.g. when the system-wide library is not shipped or is
+outdated. Because of difference in the packaging of the various
+GNU/Linux distribution, it is also sometimes required to fine-tune
+some options.
-You will find below build instructions for specific Linux
+You will find below build instructions for specific GNU/Linux
distributions. Distributions tagged by "SUPPORTED" are tested by
Sébastien Jodogne. Distributions tagged by "CONTRIBUTED" come from
Orthanc users.
@@ -183,8 +184,8 @@ SUPPORTED - CentOS 6
-Other Linux distributions?
---------------------------
+Other GNU/Linux distributions?
+------------------------------
Please send us your build instructions (by a mail to
s.jodogne at gmail.com)!
@@ -202,7 +203,7 @@ they might give indications.
Using ccache
============
-Under Linux, you also have the opportunity to use "ccache" to
+Under GNU/Linux, you also have the opportunity to use "ccache" to
dramatically decrease the compilation time when rebuilding
Orthanc. This is especially useful for developers. To this end, you
would use:
diff --git a/NEWS b/NEWS
index ffb4f7a..16a0800 100644
--- a/NEWS
+++ b/NEWS
@@ -2,7 +2,58 @@ Pending changes in the mainline
===============================
-Version 1.1.0 (2016/07/27)
+Version 1.2.0 (2016/12/13)
+==========================
+
+General
+-------
+
+* Handling of private tags/creators in the "Dictionary" configuration option
+* New configuration options: "LoadPrivateDictionary", "DicomScuTimeout" and "DicomScpTimeout"
+* New metadata automatically computed at the instance level: "TransferSyntax" and "SopClassUid"
+
+REST API
+--------
+
+* "/tools/invalidate-tags" to invalidate the JSON summary of all the DICOM files
+ (useful if private tags are registered, or if changing the default encoding)
+* "Permissive" flag for URI "/modalities/{...}/store" to ignore C-STORE transfer errors
+* "Asynchronous" flag for URIs "/modalities/{...}/store" and "/peers/{...}/store"
+ to avoid waiting for the completion of image transfers
+* Possibility to DELETE "dicom-as-json" attachments to reconstruct the JSON summaries
+ (useful if "Dictionary" has changed)
+* "Keep" option for modifications to keep original DICOM identifiers (advanced feature)
+* "/tools/default-encoding" to get or temporarily change the default encoding
+* "/{resource}/{id}/reconstruct" to reconstruct the main DICOM tags, the JSON summary and
+ the metadata of a resource (useful to compute new metadata, or if using "Keep" above)
+
+Plugins
+-------
+
+* New function: "OrthancPluginRegisterPrivateDictionaryTag()" to register private tags
+* More control over client cache in the ServeFolders plugin
+* New C++ help wrappers in "Plugins/Samples/Common/" to read DICOM datasets from REST API
+* New data structure: "OrthancPluginFindMatcher" to match DICOM against C-FIND queries
+
+Maintenance
+-----------
+
+* Fix handling of encodings in C-FIND requests (including for worklists)
+* Use of DCMTK 3.6.1 dictionary of private tags in standalone builds
+* Avoid hard crash if not enough memory (handling of std::bad_alloc)
+* Improved robustness of Orthanc Explorer wrt. query/retrieve (maybe fix issue 24)
+* Fix serious performance issue with C-FIND
+* Fix extraction of the symbolic name of the private tags
+* Performance warning if runtime debug assertions are turned on
+* Improved robustness against files with no PatientID
+* Upgrade to curl 7.50.3 for static and Windows builds
+* Content-Type for JSON documents is now "application/json; charset=utf-8"
+* Ignore "Group Length" tags in C-FIND queries
+* Fix handling of worklist SCP with ReferencedStudySequence and ReferencedPatientSequence
+* Fix handling of Move Originator AET and ID in C-MOVE SCP
+
+
+Version 1.1.0 (2016/06/27)
==========================
General
@@ -17,23 +68,23 @@ REST API
--------
* New URI: "/instances/.../frames/.../raw" to access the raw frames (bypass image decoding)
-* New URI "/modalities/.../move" to issue C-Move SCU requests
+* New URI "/modalities/.../move" to issue C-MOVE SCU requests
* "MoveOriginatorID" can be specified for "/modalities/.../store"
Dicom protocol
--------------
-* Support of optional tags for counting resources in C-Find:
+* Support of optional tags for counting resources in C-FIND:
0008-0061, 0008-0062, 0020-1200, 0020-1202, 0020-1204, 0020-1206, 0020-1208, 0020-1209
-* Support of Move Originator Message ID (0000,1031) in C-Store responses driven by C-Move
+* Support of Move Originator Message ID (0000,1031) in C-STORE responses driven by C-MOVE
Plugins
-------
* Speedup in plugins by removing unnecessary locks
* New callback to filter incoming HTTP requests: OrthancPluginRegisterIncomingHttpRequestFilter()
-* New callback to handle non-worklists C-Find requests: OrthancPluginRegisterFindCallback()
-* New callback to handle C-Move requests: OrthancPluginRegisterMoveCallback()
+* New callback to handle non-worklists C-FIND requests: OrthancPluginRegisterFindCallback()
+* New callback to handle C-MOVE requests: OrthancPluginRegisterMoveCallback()
* New function: "OrthancPluginHttpClient()" to do HTTP requests with full control
* New function: "OrthancPluginGenerateUuid()" to generate a UUID
* More than one custom image decoder can be installed (e.g. to handle different transfer syntaxes)
@@ -41,6 +92,7 @@ Plugins
Lua
---
+* Possibility to dynamically fix outgoing C-FIND requests using "OutgoingFindRequestFilter()"
* Access to the HTTP headers in the "IncomingHttpRequestFilter()" callback
Image decoding
@@ -75,7 +127,7 @@ Maintenance
Version 1.0.0 (2015/12/15)
==========================
-* Lua: "IncomingFindRequestFilter()" to apply filters to incoming C-Find requests
+* Lua: "IncomingFindRequestFilter()" to apply filters to incoming C-FIND requests
* New function in plugin SDK: "OrthancPluginSendMultipartItem2()"
* Fix of DICOMDIR generation with DCMTK 3.6.1, support of encodings
* Fix range search if the lower or upper limit is absent
@@ -296,7 +348,7 @@ Fixes
-----
* Prevent freeze on C-FIND if no DICOM tag is to be returned
-* Fix slow C-STORE SCP on recent versions of Linux, if
+* Fix slow C-STORE SCP on recent versions of GNU/Linux, if
USE_SYSTEM_DCMTK is set to OFF (http://forum.dcmtk.org/viewtopic.php?f=1&t=4009)
* Fix issue 30 (QR response missing "Query/Retrieve Level" (008,0052))
* Fix issue 32 (Cyrillic symbols): Introduction of the "Windows1251" encoding
@@ -517,8 +569,8 @@ Minor changes
* Possibility to disable the HTTP server or the DICOM server
* Automatic computation of MD5 hashes for the stored DICOM files
* Maintenance tool to recover DICOM files compressed by Orthanc
-* The newline characters in the configuration file are fixed for Linux
-* Capture of the SIGTERM signal in Linux
+* The newline characters in the configuration file are fixed for GNU/Linux
+* Capture of the SIGTERM signal in GNU/Linux
Version 0.7.2 (2013/11/08)
diff --git a/OrthancExplorer/explorer.html b/OrthancExplorer/explorer.html
index 90c61cf..fa3d77d 100644
--- a/OrthancExplorer/explorer.html
+++ b/OrthancExplorer/explorer.html
@@ -302,7 +302,7 @@
<div data-role="page" id="query-retrieve" >
<div data-role="header" >
- <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (1/3)</h1>
+ <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (1/4)</h1>
<a href="#find-patients" data-icon="home" class="ui-btn-left" data-direction="reverse">Patients</a>
</div>
<div data-role="content">
@@ -368,7 +368,7 @@
<div data-role="page" id="query-retrieve-2" >
<div data-role="header" >
- <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (2/3)</h1>
+ <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (2/4)</h1>
<a href="#find-patients" data-icon="home" class="ui-btn-left" data-direction="reverse">Patients</a>
<a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
</div>
@@ -381,17 +381,43 @@
<div data-role="page" id="query-retrieve-3" >
<div data-role="header" >
- <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (3/3)</h1>
+ <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (3/4)</h1>
<a href="#find-patients" data-icon="home" class="ui-btn-left" data-direction="reverse">Patients</a>
<a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
</div>
<div data-role="content">
- <ul data-role="listview" data-inset="true" data-filter="true" data-split-icon="arrow-d" data-split-theme="b">
+ <ul data-role="listview" data-inset="true" data-filter="true">
</ul>
</div>
</div>
+ <div data-role="page" id="query-retrieve-4" >
+ <div data-role="header" >
+ <h1><span class="orthanc-name"></span>DICOM Query/Retrieve (4/4)</h1>
+ <a href="#find-patients" data-icon="home" class="ui-btn-left" data-direction="reverse">Patients</a>
+ <a href="#query-retrieve" data-icon="search" class="ui-btn-right" data-direction="reverse">Query/Retrieve</a>
+ </div>
+
+ <div data-role="content">
+ <form data-ajax="false" id="retrieve-form">
+ <div data-role="fieldcontain">
+ <label for="retrieve-target">Target AET:</label>
+ <input type="text" name="retrieve-target" id="retrieve-target"></input>
+ </div>
+
+ <fieldset class="ui-grid-b">
+ <div class="ui-block-a"></div>
+ <div class="ui-block-b">
+ <button id="retrieve-submit" type="submit" data-theme="b">Retrieve</button>
+ </div>
+ <div class="ui-block-c"></div>
+ </fieldset>
+ </form>
+ </div>
+ </div>
+
+
<div id="peer-store" style="display:none;" class="ui-body-c">
<p align="center"><b>Sending to Orthanc peer...</b></p>
<p><img src="libs/images/ajax-loader.gif" alt="" /></p>
diff --git a/OrthancExplorer/explorer.js b/OrthancExplorer/explorer.js
index a1b130b..4d70a7b 100644
--- a/OrthancExplorer/explorer.js
+++ b/OrthancExplorer/explorer.js
@@ -30,6 +30,36 @@ String.prototype.format = function() {
};
+function DeepCopy(obj)
+{
+ return jQuery.extend(true, {}, obj);
+}
+
+
+function ChangePage(page, options)
+{
+ var first = true;
+ if (options) {
+ for (var key in options) {
+ var value = options[key];
+ if (first) {
+ page += '?';
+ first = false;
+ } else {
+ page += '&';
+ }
+
+ page += key + '=' + value;
+ }
+ }
+
+ window.location.replace('explorer.html#' + page);
+ /*$.mobile.changePage('#' + page, {
+ changeHash: true
+ });*/
+}
+
+
function Refresh()
{
if (currentPage == 'patient')
@@ -369,8 +399,10 @@ function SetupAnonymizedOrModifiedFrom(buttonSelector, resource, resourceType, f
function RefreshPatient()
{
if ($.mobile.pageData) {
- GetResource('/patients/' + $.mobile.pageData.uuid, function(patient) {
- GetResource('/patients/' + $.mobile.pageData.uuid + '/studies', function(studies) {
+ var pageData = DeepCopy($.mobile.pageData);
+
+ GetResource('/patients/' + pageData.uuid, function(patient) {
+ GetResource('/patients/' + pageData.uuid + '/studies', function(studies) {
SortOnDicomTag(studies, 'StudyDate', false, true);
$('#patient-info li').remove();
@@ -399,7 +431,7 @@ function RefreshPatient()
// Check whether this patient is protected
$.ajax({
- url: '../patients/' + $.mobile.pageData.uuid + '/protected',
+ url: '../patients/' + pageData.uuid + '/protected',
type: 'GET',
dataType: 'text',
async: false,
@@ -411,7 +443,7 @@ function RefreshPatient()
});
currentPage = 'patient';
- currentUuid = $.mobile.pageData.uuid;
+ currentUuid = pageData.uuid;
});
});
}
@@ -421,9 +453,11 @@ function RefreshPatient()
function RefreshStudy()
{
if ($.mobile.pageData) {
- GetResource('/studies/' + $.mobile.pageData.uuid, function(study) {
+ var pageData = DeepCopy($.mobile.pageData);
+
+ GetResource('/studies/' + pageData.uuid, function(study) {
GetResource('/patients/' + study.ParentPatient, function(patient) {
- GetResource('/studies/' + $.mobile.pageData.uuid + '/series', function(series) {
+ GetResource('/studies/' + pageData.uuid + '/series', function(series) {
SortOnDicomTag(series, 'SeriesDate', false, true);
$('#study .patient-link').attr('href', '#patient?uuid=' + patient.ID);
@@ -451,7 +485,7 @@ function RefreshStudy()
target.listview('refresh');
currentPage = 'study';
- currentUuid = $.mobile.pageData.uuid;
+ currentUuid = pageData.uuid;
});
});
});
@@ -462,10 +496,12 @@ function RefreshStudy()
function RefreshSeries()
{
if ($.mobile.pageData) {
- GetResource('/series/' + $.mobile.pageData.uuid, function(series) {
+ var pageData = DeepCopy($.mobile.pageData);
+
+ GetResource('/series/' + pageData.uuid, function(series) {
GetResource('/studies/' + series.ParentStudy, function(study) {
GetResource('/patients/' + study.ParentPatient, function(patient) {
- GetResource('/series/' + $.mobile.pageData.uuid + '/instances', function(instances) {
+ GetResource('/series/' + pageData.uuid + '/instances', function(instances) {
Sort(instances, function(x) { return x.IndexInSeries; }, true, false);
$('#series .patient-link').attr('href', '#patient?uuid=' + patient.ID);
@@ -492,7 +528,7 @@ function RefreshSeries()
target.listview('refresh');
currentPage = 'series';
- currentUuid = $.mobile.pageData.uuid;
+ currentUuid = pageData.uuid;
});
});
});
@@ -556,7 +592,9 @@ function ConvertForTree(dicom)
function RefreshInstance()
{
if ($.mobile.pageData) {
- GetResource('/instances/' + $.mobile.pageData.uuid, function(instance) {
+ var pageData = DeepCopy($.mobile.pageData);
+
+ GetResource('/instances/' + pageData.uuid, function(instance) {
GetResource('/series/' + instance.ParentSeries, function(series) {
GetResource('/studies/' + series.ParentStudy, function(study) {
GetResource('/patients/' + study.ParentPatient, function(patient) {
@@ -585,7 +623,7 @@ function RefreshInstance()
SetupAnonymizedOrModifiedFrom('#instance-modified-from', instance, 'instance', 'ModifiedFrom');
currentPage = 'instance';
- currentUuid = $.mobile.pageData.uuid;
+ currentUuid = pageData.uuid;
});
});
});
@@ -704,7 +742,9 @@ $('#instance-download-json').live('click', function(e) {
$('#instance-preview').live('click', function(e) {
if ($.mobile.pageData) {
- var pdf = '../instances/' + $.mobile.pageData.uuid + '/pdf';
+ var pageData = DeepCopy($.mobile.pageData);
+
+ var pdf = '../instances/' + pageData.uuid + '/pdf';
$.ajax({
url: pdf,
cache: false,
@@ -712,11 +752,11 @@ $('#instance-preview').live('click', function(e) {
window.location.assign(pdf);
},
error: function() {
- GetResource('/instances/' + $.mobile.pageData.uuid + '/frames', function(frames) {
+ GetResource('/instances/' + pageData.uuid + '/frames', function(frames) {
if (frames.length == 1)
{
// Viewing a single-frame image
- jQuery.slimbox('../instances/' + $.mobile.pageData.uuid + '/preview', '', {
+ jQuery.slimbox('../instances/' + pageData.uuid + '/preview', '', {
overlayFadeDuration : 1,
resizeDuration : 1,
imageFadeDuration : 1
@@ -728,7 +768,7 @@ $('#instance-preview').live('click', function(e) {
var images = [];
for (var i = 0; i < frames.length; i++) {
- images.push([ '../instances/' + $.mobile.pageData.uuid + '/frames/' + i + '/preview' ]);
+ images.push([ '../instances/' + pageData.uuid + '/frames/' + i + '/preview' ]);
}
jQuery.slimbox(images, 0, {
@@ -748,8 +788,10 @@ $('#instance-preview').live('click', function(e) {
$('#series-preview').live('click', function(e) {
if ($.mobile.pageData) {
- GetResource('/series/' + $.mobile.pageData.uuid, function(series) {
- GetResource('/series/' + $.mobile.pageData.uuid + '/instances', function(instances) {
+ var pageData = DeepCopy($.mobile.pageData);
+
+ GetResource('/series/' + pageData.uuid, function(series) {
+ GetResource('/series/' + pageData.uuid + '/instances', function(instances) {
Sort(instances, function(x) { return x.IndexInSeries; }, true, false);
var images = [];
@@ -858,6 +900,8 @@ function ChooseDicomModality(callback)
$('#instance-store,#series-store,#study-store,#patient-store').live('click', function(e) {
ChooseDicomModality(function(modality, peer) {
+ var pageData = DeepCopy($.mobile.pageData);
+
var url;
var loading;
@@ -878,7 +922,7 @@ $('#instance-store,#series-store,#study-store,#patient-store').live('click', fun
url: url,
type: 'POST',
dataType: 'text',
- data: $.mobile.pageData.uuid,
+ data: pageData.uuid,
async: true, // Necessary to block UI
beforeSend: function() {
$.blockUI({ message: $(loading) });
diff --git a/OrthancExplorer/file-upload.js b/OrthancExplorer/file-upload.js
index 4749335..72f794e 100644
--- a/OrthancExplorer/file-upload.js
+++ b/OrthancExplorer/file-upload.js
@@ -48,6 +48,11 @@ $(document).ready(function() {
$('#upload').live('pageshow', function() {
+ alert('WARNING - This page is currently affected by Orthanc issue #21: ' +
+ '"DICOM files might be missing after uploading with Mozilla Firefox." ' +
+ 'Do not use this upload feature for clinical uses, or carefully ' +
+ 'check that all instances have been properly received by Orthanc. ' +
+ 'Please use the command-line "ImportDicomFiles.py" script to circumvent this issue.');
$('#fileupload').fileupload('enable');
});
diff --git a/OrthancExplorer/query-retrieve.js b/OrthancExplorer/query-retrieve.js
index 14f713f..1e4d4ae 100644
--- a/OrthancExplorer/query-retrieve.js
+++ b/OrthancExplorer/query-retrieve.js
@@ -1,294 +1,322 @@
-function JavascriptDateToDicom(date)
-{
- var s = date.toISOString();
- return s.substring(0, 4) + s.substring(5, 7) + s.substring(8, 10);
-}
-
-function GenerateDicomDate(days)
-{
- var today = new Date();
- var other = new Date(today);
- other.setDate(today.getDate() + days);
- return JavascriptDateToDicom(other);
-}
-
-
-$('#query-retrieve').live('pagebeforeshow', function() {
- $.ajax({
- url: '../modalities',
- dataType: 'json',
- async: false,
- cache: false,
- success: function(modalities) {
- var target = $('#qr-server');
- $('option', target).remove();
-
- for (var i = 0; i < modalities.length; i++) {
- var option = $('<option>').text(modalities[i]);
- target.append(option);
- }
-
- target.selectmenu('refresh');
- }
- });
-
- var target = $('#qr-date');
- $('option', target).remove();
- target.append($('<option>').attr('value', '*').text('Any date'));
- target.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today'));
- target.append($('<option>').attr('value', GenerateDicomDate(-1)).text('Yesterday'));
- target.append($('<option>').attr('value', GenerateDicomDate(-7) + '-').text('Last 7 days'));
- target.append($('<option>').attr('value', GenerateDicomDate(-31) + '-').text('Last 31 days'));
- target.append($('<option>').attr('value', GenerateDicomDate(-31 * 3) + '-').text('Last 3 months'));
- target.append($('<option>').attr('value', GenerateDicomDate(-365) + '-').text('Last year'));
- target.selectmenu('refresh');
-});
-
-
-$('#qr-echo').live('click', function() {
- var server = $('#qr-server').val();
- var message = 'Error: The C-Echo has failed!';
-
- $.ajax({
- url: '../modalities/' + server + '/echo',
- type: 'POST',
- cache: false,
- async: false,
- success: function() {
- message = 'The C-Echo has succeeded!';
- }
- });
-
- $('<div>').simpledialog2({
- mode: 'button',
- headerText: 'Echo result',
- headerClose: true,
- buttonPrompt: message,
- animate: false,
- buttons : {
- 'OK': { click: function () { } }
- }
- });
-
- return false;
-});
-
-
-$('#qr-submit').live('click', function() {
- var query = {
- 'Level' : 'Study',
- 'Query' : {
- 'AccessionNumber' : '*',
- 'PatientBirthDate' : '*',
- 'PatientID' : '*',
- 'PatientName' : '*',
- 'PatientSex' : '*',
- 'SpecificCharacterSet' : 'ISO_IR 192', // UTF-8
- 'StudyDate' : $('#qr-date').val(),
- 'StudyDescription' : '*'
- }
- };
-
- var field = $('#qr-fields input:checked').val();
- query['Query'][field] = $('#qr-value').val().toUpperCase();
-
- var modalities = '';
- $('#qr-modalities input:checked').each(function() {
- var s = $(this).attr('name');
- if (modalities == '*')
- modalities = s;
- else
- modalities += '\\' + s;
- });
-
- if (modalities.length > 0) {
- query['Query']['ModalitiesInStudy'] = modalities;
- }
-
-
- var server = $('#qr-server').val();
- $.ajax({
- url: '../modalities/' + server + '/query',
- type: 'POST',
- data: JSON.stringify(query),
- dataType: 'json',
- async: false,
- error: function() {
- alert('Error during query (C-Find)');
- },
- success: function(result) {
- window.location.assign('explorer.html#query-retrieve-2?server=' + server + '&uuid=' + result['ID']);
- }
- });
-
- return false;
-});
-
-
-
-function Retrieve(url)
-{
- $.ajax({
- url: '../system',
- dataType: 'json',
- async: false,
- success: function(system) {
- $('<div>').simpledialog2({
- mode: 'button',
- headerText: 'Target',
- headerClose: true,
- buttonPrompt: 'Enter Application Entity Title (AET):',
- buttonInput: true,
- buttonInputDefault: system['DicomAet'],
- buttons : {
- 'OK': {
- click: function () {
- var aet = $.mobile.sdLastInput;
- if (aet.length == 0)
- aet = system['DicomAet'];
-
- $.ajax({
- url: url,
- type: 'POST',
- async: true, // Necessary to block UI
- dataType: 'text',
- data: aet,
- beforeSend: function() {
- $.blockUI({ message: $('#info-retrieve') });
- },
- complete: function(s) {
- $.unblockUI();
- },
- error: function() {
- alert('Error during retrieve');
- }
- });
- }
- }
- }
- });
- }
- });
-}
-
-
-
-
-$('#query-retrieve-2').live('pagebeforeshow', function() {
- if ($.mobile.pageData) {
- var uri = '../queries/' + $.mobile.pageData.uuid + '/answers';
-
- $.ajax({
- url: uri,
- dataType: 'json',
- async: false,
- success: function(answers) {
- var target = $('#query-retrieve-2 ul');
- $('li', target).remove();
-
- for (var i = 0; i < answers.length; i++) {
- $.ajax({
- url: uri + '/' + answers[i] + '/content?simplify',
- dataType: 'json',
- async: false,
- success: function(study) {
- var series = '#query-retrieve-3?server=' + $.mobile.pageData.server + '&uuid=' + study['StudyInstanceUID'];
- var info = $('<a>').attr('href', series).html(
- ('<h3>{0} - {1}</h3>' +
- '<p>Accession number: <b>{2}</b></p>' +
- '<p>Birth date: <b>{3}</b></p>' +
- '<p>Patient sex: <b>{4}</b></p>' +
- '<p>Study description: <b>{5}</b></p>' +
- '<p>Study date: <b>{6}</b></p>').format(
- study['PatientID'],
- study['PatientName'],
- study['AccessionNumber'],
- FormatDicomDate(study['PatientBirthDate']),
- study['PatientSex'],
- study['StudyDescription'],
- FormatDicomDate(study['StudyDate'])));
-
- var studyUri = uri + '/' + answers[i] + '/retrieve';
- var retrieve = $('<a>').text('Retrieve').click(function() {
- Retrieve(studyUri);
- });
-
- target.append($('<li>').append(info).append(retrieve));
- }
- });
- }
-
- target.listview('refresh');
- }
- });
- }
-});
-
-
-$('#query-retrieve-3').live('pagebeforeshow', function() {
- if ($.mobile.pageData) {
- var query = {
- 'Level' : 'Series',
- 'Query' : {
- 'Modality' : '*',
- 'ProtocolName' : '*',
- 'SeriesDescription' : '*',
- 'SeriesInstanceUID' : '*',
- 'StudyInstanceUID' : $.mobile.pageData.uuid
- }
- };
-
- $.ajax({
- url: '../modalities/' + $.mobile.pageData.server + '/query',
- type: 'POST',
- data: JSON.stringify(query),
- dataType: 'json',
- async: false,
- error: function() {
- alert('Error during query (C-Find)');
- },
- success: function(answer) {
- var uri = '../queries/' + answer['ID'] + '/answers';
-
- $.ajax({
- url: uri,
- dataType: 'json',
- async: false,
- success: function(answers) {
-
- var target = $('#query-retrieve-3 ul');
- $('li', target).remove();
-
- for (var i = 0; i < answers.length; i++) {
- $.ajax({
- url: uri + '/' + answers[i] + '/content?simplify',
- dataType: 'json',
- async: false,
- success: function(series) {
- var info = $('<a>').html(
- ('<h3>{0}</h3>' +
- '<p>Modality: <b>{1}</b></p>' +
- '<p>Protocol name: <b>{2}</b></p>'
- ).format(
- series['SeriesDescription'],
- series['Modality'],
- series['ProtocolName']
- ));
-
- var seriesUri = uri + '/' + answers[i] + '/retrieve';
- var retrieve = $('<a>').text('Retrieve').click(function() {
- Retrieve(seriesUri);
- });
-
- target.append($('<li>').append(info).append(retrieve));
- }
- });
- }
-
- target.listview('refresh');
- }
- });
- }
- });
- }
-});
+function JavascriptDateToDicom(date)
+{
+ var s = date.toISOString();
+ return s.substring(0, 4) + s.substring(5, 7) + s.substring(8, 10);
+}
+
+function GenerateDicomDate(days)
+{
+ var today = new Date();
+ var other = new Date(today);
+ other.setDate(today.getDate() + days);
+ return JavascriptDateToDicom(other);
+}
+
+
+$('#query-retrieve').live('pagebeforeshow', function() {
+ $.ajax({
+ url: '../modalities',
+ dataType: 'json',
+ async: false,
+ cache: false,
+ success: function(modalities) {
+ var target = $('#qr-server');
+ $('option', target).remove();
+
+ for (var i = 0; i < modalities.length; i++) {
+ var option = $('<option>').text(modalities[i]);
+ target.append(option);
+ }
+
+ target.selectmenu('refresh');
+ }
+ });
+
+ var target = $('#qr-date');
+ $('option', target).remove();
+ target.append($('<option>').attr('value', '*').text('Any date'));
+ target.append($('<option>').attr('value', GenerateDicomDate(0)).text('Today'));
+ target.append($('<option>').attr('value', GenerateDicomDate(-1)).text('Yesterday'));
+ target.append($('<option>').attr('value', GenerateDicomDate(-7) + '-').text('Last 7 days'));
+ target.append($('<option>').attr('value', GenerateDicomDate(-31) + '-').text('Last 31 days'));
+ target.append($('<option>').attr('value', GenerateDicomDate(-31 * 3) + '-').text('Last 3 months'));
+ target.append($('<option>').attr('value', GenerateDicomDate(-365) + '-').text('Last year'));
+ target.selectmenu('refresh');
+});
+
+
+$('#qr-echo').live('click', function() {
+ var server = $('#qr-server').val();
+ var message = 'Error: The C-Echo has failed!';
+
+ $.ajax({
+ url: '../modalities/' + server + '/echo',
+ type: 'POST',
+ cache: false,
+ async: false,
+ success: function() {
+ message = 'The C-Echo has succeeded!';
+ }
+ });
+
+ $('<div>').simpledialog2({
+ mode: 'button',
+ headerText: 'Echo result',
+ headerClose: true,
+ buttonPrompt: message,
+ animate: false,
+ buttons : {
+ 'OK': { click: function () { } }
+ }
+ });
+
+ return false;
+});
+
+
+$('#qr-submit').live('click', function() {
+ var query = {
+ 'Level' : 'Study',
+ 'Query' : {
+ 'AccessionNumber' : '*',
+ 'PatientBirthDate' : '*',
+ 'PatientID' : '*',
+ 'PatientName' : '*',
+ 'PatientSex' : '*',
+ 'StudyDate' : $('#qr-date').val(),
+ 'StudyDescription' : '*'
+ }
+ };
+
+ var field = $('#qr-fields input:checked').val();
+ query['Query'][field] = $('#qr-value').val().toUpperCase();
+
+ var modalities = '';
+ $('#qr-modalities input:checked').each(function() {
+ var s = $(this).attr('name');
+ if (modalities == '')
+ modalities = s;
+ else
+ modalities += '\\' + s;
+ });
+
+ if (modalities.length > 0) {
+ query['Query']['ModalitiesInStudy'] = modalities;
+ }
+
+
+ var server = $('#qr-server').val();
+ $.ajax({
+ url: '../modalities/' + server + '/query',
+ type: 'POST',
+ data: JSON.stringify(query),
+ dataType: 'json',
+ async: false,
+ error: function() {
+ alert('Error during query (C-Find)');
+ },
+ success: function(result) {
+ ChangePage('query-retrieve-2', {
+ 'server' : server,
+ 'uuid' : result['ID']
+ });
+ }
+ });
+
+ return false;
+});
+
+
+
+$('#query-retrieve-2').live('pagebeforeshow', function() {
+ if ($.mobile.pageData) {
+ var pageData = DeepCopy($.mobile.pageData);
+
+ var uri = '../queries/' + pageData.uuid + '/answers';
+
+ $.ajax({
+ url: uri,
+ dataType: 'json',
+ async: false,
+ success: function(answers) {
+ var target = $('#query-retrieve-2 ul');
+ $('li', target).remove();
+
+ for (var i = 0; i < answers.length; i++) {
+ $.ajax({
+ url: uri + '/' + answers[i] + '/content?simplify',
+ dataType: 'json',
+ async: false,
+ success: function(study) {
+ var series = '#query-retrieve-3?server=' + pageData.server + '&uuid=' + study['StudyInstanceUID'];
+ var info = $('<a>').attr('href', series).html(
+ ('<h3>{0} - {1}</h3>' +
+ '<p>Accession number: <b>{2}</b></p>' +
+ '<p>Birth date: <b>{3}</b></p>' +
+ '<p>Patient sex: <b>{4}</b></p>' +
+ '<p>Study description: <b>{5}</b></p>' +
+ '<p>Study date: <b>{6}</b></p>').format(
+ study['PatientID'],
+ study['PatientName'],
+ study['AccessionNumber'],
+ FormatDicomDate(study['PatientBirthDate']),
+ study['PatientSex'],
+ study['StudyDescription'],
+ FormatDicomDate(study['StudyDate'])));
+
+ var answerId = answers[i];
+ var retrieve = $('<a>').text('Retrieve all study').click(function() {
+ ChangePage('query-retrieve-4', {
+ 'query' : pageData.uuid,
+ 'answer' : answerId,
+ 'server' : pageData.server
+ });
+ });
+
+ target.append($('<li>').append(info).append(retrieve));
+ }
+ });
+ }
+
+ target.listview('refresh');
+ }
+ });
+ }
+});
+
+
+$('#query-retrieve-3').live('pagebeforeshow', function() {
+ if ($.mobile.pageData) {
+ var pageData = DeepCopy($.mobile.pageData);
+
+ var query = {
+ 'Level' : 'Series',
+ 'Query' : {
+ 'Modality' : '*',
+ 'ProtocolName' : '*',
+ 'SeriesDescription' : '*',
+ 'SeriesInstanceUID' : '*',
+ 'StudyInstanceUID' : pageData.uuid
+ }
+ };
+
+ $.ajax({
+ url: '../modalities/' + pageData.server + '/query',
+ type: 'POST',
+ data: JSON.stringify(query),
+ dataType: 'json',
+ async: false,
+ error: function() {
+ alert('Error during query (C-Find)');
+ },
+ success: function(answer) {
+ var queryUuid = answer['ID'];
+ var uri = '../queries/' + answer['ID'] + '/answers';
+
+ $.ajax({
+ url: uri,
+ dataType: 'json',
+ async: false,
+ success: function(answers) {
+
+ var target = $('#query-retrieve-3 ul');
+ $('li', target).remove();
+
+ for (var i = 0; i < answers.length; i++) {
+ $.ajax({
+ url: uri + '/' + answers[i] + '/content?simplify',
+ dataType: 'json',
+ async: false,
+ success: function(series) {
+ var info = $('<a>').html(
+ ('<h3>{0}</h3>' +
+ '<p>Modality: <b>{1}</b></p>' +
+ '<p>Protocol name: <b>{2}</b></p>'
+ ).format(
+ series['SeriesDescription'],
+ series['Modality'],
+ series['ProtocolName']
+ ));
+
+ var answerId = answers[i];
+ info.click(function() {
+ ChangePage('query-retrieve-4', {
+ 'query' : queryUuid,
+ 'study' : pageData.uuid,
+ 'answer' : answerId,
+ 'server' : pageData.server
+ });
+ });
+
+ target.append($('<li>').attr('data-icon', 'arrow-d').append(info));
+ }
+ });
+ }
+
+ target.listview('refresh');
+ }
+ });
+ }
+ });
+ }
+});
+
+
+
+$('#query-retrieve-4').live('pagebeforeshow', function() {
+ if ($.mobile.pageData) {
+ var pageData = DeepCopy($.mobile.pageData);
+ var uri = '../queries/' + pageData.query + '/answers/' + pageData.answer + '/retrieve';
+
+ $.ajax({
+ url: '../system',
+ dataType: 'json',
+ async: false,
+ cache: false,
+ success: function(system) {
+ $('#retrieve-target').val(system['DicomAet']);
+
+ $('#retrieve-form').submit(function(event) {
+ event.preventDefault();
+
+ var aet = $('#retrieve-target').val();
+ if (aet.length == 0) {
+ aet = system['DicomAet'];
+ }
+
+ $.ajax({
+ url: uri,
+ type: 'POST',
+ async: true, // Necessary to block UI
+ dataType: 'text',
+ data: aet,
+ beforeSend: function() {
+ $.blockUI({ message: $('#info-retrieve') });
+ },
+ complete: function(s) {
+ $.unblockUI();
+ },
+ success: function() {
+ if (pageData.study) {
+ // Go back to the list of series
+ ChangePage('query-retrieve-3', {
+ 'server' : pageData.server,
+ 'uuid' : pageData.study
+ });
+ } else {
+ // Go back to the list of studies
+ ChangePage('query-retrieve-2', {
+ 'server' : pageData.server,
+ 'uuid' : pageData.query
+ });
+ }
+ },
+ error: function() {
+ alert('Error during retrieve');
+ }
+ });
+ });
+ }
+ });
+ }
+});
diff --git a/OrthancServer/DatabaseWrapper.cpp b/OrthancServer/DatabaseWrapper.cpp
index 4433255..032509a 100644
--- a/OrthancServer/DatabaseWrapper.cpp
+++ b/OrthancServer/DatabaseWrapper.cpp
@@ -35,7 +35,6 @@
#include "../Core/DicomFormat/DicomArray.h"
#include "../Core/Logging.h"
-#include "../Core/Uuid.h"
#include "EmbeddedResources.h"
#include "ServerToolbox.h"
@@ -373,10 +372,10 @@ namespace Orthanc
// consists in reconstructing the main DICOM tags information
// (as more tags got included).
db_.BeginTransaction();
- Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Patient);
- Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Study);
- Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Series);
- Toolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Instance);
+ ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Patient);
+ ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Study);
+ ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Series);
+ ServerToolbox::ReconstructMainDicomTags(*this, storageArea, ResourceType_Instance);
db_.Execute("UPDATE GlobalProperties SET value=\"6\" WHERE property=" +
boost::lexical_cast<std::string>(GlobalProperty_DatabaseSchemaVersion) + ";");
db_.CommitTransaction();
diff --git a/OrthancServer/DicomDirWriter.cpp b/OrthancServer/DicomDirWriter.cpp
index 6f77011..fbe998f 100644
--- a/OrthancServer/DicomDirWriter.cpp
+++ b/OrthancServer/DicomDirWriter.cpp
@@ -105,7 +105,9 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../Core/Logging.h"
#include "../Core/OrthancException.h"
-#include "../Core/Uuid.h"
+#include "../Core/TemporaryFile.h"
+#include "../Core/Toolbox.h"
+#include "../Core/SystemToolbox.h"
#include <dcmtk/dcmdata/dcdicdir.h>
#include <dcmtk/dcmdata/dcmetinf.h>
@@ -126,7 +128,7 @@ namespace Orthanc
{
private:
std::string fileSetId_;
- Toolbox::TemporaryFile file_;
+ TemporaryFile file_;
std::auto_ptr<DcmDicomDir> dir_;
typedef std::pair<ResourceType, std::string> IndexKey;
@@ -260,7 +262,7 @@ namespace Orthanc
// cf. "DicomDirInterface::buildStudyRecord()"
std::string nowDate, nowTime;
- Toolbox::GetNowDicom(nowDate, nowTime);
+ SystemToolbox::GetNowDicom(nowDate, nowTime);
std::string studyDate;
if (!GetUtf8TagValue(studyDate, dicom, encoding, DCM_StudyDate) &&
diff --git a/OrthancServer/DicomInstanceToStore.cpp b/OrthancServer/DicomInstanceToStore.cpp
index 2f0717c..3851187 100644
--- a/OrthancServer/DicomInstanceToStore.cpp
+++ b/OrthancServer/DicomInstanceToStore.cpp
@@ -38,6 +38,7 @@
#include "../Core/Logging.h"
#include <dcmtk/dcmdata/dcfilefo.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
namespace Orthanc
@@ -104,21 +105,15 @@ namespace Orthanc
if (!summary_.HasContent())
{
summary_.Allocate();
- FromDcmtkBridge::Convert(summary_.GetContent(),
- *parsed_.GetContent().GetDcmtkObject().getDataset(),
- ORTHANC_MAXIMUM_TAG_LENGTH,
- Configuration::GetDefaultEncoding());
+ Configuration::ExtractDicomSummary(summary_.GetContent(),
+ *parsed_.GetContent().GetDcmtkObject().getDataset());
}
if (!json_.HasContent())
{
json_.Allocate();
- FromDcmtkBridge::ToJson(json_.GetContent(),
- *parsed_.GetContent().GetDcmtkObject().getDataset(),
- DicomToJsonFormat_Full,
- DicomToJsonFlags_Default,
- ORTHANC_MAXIMUM_TAG_LENGTH,
- Configuration::GetDefaultEncoding());
+ Configuration::ExtractDicomAsJson(json_.GetContent(),
+ *parsed_.GetContent().GetDcmtkObject().getDataset());
}
}
@@ -276,4 +271,25 @@ namespace Orthanc
return "";
}
}
+
+
+ bool DicomInstanceToStore::LookupTransferSyntax(std::string& result)
+ {
+ ComputeMissingInformation();
+
+ DicomMap header;
+ if (DicomMap::ParseDicomMetaInformation(header, GetBufferData(), GetBufferSize()))
+ {
+ const DicomValue* value = header.TestAndGetValue(DICOM_TAG_TRANSFER_SYNTAX_UID);
+ if (value != NULL &&
+ !value->IsBinary() &&
+ !value->IsNull())
+ {
+ result = Toolbox::StripSpaces(value->GetContent());
+ return true;
+ }
+ }
+
+ return false;
+ }
}
diff --git a/OrthancServer/DicomInstanceToStore.h b/OrthancServer/DicomInstanceToStore.h
index 5d7f318..7723922 100644
--- a/OrthancServer/DicomInstanceToStore.h
+++ b/OrthancServer/DicomInstanceToStore.h
@@ -221,5 +221,7 @@ namespace Orthanc
const Json::Value& GetJson();
void GetOriginInformation(Json::Value& result) const;
+
+ bool LookupTransferSyntax(std::string& result);
};
}
diff --git a/OrthancServer/DicomModification.cpp b/OrthancServer/DicomModification.cpp
index 896300b..35a0afd 100644
--- a/OrthancServer/DicomModification.cpp
+++ b/OrthancServer/DicomModification.cpp
@@ -144,11 +144,13 @@ namespace Orthanc
dicom.Replace(*tag, mapped, false /* don't try and decode data URI scheme for UIDs */, DicomReplaceMode_InsertIfAbsent);
}
- DicomModification::DicomModification()
+ DicomModification::DicomModification() :
+ removePrivateTags_(false),
+ level_(ResourceType_Instance),
+ allowManualIdentifiers_(true),
+ keepStudyInstanceUid_(false),
+ keepSeriesInstanceUid_(false)
{
- removePrivateTags_ = false;
- level_ = ResourceType_Instance;
- allowManualIdentifiers_ = true;
}
DicomModification::~DicomModification()
@@ -166,6 +168,16 @@ namespace Orthanc
privateTagsToKeep_.insert(tag);
}
+ if (tag == DICOM_TAG_STUDY_INSTANCE_UID)
+ {
+ keepStudyInstanceUid_ = true;
+ }
+
+ if (tag == DICOM_TAG_SERIES_INSTANCE_UID)
+ {
+ keepSeriesInstanceUid_ = true;
+ }
+
MarkNotOrthancAnonymization();
}
@@ -466,13 +478,27 @@ namespace Orthanc
if (level_ <= ResourceType_Study &&
!IsReplaced(DICOM_TAG_STUDY_INSTANCE_UID))
{
- MapDicomIdentifier(toModify, ResourceType_Study);
+ if (keepStudyInstanceUid_)
+ {
+ LOG(WARNING) << "Modifying a study while keeping its original StudyInstanceUID: This should be avoided!";
+ }
+ else
+ {
+ MapDicomIdentifier(toModify, ResourceType_Study);
+ }
}
if (level_ <= ResourceType_Series &&
!IsReplaced(DICOM_TAG_SERIES_INSTANCE_UID))
{
- MapDicomIdentifier(toModify, ResourceType_Series);
+ if (keepSeriesInstanceUid_)
+ {
+ LOG(WARNING) << "Modifying a series while keeping its original SeriesInstanceUID: This should be avoided!";
+ }
+ else
+ {
+ MapDicomIdentifier(toModify, ResourceType_Series);
+ }
}
if (level_ <= ResourceType_Instance && // Always true
diff --git a/OrthancServer/DicomModification.h b/OrthancServer/DicomModification.h
index 5e10de4..e92c177 100644
--- a/OrthancServer/DicomModification.h
+++ b/OrthancServer/DicomModification.h
@@ -57,6 +57,8 @@ namespace Orthanc
UidMap uidMap_;
SetOfTags privateTagsToKeep_;
bool allowManualIdentifiers_;
+ bool keepStudyInstanceUid_;
+ bool keepSeriesInstanceUid_;
void MapDicomIdentifier(ParsedDicomFile& dicom,
ResourceType level);
diff --git a/OrthancServer/DicomProtocol/DicomFindAnswers.cpp b/OrthancServer/DicomProtocol/DicomFindAnswers.cpp
index c649932..be15a63 100644
--- a/OrthancServer/DicomProtocol/DicomFindAnswers.cpp
+++ b/OrthancServer/DicomProtocol/DicomFindAnswers.cpp
@@ -33,8 +33,8 @@
#include "../PrecompiledHeadersServer.h"
#include "DicomFindAnswers.h"
+#include "../OrthancInitialization.h"
#include "../FromDcmtkBridge.h"
-#include "../ToDcmtkBridge.h"
#include "../../Core/OrthancException.h"
#include <memory>
@@ -44,80 +44,56 @@
namespace Orthanc
{
- class DicomFindAnswers::Answer : public boost::noncopyable
+ void DicomFindAnswers::AddAnswerInternal(ParsedDicomFile* answer)
{
- private:
- ParsedDicomFile* dicom_;
- DicomMap* map_;
+ std::auto_ptr<ParsedDicomFile> protection(answer);
- void CleanupDicom()
+ if (isWorklist_)
{
- if (dicom_ != NULL)
- {
- dicom_->Remove(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID);
- dicom_->Remove(DICOM_TAG_SOP_INSTANCE_UID);
- }
+ // These lines are necessary when serving worklists, otherwise
+ // Orthanc does not behave as "wlmscpfs"
+ protection->Remove(DICOM_TAG_MEDIA_STORAGE_SOP_INSTANCE_UID);
+ protection->Remove(DICOM_TAG_SOP_INSTANCE_UID);
}
- public:
- Answer(ParsedDicomFile& dicom) :
- dicom_(dicom.Clone()),
- map_(NULL)
- {
- CleanupDicom();
- }
+ protection->ChangeEncoding(encoding_);
- Answer(const void* dicom,
- size_t size) :
- dicom_(new ParsedDicomFile(dicom, size)),
- map_(NULL)
- {
- CleanupDicom();
- }
+ answers_.push_back(protection.release());
+ }
- Answer(const DicomMap& map) :
- dicom_(NULL),
- map_(map.Clone())
- {
- }
- ~Answer()
+ DicomFindAnswers::DicomFindAnswers(bool isWorklist) :
+ encoding_(Configuration::GetDefaultEncoding()),
+ isWorklist_(isWorklist),
+ complete_(true)
+ {
+ }
+
+
+ void DicomFindAnswers::SetEncoding(Encoding encoding)
+ {
+ for (size_t i = 0; i < answers_.size(); i++)
{
- if (dicom_ != NULL)
- {
- delete dicom_;
- }
-
- if (map_ != NULL)
- {
- delete map_;
- }
+ assert(answers_[i] != NULL);
+ answers_[i]->ChangeEncoding(encoding);
}
- ParsedDicomFile& GetDicomFile()
- {
- if (dicom_ == NULL)
- {
- assert(map_ != NULL);
- dicom_ = new ParsedDicomFile(*map_);
- }
+ encoding_ = encoding;
+ }
- return *dicom_;
- }
- DcmDataset* ExtractDcmDataset() const
+ void DicomFindAnswers::SetWorklist(bool isWorklist)
+ {
+ if (answers_.empty())
{
- if (dicom_ != NULL)
- {
- return new DcmDataset(*dicom_->GetDcmtkObject().getDataset());
- }
- else
- {
- assert(map_ != NULL);
- return ToDcmtkBridge::Convert(*map_);
- }
+ isWorklist_ = isWorklist;
}
- };
+ else
+ {
+ // This set of answers is not empty anymore, cannot change its type
+ throw OrthancException(ErrorCode_BadSequenceOfCalls);
+ }
+ }
void DicomFindAnswers::Clear()
@@ -143,28 +119,27 @@ namespace Orthanc
void DicomFindAnswers::Add(const DicomMap& map)
{
- answers_.push_back(new Answer(map));
+ AddAnswerInternal(new ParsedDicomFile(map, encoding_));
}
void DicomFindAnswers::Add(ParsedDicomFile& dicom)
{
- answers_.push_back(new Answer(dicom));
+ AddAnswerInternal(dicom.Clone());
}
-
void DicomFindAnswers::Add(const void* dicom,
size_t size)
{
- answers_.push_back(new Answer(dicom, size));
+ AddAnswerInternal(new ParsedDicomFile(dicom, size));
}
- DicomFindAnswers::Answer& DicomFindAnswers::GetAnswerInternal(size_t index) const
+ ParsedDicomFile& DicomFindAnswers::GetAnswer(size_t index) const
{
if (index < answers_.size())
{
- return *answers_.at(index);
+ return *answers_[index];
}
else
{
@@ -173,15 +148,9 @@ namespace Orthanc
}
- ParsedDicomFile& DicomFindAnswers::GetAnswer(size_t index) const
- {
- return GetAnswerInternal(index).GetDicomFile();
- }
-
-
DcmDataset* DicomFindAnswers::ExtractDcmDataset(size_t index) const
{
- return GetAnswerInternal(index).ExtractDcmDataset();
+ return new DcmDataset(*GetAnswer(index).GetDcmtkObject().getDataset());
}
@@ -190,7 +159,7 @@ namespace Orthanc
bool simplify) const
{
DicomToJsonFormat format = (simplify ? DicomToJsonFormat_Human : DicomToJsonFormat_Full);
- GetAnswer(index).ToJson(target, format, DicomToJsonFlags_None, 0);
+ GetAnswer(index).DatasetToJson(target, format, DicomToJsonFlags_None, 0);
}
diff --git a/OrthancServer/DicomProtocol/DicomFindAnswers.h b/OrthancServer/DicomProtocol/DicomFindAnswers.h
index 5dfc23c..f06bbe9 100644
--- a/OrthancServer/DicomProtocol/DicomFindAnswers.h
+++ b/OrthancServer/DicomProtocol/DicomFindAnswers.h
@@ -39,23 +39,35 @@ namespace Orthanc
class DicomFindAnswers : public boost::noncopyable
{
private:
- class Answer;
+ Encoding encoding_;
+ bool isWorklist_;
+ std::vector<ParsedDicomFile*> answers_;
+ bool complete_;
- std::vector<Answer*> answers_;
- bool complete_;
-
- Answer& GetAnswerInternal(size_t index) const;
+ void AddAnswerInternal(ParsedDicomFile* answer);
public:
- DicomFindAnswers() : complete_(true)
- {
- }
+ DicomFindAnswers(bool isWorklist);
~DicomFindAnswers()
{
Clear();
}
+ Encoding GetEncoding() const
+ {
+ return encoding_;
+ }
+
+ void SetEncoding(Encoding encoding);
+
+ void SetWorklist(bool isWorklist);
+
+ bool IsWorklist() const
+ {
+ return isWorklist_;
+ }
+
void Clear();
void Reserve(size_t index);
diff --git a/OrthancServer/DicomProtocol/DicomServer.cpp b/OrthancServer/DicomProtocol/DicomServer.cpp
index deb80aa..b908420 100644
--- a/OrthancServer/DicomProtocol/DicomServer.cpp
+++ b/OrthancServer/DicomProtocol/DicomServer.cpp
@@ -36,7 +36,6 @@
#include "../../Core/Logging.h"
#include "../../Core/OrthancException.h"
#include "../../Core/Toolbox.h"
-#include "../../Core/Uuid.h"
#include "../Internals/CommandDispatcher.h"
#include "../OrthancInitialization.h"
#include "EmbeddedResources.h"
@@ -97,7 +96,7 @@ namespace Orthanc
worklistRequestHandlerFactory_ = NULL;
applicationEntityFilter_ = NULL;
checkCalledAet_ = true;
- clientTimeout_ = 30;
+ associationTimeout_ = 30;
continue_ = false;
}
@@ -121,15 +120,18 @@ namespace Orthanc
return port_;
}
- void DicomServer::SetClientTimeout(uint32_t timeout)
+ void DicomServer::SetAssociationTimeout(uint32_t seconds)
{
+ LOG(INFO) << "Setting timeout for DICOM connections if Orthanc acts as SCP (server): "
+ << seconds << " seconds (0 = no timeout)";
+
Stop();
- clientTimeout_ = timeout;
+ associationTimeout_ = seconds;
}
- uint32_t DicomServer::GetClientTimeout() const
+ uint32_t DicomServer::GetAssociationTimeout() const
{
- return clientTimeout_;
+ return associationTimeout_;
}
diff --git a/OrthancServer/DicomProtocol/DicomServer.h b/OrthancServer/DicomProtocol/DicomServer.h
index 807f13c..f4d5f3a 100644
--- a/OrthancServer/DicomProtocol/DicomServer.h
+++ b/OrthancServer/DicomProtocol/DicomServer.h
@@ -54,7 +54,7 @@ namespace Orthanc
std::string aet_;
uint16_t port_;
bool continue_;
- uint32_t clientTimeout_;
+ uint32_t associationTimeout_;
IFindRequestHandlerFactory* findRequestHandlerFactory_;
IMoveRequestHandlerFactory* moveRequestHandlerFactory_;
IStoreRequestHandlerFactory* storeRequestHandlerFactory_;
@@ -71,8 +71,8 @@ namespace Orthanc
void SetPortNumber(uint16_t port);
uint16_t GetPortNumber() const;
- void SetClientTimeout(uint32_t timeout);
- uint32_t GetClientTimeout() const;
+ void SetAssociationTimeout(uint32_t seconds);
+ uint32_t GetAssociationTimeout() const;
void SetCalledApplicationEntityTitleCheck(bool check);
bool HasCalledApplicationEntityTitleCheck() const;
diff --git a/OrthancServer/DicomProtocol/DicomUserConnection.cpp b/OrthancServer/DicomProtocol/DicomUserConnection.cpp
index 2636536..c8a7ff5 100644
--- a/OrthancServer/DicomProtocol/DicomUserConnection.cpp
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.cpp
@@ -133,6 +133,9 @@ static const unsigned int MAXIMUM_STORAGE_SOP_CLASSES = 64;
namespace Orthanc
{
+ // By default, the timeout for DICOM SCU (client) connections is set to 10 seconds
+ static uint32_t defaultTimeout_ = 10;
+
struct DicomUserConnection::PImpl
{
// Connection state
@@ -151,6 +154,7 @@ namespace Orthanc
void Store(DcmInputStream& is,
DicomUserConnection& connection,
+ const std::string& moveOriginatorAET,
uint16_t moveOriginatorID);
};
@@ -256,6 +260,7 @@ namespace Orthanc
void DicomUserConnection::PImpl::Store(DcmInputStream& is,
DicomUserConnection& connection,
+ const std::string& moveOriginatorAET,
uint16_t moveOriginatorID)
{
CheckIsOpen();
@@ -277,21 +282,21 @@ namespace Orthanc
const std::string syntax(xfer.getXferID());
bool isGeneric = IsGenericTransferSyntax(syntax);
- bool renegociate;
+ bool renegotiate;
if (isGeneric)
{
// Are we making a generic-to-specific or specific-to-generic change of
// the transfer syntax? If this is the case, renegotiate the connection.
- renegociate = !IsGenericTransferSyntax(connection.GetPreferredTransferSyntax());
+ renegotiate = !IsGenericTransferSyntax(connection.GetPreferredTransferSyntax());
}
else
{
- // We are using a specific transfer syntax. Renegociate if the
+ // We are using a specific transfer syntax. Renegotiate if the
// current connection does not match this transfer syntax.
- renegociate = (syntax != connection.GetPreferredTransferSyntax());
+ renegotiate = (syntax != connection.GetPreferredTransferSyntax());
}
- if (renegociate)
+ if (renegotiate)
{
LOG(INFO) << "Change in the transfer syntax: the C-Store associated must be renegotiated";
@@ -338,12 +343,12 @@ namespace Orthanc
request.DataSetType = DIMSE_DATASET_PRESENT;
strncpy(request.AffectedSOPInstanceUID, sopInstance, DIC_UI_LEN);
- strncpy(request.MoveOriginatorApplicationEntityTitle,
- connection.GetLocalApplicationEntityTitle().c_str(), DIC_AE_LEN);
- request.opts = O_STORE_MOVEORIGINATORAETITLE;
-
- if (moveOriginatorID != 0)
+ if (!moveOriginatorAET.empty())
{
+ strncpy(request.MoveOriginatorApplicationEntityTitle,
+ moveOriginatorAET.c_str(), DIC_AE_LEN);
+ request.opts = O_STORE_MOVEORIGINATORAETITLE;
+
request.MoveOriginatorID = moveOriginatorID; // The type DIC_US is an alias for uint16_t
request.opts |= O_STORE_MOVEORIGINATORID;
}
@@ -395,9 +400,7 @@ namespace Orthanc
else
{
DicomMap m;
- FromDcmtkBridge::Convert(m, *responseIdentifiers,
- ORTHANC_MAXIMUM_TAG_LENGTH,
- Configuration::GetDefaultEncoding());
+ Configuration::ExtractDicomSummary(m, *responseIdentifiers);
if (!m.HasTag(DICOM_TAG_QUERY_RETRIEVE_LEVEL))
{
@@ -477,8 +480,8 @@ namespace Orthanc
}
- static DcmDataset* ConvertQueryFields(const DicomMap& fields,
- ModalityManufacturer manufacturer)
+ static ParsedDicomFile* ConvertQueryFields(const DicomMap& fields,
+ ModalityManufacturer manufacturer)
{
switch (manufacturer)
{
@@ -512,11 +515,11 @@ namespace Orthanc
}
}
- return ToDcmtkBridge::Convert(*fix);
+ return new ParsedDicomFile(*fix);
}
default:
- return ToDcmtkBridge::Convert(fields);
+ return new ParsedDicomFile(fields);
}
}
@@ -576,7 +579,9 @@ namespace Orthanc
CheckIsOpen();
- std::auto_ptr<DcmDataset> dataset(ConvertQueryFields(fields, manufacturer_));
+ std::auto_ptr<ParsedDicomFile> query(ConvertQueryFields(fields, manufacturer_));
+ DcmDataset* dataset = query->GetDcmtkObject().getDataset();
+
const char* clevel = NULL;
const char* sopClass = NULL;
@@ -584,19 +589,19 @@ namespace Orthanc
{
case ResourceType_Patient:
clevel = "PATIENT";
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "PATIENT");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "PATIENT");
sopClass = UID_FINDPatientRootQueryRetrieveInformationModel;
break;
case ResourceType_Study:
clevel = "STUDY";
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "STUDY");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "STUDY");
sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
break;
case ResourceType_Series:
clevel = "SERIES";
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "SERIES");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "SERIES");
sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
break;
@@ -608,11 +613,11 @@ namespace Orthanc
// This is a particular case for ClearCanvas, thanks to Peter Somlo <peter.somlo at gmail.com>.
// https://groups.google.com/d/msg/orthanc-users/j-6C3MAVwiw/iolB9hclom8J
// http://www.clearcanvas.ca/Home/Community/OldForums/tabid/526/aff/11/aft/14670/afv/topic/Default.aspx
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "IMAGE");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "IMAGE");
}
else
{
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "INSTANCE");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "INSTANCE");
}
sopClass = UID_FINDStudyRootQueryRetrieveInformationModel;
@@ -629,26 +634,26 @@ namespace Orthanc
case ResourceType_Instance:
// SOP Instance UID
if (!fields.HasTag(0x0008, 0x0018))
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0018), "");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0018), "");
case ResourceType_Series:
// Series instance UID
if (!fields.HasTag(0x0020, 0x000e))
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000e), "");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0020, 0x000e), "");
case ResourceType_Study:
// Accession number
if (!fields.HasTag(0x0008, 0x0050))
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0050), "");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0050), "");
// Study instance UID
if (!fields.HasTag(0x0020, 0x000d))
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0020, 0x000d), "");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0020, 0x000d), "");
case ResourceType_Patient:
// Patient ID
if (!fields.HasTag(0x0010, 0x0020))
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0010, 0x0020), "");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0010, 0x0020), "");
break;
@@ -657,7 +662,7 @@ namespace Orthanc
}
assert(clevel != NULL && sopClass != NULL);
- ExecuteFind(result, pimpl_->assoc_, dataset.get(), sopClass, false, clevel, pimpl_->dimseTimeout_);
+ ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, false, clevel, pimpl_->dimseTimeout_);
}
@@ -667,21 +672,22 @@ namespace Orthanc
{
CheckIsOpen();
- std::auto_ptr<DcmDataset> dataset(ConvertQueryFields(fields, manufacturer_));
+ std::auto_ptr<ParsedDicomFile> query(ConvertQueryFields(fields, manufacturer_));
+ DcmDataset* dataset = query->GetDcmtkObject().getDataset();
const char* sopClass = UID_MOVEStudyRootQueryRetrieveInformationModel;
switch (level)
{
case ResourceType_Patient:
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "PATIENT");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "PATIENT");
break;
case ResourceType_Study:
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "STUDY");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "STUDY");
break;
case ResourceType_Series:
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "SERIES");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "SERIES");
break;
case ResourceType_Instance:
@@ -691,11 +697,11 @@ namespace Orthanc
// This is a particular case for ClearCanvas, thanks to Peter Somlo <peter.somlo at gmail.com>.
// https://groups.google.com/d/msg/orthanc-users/j-6C3MAVwiw/iolB9hclom8J
// http://www.clearcanvas.ca/Home/Community/OldForums/tabid/526/aff/11/aft/14670/afv/topic/Default.aspx
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "IMAGE");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "IMAGE");
}
else
{
- DU_putStringDOElement(dataset.get(), DcmTagKey(0x0008, 0x0052), "INSTANCE");
+ DU_putStringDOElement(dataset, DcmTagKey(0x0008, 0x0052), "INSTANCE");
}
break;
@@ -721,7 +727,7 @@ namespace Orthanc
T_DIMSE_C_MoveRSP response;
DcmDataset* statusDetail = NULL;
DcmDataset* responseIdentifiers = NULL;
- OFCondition cond = DIMSE_moveUser(pimpl_->assoc_, presID, &request, dataset.get(),
+ OFCondition cond = DIMSE_moveUser(pimpl_->assoc_, presID, &request, dataset,
NULL, NULL,
/*opt_blockMode*/ DIMSE_BLOCKING,
/*opt_dimse_timeout*/ pimpl_->dimseTimeout_,
@@ -782,7 +788,7 @@ namespace Orthanc
remotePort_ = 104;
manufacturer_ = ModalityManufacturer_Generic;
- SetTimeout(10);
+ SetTimeout(defaultTimeout_);
pimpl_->net_ = NULL;
pimpl_->params_ = NULL;
pimpl_->assoc_ = NULL;
@@ -957,6 +963,7 @@ namespace Orthanc
void DicomUserConnection::Store(const char* buffer,
size_t size,
+ const std::string& moveOriginatorAET,
uint16_t moveOriginatorID)
{
// Prepare an input stream for the memory buffer
@@ -965,24 +972,26 @@ namespace Orthanc
is.setBuffer(buffer, size);
is.setEos();
- pimpl_->Store(is, *this, moveOriginatorID);
+ pimpl_->Store(is, *this, moveOriginatorAET, moveOriginatorID);
}
void DicomUserConnection::Store(const std::string& buffer,
+ const std::string& moveOriginatorAET,
uint16_t moveOriginatorID)
{
if (buffer.size() > 0)
- Store(reinterpret_cast<const char*>(&buffer[0]), buffer.size(), moveOriginatorID);
+ Store(reinterpret_cast<const char*>(&buffer[0]), buffer.size(), moveOriginatorAET, moveOriginatorID);
else
- Store(NULL, 0, moveOriginatorID);
+ Store(NULL, 0, moveOriginatorAET, moveOriginatorID);
}
void DicomUserConnection::StoreFile(const std::string& path,
+ const std::string& moveOriginatorAET,
uint16_t moveOriginatorID)
{
// Prepare an input stream for the file
DcmInputFileStream is(path.c_str());
- pimpl_->Store(is, *this, moveOriginatorID);
+ pimpl_->Store(is, *this, moveOriginatorAET, moveOriginatorID);
}
bool DicomUserConnection::Echo()
@@ -1102,14 +1111,16 @@ namespace Orthanc
void DicomUserConnection::SetTimeout(uint32_t seconds)
{
- if (seconds <= 0)
+ if (seconds == 0)
{
- throw OrthancException(ErrorCode_ParameterOutOfRange);
+ DisableTimeout();
+ }
+ else
+ {
+ dcmConnectionTimeout.set(seconds);
+ pimpl_->dimseTimeout_ = seconds;
+ pimpl_->acseTimeout_ = 10; // Timeout used during association negociation
}
-
- dcmConnectionTimeout.set(seconds);
- pimpl_->dimseTimeout_ = seconds;
- pimpl_->acseTimeout_ = 10;
}
@@ -1121,7 +1132,7 @@ namespace Orthanc
*/
dcmConnectionTimeout.set(-1);
pimpl_->dimseTimeout_ = 0;
- pimpl_->acseTimeout_ = 10;
+ pimpl_->acseTimeout_ = 10; // Timeout used during association negociation
}
@@ -1191,4 +1202,12 @@ namespace Orthanc
ExecuteFind(result, pimpl_->assoc_, dataset, sopClass, true, NULL, pimpl_->dimseTimeout_);
}
+
+
+ void DicomUserConnection::SetDefaultTimeout(uint32_t seconds)
+ {
+ LOG(INFO) << "Default timeout for DICOM connections if Orthanc acts as SCU (client): "
+ << seconds << " seconds (0 = no timeout)";
+ defaultTimeout_ = seconds;
+ }
}
diff --git a/OrthancServer/DicomProtocol/DicomUserConnection.h b/OrthancServer/DicomProtocol/DicomUserConnection.h
index 48ea451..6161578 100644
--- a/OrthancServer/DicomProtocol/DicomUserConnection.h
+++ b/OrthancServer/DicomProtocol/DicomUserConnection.h
@@ -135,14 +135,33 @@ namespace Orthanc
void Store(const char* buffer,
size_t size,
+ const std::string& moveOriginatorAET,
uint16_t moveOriginatorID);
+ void Store(const char* buffer,
+ size_t size)
+ {
+ Store(buffer, size, "", 0); // Not a C-Move
+ }
+
void Store(const std::string& buffer,
+ const std::string& moveOriginatorAET,
uint16_t moveOriginatorID);
+ void Store(const std::string& buffer)
+ {
+ Store(buffer, "", 0); // Not a C-Move
+ }
+
void StoreFile(const std::string& path,
+ const std::string& moveOriginatorAET,
uint16_t moveOriginatorID);
+ void StoreFile(const std::string& path)
+ {
+ StoreFile(path, "", 0); // Not a C-Move
+ }
+
void Find(DicomFindAnswers& result,
ResourceType level,
const DicomMap& fields);
@@ -175,5 +194,7 @@ namespace Orthanc
void FindWorklist(DicomFindAnswers& result,
ParsedDicomFile& query);
+
+ static void SetDefaultTimeout(uint32_t seconds);
};
}
diff --git a/OrthancServer/DicomProtocol/IMoveRequestHandler.h b/OrthancServer/DicomProtocol/IMoveRequestHandler.h
index e840e02..44942e6 100644
--- a/OrthancServer/DicomProtocol/IMoveRequestHandler.h
+++ b/OrthancServer/DicomProtocol/IMoveRequestHandler.h
@@ -67,12 +67,12 @@ namespace Orthanc
{
}
- virtual IMoveRequestIterator* Handle(const std::string& target,
+ virtual IMoveRequestIterator* Handle(const std::string& targetAet,
const DicomMap& input,
- const std::string& remoteIp,
- const std::string& remoteAet,
+ const std::string& originatorIp,
+ const std::string& originatorAet,
const std::string& calledAet,
- uint16_t messageId) = 0;
+ uint16_t originatorId) = 0;
};
}
diff --git a/OrthancServer/FromDcmtkBridge.cpp b/OrthancServer/FromDcmtkBridge.cpp
index 921d250..afd33b8 100644
--- a/OrthancServer/FromDcmtkBridge.cpp
+++ b/OrthancServer/FromDcmtkBridge.cpp
@@ -39,8 +39,9 @@
#include "FromDcmtkBridge.h"
#include "ToDcmtkBridge.h"
#include "../Core/Logging.h"
+#include "../Core/SystemToolbox.h"
#include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
+#include "../Core/TemporaryFile.h"
#include "../Core/OrthancException.h"
#include <list>
@@ -118,7 +119,7 @@ namespace Orthanc
std::string content;
EmbeddedResources::GetFileResource(content, resource);
- Toolbox::TemporaryFile tmp;
+ TemporaryFile tmp;
tmp.Write(content);
if (!dictionary.loadDictionary(tmp.GetPath().c_str()))
@@ -144,7 +145,6 @@ namespace Orthanc
throw OrthancException(ErrorCode_InternalError);
}
}
-
#endif
@@ -178,7 +178,7 @@ namespace Orthanc
}
- void FromDcmtkBridge::InitializeDictionary()
+ void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary)
{
{
DictionaryLocker locker;
@@ -195,7 +195,16 @@ namespace Orthanc
//LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICONDE);
LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICOM);
- LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE);
+
+ if (loadPrivateDictionary)
+ {
+ LOG(INFO) << "Loading the embedded dictionary of private tags";
+ LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_PRIVATE);
+ }
+ else
+ {
+ LOG(INFO) << "The dictionary of private tags has not been loaded";
+ }
#elif defined(__linux__) || defined(__FreeBSD_kernel__)
std::string path = DCMTK_DICTIONARY_DIR;
@@ -207,7 +216,15 @@ namespace Orthanc
}
LoadExternalDictionary(*locker, path, "dicom.dic");
- LoadExternalDictionary(*locker, path, "private.dic");
+
+ if (loadPrivateDictionary)
+ {
+ LoadExternalDictionary(*locker, path, "private.dic");
+ }
+ else
+ {
+ LOG(INFO) << "The dictionary of private tags has not been loaded";
+ }
#else
#error Support your platform here
@@ -237,7 +254,8 @@ namespace Orthanc
ValueRepresentation vr,
const std::string& name,
unsigned int minMultiplicity,
- unsigned int maxMultiplicity)
+ unsigned int maxMultiplicity,
+ const std::string& privateCreator)
{
if (minMultiplicity < 1)
{
@@ -261,20 +279,68 @@ namespace Orthanc
<< name << " (multiplicity: " << minMultiplicity << "-"
<< (arbitrary ? "n" : boost::lexical_cast<std::string>(maxMultiplicity)) << ")";
- std::auto_ptr<DcmDictEntry> entry(new DcmDictEntry(tag.GetGroup(),
- tag.GetElement(),
- evr, name.c_str(),
- static_cast<int>(minMultiplicity),
- static_cast<int>(maxMultiplicity),
- NULL /* version */,
- OFTrue /* doCopyString */,
- NULL /* private creator */));
+ std::auto_ptr<DcmDictEntry> entry;
+ if (privateCreator.empty())
+ {
+ if (tag.GetGroup() % 2 == 1)
+ {
+ char buf[128];
+ sprintf(buf, "Warning: You are registering a private tag (%04x,%04x), "
+ "but no private creator was associated with it",
+ tag.GetGroup(), tag.GetElement());
+ LOG(WARNING) << buf;
+ }
+
+ entry.reset(new DcmDictEntry(tag.GetGroup(),
+ tag.GetElement(),
+ evr, name.c_str(),
+ static_cast<int>(minMultiplicity),
+ static_cast<int>(maxMultiplicity),
+ NULL /* version */,
+ OFTrue /* doCopyString */,
+ NULL /* private creator */));
+ }
+ else
+ {
+ // "Private Data Elements have an odd Group Number that is not
+ // (0001,eeee), (0003,eeee), (0005,eeee), (0007,eeee), or
+ // (FFFF,eeee)."
+ if (tag.GetGroup() % 2 == 0 /* even */ ||
+ tag.GetGroup() == 0x0001 ||
+ tag.GetGroup() == 0x0003 ||
+ tag.GetGroup() == 0x0005 ||
+ tag.GetGroup() == 0x0007 ||
+ tag.GetGroup() == 0xffff)
+ {
+ char buf[128];
+ sprintf(buf, "Trying to register private tag (%04x,%04x), but it must have an odd group >= 0x0009",
+ tag.GetGroup(), tag.GetElement());
+ LOG(ERROR) << buf;
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+
+ entry.reset(new DcmDictEntry(tag.GetGroup(),
+ tag.GetElement(),
+ evr, name.c_str(),
+ static_cast<int>(minMultiplicity),
+ static_cast<int>(maxMultiplicity),
+ "private" /* version */,
+ OFTrue /* doCopyString */,
+ privateCreator.c_str()));
+ }
entry->setGroupRangeRestriction(DcmDictRange_Unspecified);
entry->setElementRangeRestriction(DcmDictRange_Unspecified);
{
DictionaryLocker locker;
+
+ if (locker->findEntry(name.c_str()))
+ {
+ LOG(ERROR) << "Cannot register two tags with the same symbolic name \"" << name << "\"";
+ throw OrthancException(ErrorCode_AlreadyExistingTag);
+ }
+
locker->addEntry(entry.release());
}
}
@@ -314,10 +380,10 @@ namespace Orthanc
}
- void FromDcmtkBridge::Convert(DicomMap& target,
- DcmItem& dataset,
- unsigned int maxStringLength,
- Encoding defaultEncoding)
+ void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target,
+ DcmItem& dataset,
+ unsigned int maxStringLength,
+ Encoding defaultEncoding)
{
Encoding encoding = DetectEncoding(dataset, defaultEncoding);
@@ -374,7 +440,7 @@ namespace Orthanc
if (maxStringLength != 0 &&
utf8.size() > maxStringLength)
{
- return new DicomValue; // Create a NULL value
+ return new DicomValue; // Too long, create a NULL value
}
else
{
@@ -383,6 +449,47 @@ namespace Orthanc
}
}
+
+ if (element.getVR() == EVR_UN)
+ {
+ // Unknown value representation: Lookup in the dictionary. This
+ // is notably the case for private tags registered with the
+ // "Dictionary" configuration option.
+ DictionaryLocker locker;
+
+ const DcmDictEntry* entry = locker->findEntry(element.getTag().getXTag(),
+ element.getTag().getPrivateCreator());
+ if (entry != NULL &&
+ entry->getVR().isaString())
+ {
+ Uint8* data = NULL;
+
+ // At (*), we do not try and convert to UTF-8, as nothing says
+ // the encoding of the private tag is the same as that of the
+ // remaining of the DICOM dataset. Only go for ASCII strings.
+
+ if (element.getUint8Array(data) == EC_Normal &&
+ Toolbox::IsAsciiString(data, element.getLength())) // (*)
+ {
+ if (data == NULL)
+ {
+ return new DicomValue("", false); // Empty string
+ }
+ else if (maxStringLength != 0 &&
+ element.getLength() > maxStringLength)
+ {
+ return new DicomValue; // Too long, create a NULL value
+ }
+ else
+ {
+ std::string s(reinterpret_cast<const char*>(data), element.getLength());
+ return new DicomValue(s, false);
+ }
+ }
+ }
+ }
+
+
try
{
// http://support.dcmtk.org/docs/dcvr_8h-source.html
@@ -429,7 +536,7 @@ namespace Orthanc
}
/**
- * Numberic types
+ * Numeric types
**/
case EVR_SL: // signed long
@@ -571,8 +678,7 @@ namespace Orthanc
}
// This code gives access to the name of the private tags
- DcmTag tagbis(element.getTag());
- const std::string tagName(tagbis.getTagName());
+ std::string tagName = FromDcmtkBridge::GetTagName(element);
switch (format)
{
@@ -589,9 +695,9 @@ namespace Orthanc
{
node["Name"] = tagName;
- if (tagbis.getPrivateCreator() != NULL)
+ if (element.getTag().getPrivateCreator() != NULL)
{
- node["PrivateCreator"] = tagbis.getPrivateCreator();
+ node["PrivateCreator"] = element.getTag().getPrivateCreator();
}
return node;
@@ -693,20 +799,12 @@ namespace Orthanc
}
- static void DatasetToJson(Json::Value& parent,
- DcmItem& item,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding encoding);
-
-
- void FromDcmtkBridge::ToJson(Json::Value& parent,
- DcmElement& element,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding encoding)
+ void FromDcmtkBridge::ElementToJson(Json::Value& parent,
+ DcmElement& element,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding encoding)
{
if (parent.type() == Json::nullValue)
{
@@ -718,7 +816,8 @@ namespace Orthanc
if (element.isLeaf())
{
- std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, maxStringLength, encoding));
+ // The "0" below lets "LeafValueToJson()" take care of "TooLong" values
+ std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement(element, flags, 0, encoding));
LeafValueToJson(target, *v, format, flags, maxStringLength);
}
else
@@ -741,12 +840,12 @@ namespace Orthanc
}
- static void DatasetToJson(Json::Value& parent,
- DcmItem& item,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding encoding)
+ void FromDcmtkBridge::DatasetToJson(Json::Value& parent,
+ DcmItem& item,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding encoding)
{
assert(parent.type() == Json::objectValue);
@@ -791,47 +890,53 @@ namespace Orthanc
}
}
- FromDcmtkBridge::ToJson(parent, *element, format, flags, maxStringLength, encoding);
+ FromDcmtkBridge::ElementToJson(parent, *element, format, flags, maxStringLength, encoding);
}
}
- void FromDcmtkBridge::ToJson(Json::Value& target,
- DcmDataset& dataset,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding defaultEncoding)
+ void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target,
+ DcmDataset& dataset,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding defaultEncoding)
{
+ Encoding encoding = DetectEncoding(dataset, defaultEncoding);
+
target = Json::objectValue;
- DatasetToJson(target, dataset, format, flags, maxStringLength, DetectEncoding(dataset, defaultEncoding));
+ DatasetToJson(target, dataset, format, flags, maxStringLength, encoding);
}
- void FromDcmtkBridge::ToJson(Json::Value& target,
- DcmMetaInfo& dataset,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength)
+ void FromDcmtkBridge::ExtractHeaderAsJson(Json::Value& target,
+ DcmMetaInfo& dataset,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength)
{
target = Json::objectValue;
DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii);
}
- std::string FromDcmtkBridge::GetName(const DicomTag& t)
+
+ static std::string GetTagNameInternal(DcmTag& tag)
{
- // Some patches for important tags because of different DICOM
- // dictionaries between DCMTK versions
- std::string n = t.GetMainTagsName();
- if (n.size() != 0)
{
- return n;
+ // Some patches for important tags because of different DICOM
+ // dictionaries between DCMTK versions
+ DicomTag tmp(tag.getGroup(), tag.getElement());
+ std::string n = tmp.GetMainTagsName();
+ if (n.size() != 0)
+ {
+ return n;
+ }
+ // End of patches
}
- // End of patches
#if 0
- DcmTagKey tag(t.GetGroup(), t.GetElement());
+ // This version explicitly calls the dictionary
const DcmDataDictionary& dict = dcmDataDict.rdlock();
const DcmDictEntry* entry = dict.findEntry(tag, NULL);
@@ -844,7 +949,6 @@ namespace Orthanc
dcmDataDict.unlock();
return s;
#else
- DcmTag tag(t.GetGroup(), t.GetElement());
const char* name = tag.getTagName();
if (name == NULL)
{
@@ -858,6 +962,31 @@ namespace Orthanc
}
+ std::string FromDcmtkBridge::GetTagName(const DicomTag& t,
+ const std::string& privateCreator)
+ {
+ DcmTag tag(t.GetGroup(), t.GetElement());
+
+ if (!privateCreator.empty())
+ {
+ tag.setPrivateCreator(privateCreator.c_str());
+ }
+
+ return GetTagNameInternal(tag);
+ }
+
+
+ std::string FromDcmtkBridge::GetTagName(const DcmElement& element)
+ {
+ // Copy the tag to ensure const-correctness of DcmElement. Note
+ // that the private creator information is also copied.
+ DcmTag tag(element.getTag());
+
+ return GetTagNameInternal(tag);
+ }
+
+
+
DicomTag FromDcmtkBridge::ParseTag(const char* name)
{
if (strlen(name) == 9 &&
@@ -942,23 +1071,26 @@ namespace Orthanc
for (DicomMap::Map::const_iterator
it = values.map_.begin(); it != values.map_.end(); ++it)
{
+ // TODO Inject PrivateCreator if some is available in the DicomMap?
+ const std::string tagName = GetTagName(it->first, "");
+
if (simplify)
{
if (it->second->IsNull())
{
- result[GetName(it->first)] = Json::nullValue;
+ result[tagName] = Json::nullValue;
}
else
{
// TODO IsBinary
- result[GetName(it->first)] = it->second->GetContent();
+ result[tagName] = it->second->GetContent();
}
}
else
{
Json::Value value = Json::objectValue;
- value["Name"] = GetName(it->first);
+ value["Name"] = tagName;
if (it->second->IsNull())
{
@@ -988,7 +1120,7 @@ namespace Orthanc
// The "PatientID" field is of type LO (Long String), 64
// Bytes Maximum. An UUID is of length 36, thus it can be used
// as a random PatientID.
- return Toolbox::GenerateUuid();
+ return SystemToolbox::GenerateUuid();
case ResourceType_Instance:
return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT);
@@ -1514,7 +1646,9 @@ namespace Orthanc
if (!ok)
{
- throw OrthancException(ErrorCode_InternalError);
+ LOG(ERROR) << "While creating a DICOM instance, tag (" << tag.Format()
+ << ") has out-of-range value: \"" << *decoded << "\"";
+ throw OrthancException(ErrorCode_BadFileFormat);
}
}
@@ -1533,6 +1667,11 @@ namespace Orthanc
FillElementWithString(*element, tag, value.asString(), decodeDataUriScheme, dicomEncoding);
break;
+ case Json::nullValue:
+ element.reset(CreateElementForTag(tag));
+ FillElementWithString(*element, tag, "", decodeDataUriScheme, dicomEncoding);
+ break;
+
case Json::arrayValue:
{
DcmTag key(tag.GetGroup(), tag.GetElement());
@@ -1610,11 +1749,17 @@ namespace Orthanc
{
const Json::Value& value = json[tags[i]];
if (value.type() != Json::stringValue ||
- !GetDicomEncoding(encoding, value.asCString()))
+ (value.asString().length() != 0 &&
+ !GetDicomEncoding(encoding, value.asCString())))
{
LOG(ERROR) << "Unknown encoding while creating DICOM from JSON: " << value;
throw OrthancException(ErrorCode_BadRequest);
}
+
+ if (value.asString().length() == 0)
+ {
+ return defaultEncoding;
+ }
}
}
@@ -1765,4 +1910,106 @@ namespace Orthanc
target.SetValue(ParseTag(members[i]), value.asString(), false);
}
}
+
+
+ void FromDcmtkBridge::ChangeStringEncoding(DcmItem& dataset,
+ Encoding source,
+ Encoding target)
+ {
+ // Recursive exploration of a dataset to change the encoding of
+ // each string-like element
+
+ if (source == target)
+ {
+ return;
+ }
+
+ for (unsigned long i = 0; i < dataset.card(); i++)
+ {
+ DcmElement* element = dataset.getElement(i);
+ if (element)
+ {
+ if (element->isLeaf())
+ {
+ char *c = NULL;
+ if (element->isaString() &&
+ element->getString(c).good() &&
+ c != NULL)
+ {
+ std::string a = Toolbox::ConvertToUtf8(c, source);
+ std::string b = Toolbox::ConvertFromUtf8(a, target);
+ element->putString(b.c_str());
+ }
+ }
+ else
+ {
+ // "All subclasses of DcmElement except for DcmSequenceOfItems
+ // are leaf nodes, while DcmSequenceOfItems, DcmItem, DcmDataset
+ // etc. are not." The following dynamic_cast is thus OK.
+ DcmSequenceOfItems& sequence = dynamic_cast<DcmSequenceOfItems&>(*element);
+
+ for (unsigned long j = 0; j < sequence.card(); j++)
+ {
+ ChangeStringEncoding(*sequence.getItem(j), source, target);
+ }
+ }
+ }
+ }
+ }
+
+
+ bool FromDcmtkBridge::LookupTransferSyntax(std::string& result,
+ DcmFileFormat& dicom)
+ {
+ const char* value = NULL;
+
+ if (dicom.getMetaInfo() != NULL &&
+ dicom.getMetaInfo()->findAndGetString(DCM_TransferSyntaxUID, value).good() &&
+ value != NULL)
+ {
+ result.assign(value);
+ return true;
+ }
+ else
+ {
+ return false;
+ }
+ }
+
+
+ void FromDcmtkBridge::ExecuteToDicom(DicomMap& target,
+ LuaFunctionCall& call)
+ {
+ Json::Value output;
+ call.ExecuteToJson(output, true /* keep strings */);
+
+ target.Clear();
+
+ if (output.type() == Json::arrayValue &&
+ output.size() == 0)
+ {
+ // This case happens for empty tables
+ return;
+ }
+
+ if (output.type() != Json::objectValue)
+ {
+ LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table";
+ throw OrthancException(ErrorCode_LuaBadOutput);
+ }
+
+ Json::Value::Members members = output.getMemberNames();
+
+ for (size_t i = 0; i < members.size(); i++)
+ {
+ if (output[members[i]].type() != Json::stringValue)
+ {
+ LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table mapping names of DICOM tags to strings";
+ throw OrthancException(ErrorCode_LuaBadOutput);
+ }
+
+ DicomTag tag(ParseTag(members[i]));
+ target.SetValue(tag, output[members[i]].asString(), false);
+ }
+ }
}
diff --git a/OrthancServer/FromDcmtkBridge.h b/OrthancServer/FromDcmtkBridge.h
index eff3b81..d7ee001 100644
--- a/OrthancServer/FromDcmtkBridge.h
+++ b/OrthancServer/FromDcmtkBridge.h
@@ -34,7 +34,9 @@
#include "ServerEnumerations.h"
+#include "../Core/DicomFormat/DicomElement.h"
#include "../Core/DicomFormat/DicomMap.h"
+#include "../Core/Lua/LuaFunctionCall.h"
#include <dcmtk/dcmdata/dcdatset.h>
#include <dcmtk/dcmdata/dcmetinf.h>
@@ -42,27 +44,68 @@
#include <dcmtk/dcmdata/dcfilefo.h>
#include <json/json.h>
+#if ORTHANC_BUILD_UNIT_TESTS == 1
+# include <gtest/gtest_prod.h>
+#endif
+
+
namespace Orthanc
{
- class FromDcmtkBridge
+ class FromDcmtkBridge : public boost::noncopyable
{
+#if ORTHANC_BUILD_UNIT_TESTS == 1
+ FRIEND_TEST(FromDcmtkBridge, FromJson);
+#endif
+
+ friend class ParsedDicomFile;
+ friend class Configuration;
+
+ private:
+ FromDcmtkBridge(); // Pure static class
+
+ static void ExtractDicomSummary(DicomMap& target,
+ DcmItem& dataset,
+ unsigned int maxStringLength,
+ Encoding defaultEncoding);
+
+ static void DatasetToJson(Json::Value& parent,
+ DcmItem& item,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding encoding);
+
+ static void ElementToJson(Json::Value& parent,
+ DcmElement& element,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding dicomEncoding);
+
+ static void ExtractDicomAsJson(Json::Value& target,
+ DcmDataset& dataset,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength,
+ Encoding defaultEncoding);
+
+ static void ChangeStringEncoding(DcmItem& dataset,
+ Encoding source,
+ Encoding target);
+
public:
- static void InitializeDictionary();
+ static void InitializeDictionary(bool loadPrivateDictionary);
static void RegisterDictionaryTag(const DicomTag& tag,
ValueRepresentation vr,
const std::string& name,
unsigned int minMultiplicity,
- unsigned int maxMultiplicity);
+ unsigned int maxMultiplicity,
+ const std::string& privateCreator);
static Encoding DetectEncoding(DcmItem& dataset,
Encoding defaultEncoding);
- static void Convert(DicomMap& target,
- DcmItem& dataset,
- unsigned int maxStringLength,
- Encoding defaultEncoding);
-
static DicomTag Convert(const DcmTag& tag);
static DicomTag GetTag(const DcmElement& element);
@@ -74,27 +117,21 @@ namespace Orthanc
unsigned int maxStringLength,
Encoding encoding);
- static void ToJson(Json::Value& parent,
- DcmElement& element,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding dicomEncoding);
+ static void ExtractHeaderAsJson(Json::Value& target,
+ DcmMetaInfo& header,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength);
- static void ToJson(Json::Value& target,
- DcmDataset& dataset,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength,
- Encoding defaultEncoding);
+ static std::string GetTagName(const DicomTag& tag,
+ const std::string& privateCreator);
- static void ToJson(Json::Value& target,
- DcmMetaInfo& header,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength);
+ static std::string GetTagName(const DcmElement& element);
- static std::string GetName(const DicomTag& tag);
+ static std::string GetTagName(const DicomElement& element)
+ {
+ return GetTagName(element.GetTag(), "");
+ }
static DicomTag ParseTag(const char* name);
@@ -163,5 +200,11 @@ namespace Orthanc
static void FromJson(DicomMap& values,
const Json::Value& result);
+
+ static bool LookupTransferSyntax(std::string& result,
+ DcmFileFormat& dicom);
+
+ static void ExecuteToDicom(DicomMap& target,
+ LuaFunctionCall& call);
};
}
diff --git a/OrthancServer/Internals/CommandDispatcher.cpp b/OrthancServer/Internals/CommandDispatcher.cpp
index 7b56db5..a29690b 100644
--- a/OrthancServer/Internals/CommandDispatcher.cpp
+++ b/OrthancServer/Internals/CommandDispatcher.cpp
@@ -381,7 +381,6 @@ namespace Orthanc
OFCondition AssociationCleanup(T_ASC_Association *assoc)
{
- OFString temp_str;
OFCondition cond = ASC_dropSCPAssociation(assoc);
if (cond.bad())
{
@@ -695,6 +694,38 @@ namespace Orthanc
return new CommandDispatcher(server, assoc, remoteIp, remoteAet, calledAet, filter);
}
+
+ CommandDispatcher::CommandDispatcher(const DicomServer& server,
+ T_ASC_Association* assoc,
+ const std::string& remoteIp,
+ const std::string& remoteAet,
+ const std::string& calledAet,
+ IApplicationEntityFilter* filter) :
+ server_(server),
+ assoc_(assoc),
+ remoteIp_(remoteIp),
+ remoteAet_(remoteAet),
+ calledAet_(calledAet),
+ filter_(filter)
+ {
+ associationTimeout_ = server.GetAssociationTimeout();
+ elapsedTimeSinceLastCommand_ = 0;
+ }
+
+
+ CommandDispatcher::~CommandDispatcher()
+ {
+ try
+ {
+ AssociationCleanup(assoc_);
+ }
+ catch (...)
+ {
+ LOG(ERROR) << "Some association was not cleanly aborted";
+ }
+ }
+
+
bool CommandDispatcher::Step()
/*
* This function receives DIMSE commmands over the network connection
@@ -727,16 +758,16 @@ namespace Orthanc
else if (cond == DIMSE_NODATAAVAILABLE)
{
// Timeout due to DIMSE_NONBLOCKING
- if (clientTimeout_ != 0 &&
- elapsedTimeSinceLastCommand_ >= clientTimeout_)
+ if (associationTimeout_ != 0 &&
+ elapsedTimeSinceLastCommand_ >= associationTimeout_)
{
- // This timeout is actually a client timeout
+ // This timeout is actually a association timeout
finished = true;
}
}
else if (cond == EC_Normal)
{
- // Reset the client timeout counter
+ // Reset the association timeout counter
elapsedTimeSinceLastCommand_ = 0;
// Convert the type of request to Orthanc's internal type
diff --git a/OrthancServer/Internals/CommandDispatcher.h b/OrthancServer/Internals/CommandDispatcher.h
index 35dd970..eeb8559 100644
--- a/OrthancServer/Internals/CommandDispatcher.h
+++ b/OrthancServer/Internals/CommandDispatcher.h
@@ -46,7 +46,7 @@ namespace Orthanc
class CommandDispatcher : public IRunnableBySteps
{
private:
- uint32_t clientTimeout_;
+ uint32_t associationTimeout_;
uint32_t elapsedTimeSinceLastCommand_;
const DicomServer& server_;
T_ASC_Association* assoc_;
@@ -61,22 +61,9 @@ namespace Orthanc
const std::string& remoteIp,
const std::string& remoteAet,
const std::string& calledAet,
- IApplicationEntityFilter* filter) :
- server_(server),
- assoc_(assoc),
- remoteIp_(remoteIp),
- remoteAet_(remoteAet),
- calledAet_(calledAet),
- filter_(filter)
- {
- clientTimeout_ = server.GetClientTimeout();
- elapsedTimeSinceLastCommand_ = 0;
- }
+ IApplicationEntityFilter* filter);
- virtual ~CommandDispatcher()
- {
- AssociationCleanup(assoc_);
- }
+ virtual ~CommandDispatcher();
virtual bool Step();
};
diff --git a/OrthancServer/Internals/DicomFrameIndex.cpp b/OrthancServer/Internals/DicomFrameIndex.cpp
index c157656..8e8aaf4 100644
--- a/OrthancServer/Internals/DicomFrameIndex.cpp
+++ b/OrthancServer/Internals/DicomFrameIndex.cpp
@@ -404,8 +404,7 @@ namespace Orthanc
// Extract information about the image structure
DicomMap tags;
- FromDcmtkBridge::Convert(tags, dataset, ORTHANC_MAXIMUM_TAG_LENGTH,
- Configuration::GetDefaultEncoding());
+ Configuration::ExtractDicomSummary(tags, dataset);
DicomImageInformation information(tags);
diff --git a/OrthancServer/Internals/DicomImageDecoder.cpp b/OrthancServer/Internals/DicomImageDecoder.cpp
index a78bea8..6165090 100644
--- a/OrthancServer/Internals/DicomImageDecoder.cpp
+++ b/OrthancServer/Internals/DicomImageDecoder.cpp
@@ -94,13 +94,13 @@
#include <dcmtk/dcmdata/dcrleccd.h>
#include <dcmtk/dcmdata/dcrlecp.h>
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
# include <dcmtk/dcmjpls/djcodecd.h>
# include <dcmtk/dcmjpls/djcparam.h>
# include <dcmtk/dcmjpeg/djrplol.h>
#endif
-#if ORTHANC_JPEG_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG == 1
# include <dcmtk/dcmjpeg/djcodecd.h>
# include <dcmtk/dcmjpeg/djcparam.h>
# include <dcmtk/dcmjpeg/djdecbas.h>
@@ -250,8 +250,7 @@ namespace Orthanc
// See also: http://support.dcmtk.org/wiki/dcmtk/howto/accessing-compressed-data
DicomMap m;
- FromDcmtkBridge::Convert(m, dataset, ORTHANC_MAXIMUM_TAG_LENGTH,
- Configuration::GetDefaultEncoding());
+ Configuration::ExtractDicomSummary(m, dataset);
/**
* Create an accessor to the raw values of the DICOM image.
@@ -323,8 +322,7 @@ namespace Orthanc
bool ignorePhotometricInterpretation)
{
DicomMap m;
- FromDcmtkBridge::Convert(m, dataset, ORTHANC_MAXIMUM_TAG_LENGTH,
- Configuration::GetDefaultEncoding());
+ Configuration::ExtractDicomSummary(m, dataset);
DicomImageInformation info(m);
PixelFormat format;
@@ -340,7 +338,7 @@ namespace Orthanc
throw OrthancException(ErrorCode_NotImplemented);
}
- return new Image(format, info.GetWidth(), info.GetHeight());
+ return new Image(format, info.GetWidth(), info.GetHeight(), false);
}
@@ -519,7 +517,7 @@ namespace Orthanc
}
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
/**
* Deal with JPEG-LS images.
**/
@@ -551,7 +549,7 @@ namespace Orthanc
#endif
-#if ORTHANC_JPEG_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG == 1
/**
* Deal with JPEG images.
**/
@@ -674,7 +672,7 @@ namespace Orthanc
if (image->GetFormat() != format)
{
// A conversion is required
- std::auto_ptr<ImageAccessor> target(new Image(format, image->GetWidth(), image->GetHeight()));
+ std::auto_ptr<ImageAccessor> target(new Image(format, image->GetWidth(), image->GetHeight(), false));
ImageProcessing::Convert(*target, *image);
image = target;
}
@@ -713,7 +711,7 @@ namespace Orthanc
// If the source image is not grayscale 8bpp, convert it
if (image->GetFormat() != PixelFormat_Grayscale8)
{
- std::auto_ptr<ImageAccessor> target(new Image(PixelFormat_Grayscale8, image->GetWidth(), image->GetHeight()));
+ std::auto_ptr<ImageAccessor> target(new Image(PixelFormat_Grayscale8, image->GetWidth(), image->GetHeight(), false));
ImageProcessing::Convert(*target, *image);
image = target;
}
diff --git a/OrthancServer/Internals/DicomImageDecoder.h b/OrthancServer/Internals/DicomImageDecoder.h
index 9c1d752..97a9278 100644
--- a/OrthancServer/Internals/DicomImageDecoder.h
+++ b/OrthancServer/Internals/DicomImageDecoder.h
@@ -36,6 +36,15 @@
#include <memory>
+#if !defined(ORTHANC_ENABLE_JPEG)
+# error The macro ORTHANC_ENABLE_JPEG must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_JPEG_LOSSLESS)
+# error The macro ORTHANC_ENABLE_JPEG_LOSSLESS must be defined
+#endif
+
+
class DcmDataset;
class DcmCodec;
class DcmCodecParameter;
diff --git a/OrthancServer/Internals/FindScp.cpp b/OrthancServer/Internals/FindScp.cpp
index da96e1f..b3a52e0 100644
--- a/OrthancServer/Internals/FindScp.cpp
+++ b/OrthancServer/Internals/FindScp.cpp
@@ -89,6 +89,48 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../OrthancInitialization.h"
#include <dcmtk/dcmdata/dcfilefo.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
+
+
+
+/**
+ * The function below is extracted from DCMTK 3.6.0, cf. file
+ * "dcmtk-3.6.0/dcmwlm/libsrc/wldsfs.cc".
+ **/
+
+static void HandleExistentButEmptyReferencedStudyOrPatientSequenceAttributes(DcmDataset *dataset,
+ const DcmTagKey &sequenceTagKey)
+// Date : May 3, 2005
+// Author : Thomas Wilkens
+// Task : This function performs a check on a sequence attribute in the given dataset. At two different places
+// in the definition of the DICOM worklist management service, a sequence attribute with a return type
+// of 2 is mentioned containing two 1C attributes in its item; the condition of the two 1C attributes
+// specifies that in case a sequence item is present, then these two attributes must be existent and
+// must contain a value. (I am talking about ReferencedStudySequence and ReferencedPatientSequence.)
+// In cases where the sequence attribute contains exactly one item with an empty ReferencedSOPClass
+// and an empty ReferencedSOPInstance, we want to remove the item from the sequence. This is what
+// this function does.
+// Parameters : dataset - [in] Dataset in which the consistency of the sequence attribute shall be checked.
+// sequenceTagKey - [in] DcmTagKey of the sequence attribute which shall be checked.
+// Return Value : none.
+{
+ DcmElement *sequenceAttribute = NULL, *referencedSOPClassUIDAttribute = NULL, *referencedSOPInstanceUIDAttribute = NULL;
+
+ // in case the sequence attribute contains exactly one item with an empty
+ // ReferencedSOPClassUID and an empty ReferencedSOPInstanceUID, remove the item
+ if( dataset->findAndGetElement( sequenceTagKey, sequenceAttribute ).good() &&
+ ( (DcmSequenceOfItems*)sequenceAttribute )->card() == 1 &&
+ ( (DcmSequenceOfItems*)sequenceAttribute )->getItem(0)->findAndGetElement( DCM_ReferencedSOPClassUID, referencedSOPClassUIDAttribute ).good() &&
+ referencedSOPClassUIDAttribute->getLength() == 0 &&
+ ( (DcmSequenceOfItems*)sequenceAttribute )->getItem(0)->findAndGetElement( DCM_ReferencedSOPInstanceUID, referencedSOPInstanceUIDAttribute, OFFalse ).good() &&
+ referencedSOPInstanceUIDAttribute->getLength() == 0 )
+ {
+ DcmItem *item = ((DcmSequenceOfItems*)sequenceAttribute)->remove( ((DcmSequenceOfItems*)sequenceAttribute)->getItem(0) );
+ delete item;
+ }
+}
+
+
namespace Orthanc
{
@@ -103,9 +145,27 @@ namespace Orthanc
const std::string* remoteIp_;
const std::string* remoteAet_;
const std::string* calledAet_;
+
+ FindScpData() : answers_(false)
+ {
+ }
};
+
+ static void FixWorklistQuery(ParsedDicomFile& query)
+ {
+ // TODO: Check out
+ // WlmDataSourceFileSystem::HandleExistentButEmptyDescriptionAndCodeSequenceAttributes()"
+ // in DCMTK 3.6.0
+
+ DcmDataset* dataset = query.GetDcmtkObject().getDataset();
+ HandleExistentButEmptyReferencedStudyOrPatientSequenceAttributes(dataset, DCM_ReferencedStudySequence);
+ HandleExistentButEmptyReferencedStudyOrPatientSequenceAttributes(dataset, DCM_ReferencedPatientSequence);
+ }
+
+
+
void FindScpCallback(
/* in */
void *callbackData,
@@ -132,9 +192,13 @@ namespace Orthanc
{
if (sopClassUid == UID_FINDModalityWorklistInformationModel)
{
+ data.answers_.SetWorklist(true);
+
if (data.worklistHandler_ != NULL)
{
ParsedDicomFile query(*requestIdentifiers);
+ FixWorklistQuery(query);
+
data.worklistHandler_->Handle(data.answers_, query,
*data.remoteIp_, *data.remoteAet_,
*data.calledAet_);
@@ -147,6 +211,8 @@ namespace Orthanc
}
else
{
+ data.answers_.SetWorklist(false);
+
if (data.findHandler_ != NULL)
{
std::list<DicomTag> sequencesToReturn;
@@ -163,7 +229,7 @@ namespace Orthanc
{
LOG(WARNING) << "Orthanc only supports sequence matching on worklists, "
<< "ignoring C-FIND SCU constraint on tag (" << tag.Format()
- << ") " << FromDcmtkBridge::GetName(tag);
+ << ") " << FromDcmtkBridge::GetTagName(*element);
}
sequencesToReturn.push_back(tag);
@@ -171,8 +237,8 @@ namespace Orthanc
}
DicomMap input;
- FromDcmtkBridge::Convert(input, *requestIdentifiers, ORTHANC_MAXIMUM_TAG_LENGTH,
- Configuration::GetDefaultEncoding());
+ Configuration::ExtractDicomSummary(input, *requestIdentifiers);
+
data.findHandler_->Handle(data.answers_, input, sequencesToReturn,
*data.remoteIp_, *data.remoteAet_,
*data.calledAet_);
diff --git a/OrthancServer/Internals/MoveScp.cpp b/OrthancServer/Internals/MoveScp.cpp
index 1b0ba1d..a37b8f5 100644
--- a/OrthancServer/Internals/MoveScp.cpp
+++ b/OrthancServer/Internals/MoveScp.cpp
@@ -90,6 +90,8 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../../Core/Logging.h"
#include "../../Core/OrthancException.h"
+#include <boost/lexical_cast.hpp>
+
namespace Orthanc
{
@@ -110,6 +112,42 @@ namespace Orthanc
};
+
+ static uint16_t GetMessageId(const DicomMap& message)
+ {
+ /**
+ * Retrieve the Message ID (0000,0110) for this C-MOVE request, if
+ * any. If present, this Message ID will be stored in the Move
+ * Originator Message ID (0000,1031) field of the C-MOVE response.
+ * http://dicom.nema.org/dicom/2013/output/chtml/part07/chapter_E.html
+ **/
+
+ const DicomValue* value = message.TestAndGetValue(DICOM_TAG_MESSAGE_ID);
+
+ if (value != NULL &&
+ !value->IsNull() &&
+ !value->IsBinary())
+ {
+ try
+ {
+ int tmp = boost::lexical_cast<int>(value->GetContent());
+ if (tmp >= 0 && tmp <= 0xffff)
+ {
+ return static_cast<uint16_t>(tmp);
+ }
+ }
+ catch (boost::bad_lexical_cast&)
+ {
+ LOG(WARNING) << "Cannot convert the Message ID (\"" << value->GetContent()
+ << "\") of an incoming C-MOVE request to an integer, assuming zero";
+ }
+ }
+
+ return 0;
+ }
+
+
+
void MoveScpCallback(
/* in */
void *callbackData,
@@ -130,14 +168,12 @@ namespace Orthanc
if (data.lastRequest_ == NULL)
{
DicomMap input;
- FromDcmtkBridge::Convert(input, *requestIdentifiers, ORTHANC_MAXIMUM_TAG_LENGTH,
- Configuration::GetDefaultEncoding());
+ Configuration::ExtractDicomSummary(input, *requestIdentifiers);
try
{
- data.iterator_.reset(data.handler_->Handle(data.target_, input,
- *data.remoteIp_, *data.remoteAet_,
- *data.calledAet_, request->MessageID));
+ data.iterator_.reset(data.handler_->Handle(data.target_, input, *data.remoteIp_, *data.remoteAet_,
+ *data.calledAet_, GetMessageId(input)));
if (data.iterator_.get() == NULL)
{
diff --git a/OrthancServer/Internals/StoreScp.cpp b/OrthancServer/Internals/StoreScp.cpp
index 2f57b02..30b9025 100644
--- a/OrthancServer/Internals/StoreScp.cpp
+++ b/OrthancServer/Internals/StoreScp.cpp
@@ -168,15 +168,8 @@ namespace Orthanc
try
{
- const Encoding defaultEncoding = Configuration::GetDefaultEncoding();
- FromDcmtkBridge::Convert(summary, **imageDataSet,
- ORTHANC_MAXIMUM_TAG_LENGTH,
- defaultEncoding);
- FromDcmtkBridge::ToJson(dicomJson, **imageDataSet,
- DicomToJsonFormat_Full,
- DicomToJsonFlags_Default,
- ORTHANC_MAXIMUM_TAG_LENGTH,
- defaultEncoding);
+ Configuration::ExtractDicomSummary(summary, **imageDataSet);
+ Configuration::ExtractDicomAsJson(dicomJson, **imageDataSet);
if (!FromDcmtkBridge::SaveToMemoryBuffer(buffer, **imageDataSet))
{
@@ -219,7 +212,7 @@ namespace Orthanc
if (e.GetErrorCode() == ErrorCode_InexistentTag)
{
- Toolbox::LogMissingRequiredTag(summary);
+ ServerToolbox::LogMissingRequiredTag(summary);
}
else
{
diff --git a/OrthancServer/LuaScripting.cpp b/OrthancServer/LuaScripting.cpp
index 4d961e2..d80cd0a 100644
--- a/OrthancServer/LuaScripting.cpp
+++ b/OrthancServer/LuaScripting.cpp
@@ -252,9 +252,10 @@ namespace Orthanc
std::string modality = parameters["Modality"].asString();
LOG(INFO) << "Lua script to send resource " << parameters["Resource"].asString()
<< " to modality " << modality << " using Store-SCU";
+
+ // This is not a C-MOVE: No need to call "StoreScuCommand::SetMoveOriginator()"
return new StoreScuCommand(context_, localAet,
- Configuration::GetModalityUsingSymbolicName(modality),
- true, 0 /* not a C-MOVE */);
+ Configuration::GetModalityUsingSymbolicName(modality), true);
}
if (operation == "store-peer")
diff --git a/OrthancServer/OrthancFindRequestHandler.cpp b/OrthancServer/OrthancFindRequestHandler.cpp
index f451083..2134ff1 100644
--- a/OrthancServer/OrthancFindRequestHandler.cpp
+++ b/OrthancServer/OrthancFindRequestHandler.cpp
@@ -107,10 +107,34 @@ namespace Orthanc
}
- static void ExtractTagFromInstances(std::set<std::string>& target,
- ServerContext& context,
- const DicomTag& tag,
- const std::list<std::string>& instances)
+ static bool ExtractMetadata(std::set<std::string>& target,
+ ServerIndex& index,
+ MetadataType metadata,
+ const std::list<std::string>& resources)
+ {
+ for (std::list<std::string>::const_iterator
+ it = resources.begin(); it != resources.end(); ++it)
+ {
+ std::string value;
+ if (index.LookupMetadata(value, *it, metadata))
+ {
+ target.insert(value);
+ }
+ else
+ {
+ // This metadata is unavailable for some resource, give up
+ return false;
+ }
+ }
+
+ return true;
+ }
+
+
+ static void ExtractTagFromInstancesOnDisk(std::set<std::string>& target,
+ ServerContext& context,
+ const DicomTag& tag,
+ const std::list<std::string>& instances)
{
// WARNING: This function is slow, as it reads the JSON file
// summarizing each instance of interest from the hard drive.
@@ -121,7 +145,7 @@ namespace Orthanc
it = instances.begin(); it != instances.end(); ++it)
{
Json::Value dicom;
- context.ReadJson(dicom, *it);
+ context.ReadDicomAsJson(dicom, *it);
if (dicom.isMember(formatted))
{
@@ -226,10 +250,16 @@ namespace Orthanc
if (query.HasTag(DICOM_TAG_SOP_CLASSES_IN_STUDY))
{
- if (Configuration::GetGlobalBoolParameter("AllowFindSopClassesInStudy", false))
+ std::set<std::string> values;
+
+ if (ExtractMetadata(values, index, MetadataType_Instance_SopClassUid, instances))
{
- std::set<std::string> values;
- ExtractTagFromInstances(values, context, DICOM_TAG_SOP_CLASS_UID, instances);
+ // The metadata "SopClassUid" is available for each of these instances
+ StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values);
+ }
+ else if (Configuration::GetGlobalBoolParameter("AllowFindSopClassesInStudy", false))
+ {
+ ExtractTagFromInstancesOnDisk(values, context, DICOM_TAG_SOP_CLASS_UID, instances);
StoreSetOfStrings(result, DICOM_TAG_SOP_CLASSES_IN_STUDY, values);
}
else
@@ -401,7 +431,7 @@ namespace Orthanc
for (Json::Value::ArrayIndex i = 0; i < source["Value"].size(); i++)
{
Json::Value item;
- Toolbox::SimplifyTags(item, source["Value"][i], DicomToJsonFormat_Short);
+ ServerToolbox::SimplifyTags(item, source["Value"][i], DicomToJsonFormat_Short);
content.append(item);
}
@@ -456,62 +486,27 @@ namespace Orthanc
const std::string& remoteAet,
const std::string& calledAet)
{
- Json::Value output;
+ static const char* LUA_CALLBACK = "IncomingFindRequestFilter";
+ LuaScripting::Locker locker(context_.GetLua());
+ if (!locker.GetLua().IsExistingFunction(LUA_CALLBACK))
+ {
+ return false;
+ }
+ else
{
- LuaScripting::Locker locker(context_.GetLua());
- static const char* NAME = "IncomingFindRequestFilter";
-
- if (!locker.GetLua().IsExistingFunction(NAME))
- {
- return false;
- }
-
- Json::Value tmp = Json::objectValue;
- DicomArray a(source);
-
- for (size_t i = 0; i < a.GetSize(); i++)
- {
- const DicomValue& v = a.GetElement(i).GetValue();
- std::string s = (v.IsNull() || v.IsBinary()) ? "" : v.GetContent();
- tmp[a.GetElement(i).GetTag().Format()] = s;
- }
-
Json::Value origin = Json::objectValue;
origin["RemoteIp"] = remoteIp;
origin["RemoteAet"] = remoteAet;
origin["CalledAet"] = calledAet;
- LuaFunctionCall call(locker.GetLua(), NAME);
- call.PushJson(tmp);
+ LuaFunctionCall call(locker.GetLua(), LUA_CALLBACK);
+ call.PushDicom(source);
call.PushJson(origin);
+ FromDcmtkBridge::ExecuteToDicom(target, call);
- call.ExecuteToJson(output, true);
+ return true;
}
-
- // The Lua context is released at this point
-
- if (output.type() != Json::objectValue)
- {
- LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table";
- throw OrthancException(ErrorCode_LuaBadOutput);
- }
-
- Json::Value::Members members = output.getMemberNames();
-
- for (size_t i = 0; i < members.size(); i++)
- {
- if (output[members[i]].type() != Json::stringValue)
- {
- LOG(ERROR) << "Lua: IncomingFindRequestFilter must return a table mapping names of DICOM tags to strings";
- throw OrthancException(ErrorCode_LuaBadOutput);
- }
-
- DicomTag tag(FromDcmtkBridge::ParseTag(members[i]));
- target.SetValue(tag, output[members[i]].asString(), false);
- }
-
- return true;
}
@@ -582,7 +577,7 @@ namespace Orthanc
if (!query.GetElement(i).GetValue().IsNull())
{
LOG(INFO) << " " << query.GetElement(i).GetTag()
- << " " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag())
+ << " " << FromDcmtkBridge::GetTagName(query.GetElement(i))
<< " = " << query.GetElement(i).GetValue().GetContent();
}
}
@@ -591,7 +586,7 @@ namespace Orthanc
it != sequencesToReturn.end(); ++it)
{
LOG(INFO) << " (" << it->Format()
- << ") " << FromDcmtkBridge::GetName(*it)
+ << ") " << FromDcmtkBridge::GetTagName(*it, "")
<< " : sequence tag whose content will be copied";
}
@@ -604,16 +599,17 @@ namespace Orthanc
for (size_t i = 0; i < query.GetSize(); i++)
{
- const DicomTag tag = query.GetElement(i).GetTag();
+ const DicomElement& element = query.GetElement(i);
+ const DicomTag tag = element.GetTag();
- if (query.GetElement(i).GetValue().IsNull() ||
+ if (element.GetValue().IsNull() ||
tag == DICOM_TAG_QUERY_RETRIEVE_LEVEL ||
tag == DICOM_TAG_SPECIFIC_CHARACTER_SET)
{
continue;
}
- std::string value = query.GetElement(i).GetValue().GetContent();
+ std::string value = element.GetValue().GetContent();
if (value.size() == 0)
{
// An empty string corresponds to a "*" wildcard constraint, so we ignore it
@@ -637,7 +633,7 @@ namespace Orthanc
else
{
LOG(INFO) << "Because of a patch for the manufacturer of the remote modality, "
- << "ignoring constraint on tag (" << tag.Format() << ") " << FromDcmtkBridge::GetName(tag);
+ << "ignoring constraint on tag (" << tag.Format() << ") " << FromDcmtkBridge::GetTagName(element);
}
}
@@ -651,13 +647,15 @@ namespace Orthanc
std::vector<std::string> resources, instances;
context_.GetIndex().FindCandidates(resources, instances, finder);
+ LOG(INFO) << "Number of candidate resources after fast DB filtering: " << resources.size();
+
assert(resources.size() == instances.size());
bool complete = true;
for (size_t i = 0; i < instances.size(); i++)
{
Json::Value dicom;
- context_.ReadJson(dicom, instances[i]);
+ context_.ReadDicomAsJson(dicom, instances[i]);
if (finder.IsMatch(dicom))
{
@@ -669,7 +667,7 @@ namespace Orthanc
}
else
{
- std::auto_ptr<DicomMap> counters(ComputeCounters(context_, instances[i], level, input));
+ std::auto_ptr<DicomMap> counters(ComputeCounters(context_, instances[i], level, *filteredInput));
AddAnswer(answers, dicom, query, sequencesToReturn, counters.get());
}
}
diff --git a/OrthancServer/OrthancInitialization.cpp b/OrthancServer/OrthancInitialization.cpp
index a498a67..a4e2830 100644
--- a/OrthancServer/OrthancInitialization.cpp
+++ b/OrthancServer/OrthancInitialization.cpp
@@ -47,26 +47,16 @@
#include <boost/lexical_cast.hpp>
#include <boost/filesystem.hpp>
#include <curl/curl.h>
-#include <boost/thread.hpp>
+#include <boost/thread/recursive_mutex.hpp>
-#if ORTHANC_SSL_ENABLED == 1
-// For OpenSSL initialization and finalization
-#include <openssl/conf.h>
-#include <openssl/engine.h>
-#include <openssl/err.h>
-#include <openssl/evp.h>
-#include <openssl/ssl.h>
+#if ORTHANC_ENABLE_JPEG == 1
+# include <dcmtk/dcmjpeg/djdecode.h>
#endif
-#if ORTHANC_JPEG_ENABLED == 1
-#include <dcmtk/dcmjpeg/djdecode.h>
-#endif
-
-
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
-#include <dcmtk/dcmjpls/djdecode.h>
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
+# include <dcmtk/dcmjpls/djdecode.h>
#endif
@@ -138,7 +128,7 @@ namespace Orthanc
{
std::string content;
- Toolbox::ReadFile(content, path.string());
+ SystemToolbox::ReadFile(content, path.string());
Json::Value tmp;
Json::Reader reader;
@@ -404,11 +394,12 @@ namespace Orthanc
const Json::Value& content = configuration["Dictionary"][tags[i]];
if (content.type() != Json::arrayValue ||
content.size() < 2 ||
- content.size() > 4 ||
+ content.size() > 5 ||
content[0].type() != Json::stringValue ||
content[1].type() != Json::stringValue ||
(content.size() >= 3 && content[2].type() != Json::intValue) ||
- (content.size() >= 4 && content[3].type() != Json::intValue))
+ (content.size() >= 4 && content[3].type() != Json::intValue) ||
+ (content.size() >= 5 && content[4].type() != Json::stringValue))
{
throw OrthancException(ErrorCode_BadFileFormat);
}
@@ -418,8 +409,9 @@ namespace Orthanc
std::string name = content[1].asString();
unsigned int minMultiplicity = (content.size() >= 2) ? content[2].asUInt() : 1;
unsigned int maxMultiplicity = (content.size() >= 3) ? content[3].asUInt() : 1;
+ std::string privateCreator = (content.size() >= 4) ? content[4].asString() : "";
- FromDcmtkBridge::RegisterDictionaryTag(tag, vr, name, minMultiplicity, maxMultiplicity);
+ FromDcmtkBridge::RegisterDictionaryTag(tag, vr, name, minMultiplicity, maxMultiplicity, privateCreator);
}
}
@@ -471,13 +463,7 @@ namespace Orthanc
{
boost::recursive_mutex::scoped_lock lock(globalMutex_);
-#if ORTHANC_SSL_ENABLED == 1
- // https://wiki.openssl.org/index.php/Library_Initialization
- SSL_library_init();
- SSL_load_error_strings();
- OpenSSL_add_all_algorithms();
- ERR_load_crypto_strings();
-#endif
+ HttpClient::InitializeOpenSsl();
InitializeServerEnumerations();
@@ -495,15 +481,15 @@ namespace Orthanc
RegisterUserMetadata();
RegisterUserContentType();
- FromDcmtkBridge::InitializeDictionary();
+ FromDcmtkBridge::InitializeDictionary(GetGlobalBoolParameterInternal("LoadPrivateDictionary", true));
LoadCustomDictionary(configuration_);
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
LOG(WARNING) << "Registering JPEG Lossless codecs";
DJLSDecoderRegistration::registerCodecs();
#endif
-#if ORTHANC_JPEG_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG == 1
LOG(WARNING) << "Registering JPEG codecs";
DJDecoderRegistration::registerCodecs();
#endif
@@ -521,27 +507,17 @@ namespace Orthanc
boost::recursive_mutex::scoped_lock lock(globalMutex_);
HttpClient::GlobalFinalize();
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
// Unregister JPEG-LS codecs
DJLSDecoderRegistration::cleanup();
#endif
-#if ORTHANC_JPEG_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG == 1
// Unregister JPEG codecs
DJDecoderRegistration::cleanup();
#endif
-#if ORTHANC_SSL_ENABLED == 1
- // Finalize OpenSSL
- // https://wiki.openssl.org/index.php/Library_Initialization#Cleanup
- FIPS_mode_set(0);
- ENGINE_cleanup();
- CONF_modules_unload(1);
- EVP_cleanup();
- CRYPTO_cleanup_all_ex_data();
- ERR_remove_state(0);
- ERR_free_strings();
-#endif
+ HttpClient::FinalizeOpenSsl();
}
@@ -577,6 +553,23 @@ namespace Orthanc
}
+ unsigned int Configuration::GetGlobalUnsignedIntegerParameter(const std::string& parameter,
+ unsigned int defaultValue)
+ {
+ int v = GetGlobalIntegerParameter(parameter, defaultValue);
+
+ if (v < 0)
+ {
+ LOG(ERROR) << "The configuration option \"" << parameter << "\" must be a positive integer";
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+ else
+ {
+ return static_cast<unsigned int>(v);
+ }
+ }
+
+
bool Configuration::GetGlobalBoolParameter(const std::string& parameter,
bool defaultValue)
{
@@ -1118,6 +1111,19 @@ namespace Orthanc
}
+ void Configuration::SetDefaultEncoding(Encoding encoding)
+ {
+ std::string name = EnumerationToString(encoding);
+
+ {
+ boost::recursive_mutex::scoped_lock lock(globalMutex_);
+ configuration_["DefaultEncoding"] = name;
+ }
+
+ LOG(INFO) << "Default encoding was changed to: " << name;
+ }
+
+
bool Configuration::HasConfigurationChanged()
{
Json::Value starting;
@@ -1132,4 +1138,21 @@ namespace Orthanc
return a != b;
}
+
+
+ void Configuration::ExtractDicomSummary(DicomMap& target,
+ DcmItem& dataset)
+ {
+ FromDcmtkBridge::ExtractDicomSummary(target, dataset,
+ ORTHANC_MAXIMUM_TAG_LENGTH, GetDefaultEncoding());
+ }
+
+
+ void Configuration::ExtractDicomAsJson(Json::Value& target,
+ DcmDataset& dataset)
+ {
+ FromDcmtkBridge::ExtractDicomAsJson(target, dataset,
+ DicomToJsonFormat_Full, DicomToJsonFlags_Default,
+ ORTHANC_MAXIMUM_TAG_LENGTH, GetDefaultEncoding());
+ }
}
diff --git a/OrthancServer/OrthancInitialization.h b/OrthancServer/OrthancInitialization.h
index b2dc0cc..7218335 100644
--- a/OrthancServer/OrthancInitialization.h
+++ b/OrthancServer/OrthancInitialization.h
@@ -46,6 +46,18 @@
#include "IDatabaseWrapper.h"
#include "ServerEnumerations.h"
+#if !defined(ORTHANC_ENABLE_JPEG)
+# error The macro ORTHANC_ENABLE_JPEG must be defined
+#endif
+
+#if !defined(ORTHANC_ENABLE_JPEG_LOSSLESS)
+# error The macro ORTHANC_ENABLE_JPEG_LOSSLESS must be defined
+#endif
+
+
+class DcmDataset;
+class DcmItem;
+
namespace Orthanc
{
void OrthancInitialize(const char* configurationFile = NULL);
@@ -64,6 +76,9 @@ namespace Orthanc
static int GetGlobalIntegerParameter(const std::string& parameter,
int defaultValue);
+ static unsigned int GetGlobalUnsignedIntegerParameter(const std::string& parameter,
+ unsigned int defaultValue);
+
static bool GetGlobalBoolParameter(const std::string& parameter,
bool defaultValue);
@@ -123,6 +138,14 @@ namespace Orthanc
static Encoding GetDefaultEncoding();
+ static void SetDefaultEncoding(Encoding encoding);
+
static bool HasConfigurationChanged();
+
+ static void ExtractDicomSummary(DicomMap& target,
+ DcmItem& dataset);
+
+ static void ExtractDicomAsJson(Json::Value& target,
+ DcmDataset& dataset);
};
}
diff --git a/OrthancServer/OrthancMoveRequestHandler.cpp b/OrthancServer/OrthancMoveRequestHandler.cpp
index 240b703..b48f5a1 100644
--- a/OrthancServer/OrthancMoveRequestHandler.cpp
+++ b/OrthancServer/OrthancMoveRequestHandler.cpp
@@ -52,17 +52,20 @@ namespace Orthanc
std::vector<std::string> instances_;
size_t position_;
RemoteModalityParameters remote_;
- uint16_t moveRequestID_;
+ std::string originatorAet_;
+ uint16_t originatorId_;
public:
OrthancMoveRequestIterator(ServerContext& context,
const std::string& aet,
const std::string& publicId,
- uint16_t moveRequestID) :
+ const std::string& originatorAet,
+ uint16_t originatorId) :
context_(context),
localAet_(context.GetDefaultLocalApplicationEntityTitle()),
position_(0),
- moveRequestID_(moveRequestID)
+ originatorAet_(originatorAet),
+ originatorId_(originatorId)
{
LOG(INFO) << "Sending resource " << publicId << " to modality \"" << aet << "\"";
@@ -93,12 +96,12 @@ namespace Orthanc
const std::string& id = instances_[position_++];
std::string dicom;
- context_.ReadFile(dicom, id, FileContentType_Dicom);
+ context_.ReadDicom(dicom, id);
{
ReusableDicomUserConnection::Locker locker
(context_.GetReusableDicomUserConnection(), localAet_, remote_);
- locker.GetConnection().Store(dicom, moveRequestID_);
+ locker.GetConnection().Store(dicom, originatorAet_, originatorId_);
}
return Status_Success;
@@ -167,10 +170,10 @@ namespace Orthanc
IMoveRequestIterator* OrthancMoveRequestHandler::Handle(const std::string& targetAet,
const DicomMap& input,
- const std::string& remoteIp,
- const std::string& remoteAet,
+ const std::string& originatorIp,
+ const std::string& originatorAet,
const std::string& calledAet,
- uint16_t messageId)
+ uint16_t originatorId)
{
LOG(WARNING) << "Move-SCU request received for AET \"" << targetAet << "\"";
@@ -181,43 +184,13 @@ namespace Orthanc
if (!query.GetElement(i).GetValue().IsNull())
{
LOG(INFO) << " " << query.GetElement(i).GetTag()
- << " " << FromDcmtkBridge::GetName(query.GetElement(i).GetTag())
+ << " " << FromDcmtkBridge::GetTagName(query.GetElement(i))
<< " = " << query.GetElement(i).GetValue().GetContent();
}
}
}
-#if 0
- /**
- * Retrieve the Message ID (0000,0110) for this C-MOVE request, if
- * any. If present, this Message ID will be stored in the Move
- * Originator Message ID (0000,1031) field of the C-MOVE response.
- * http://dicom.nema.org/medical/dicom/current/output/html/part07.html#sect_9.3.1
- **/
-
- static const DicomTag MESSAGE_ID(0x0000, 0x0110);
- const DicomValue* messageIdTmp = input.TestAndGetValue(MESSAGE_ID);
-
- messageId = 0;
-
- if (messageIdTmp != NULL &&
- !messageIdTmp->IsNull() &&
- !messageIdTmp->IsBinary())
- {
- try
- {
- messageId = boost::lexical_cast<uint16_t>(messageIdTmp->GetContent());
- }
- catch (boost::bad_lexical_cast&)
- {
- LOG(WARNING) << "Cannot convert the Message ID (\"" << messageIdTmp ->GetContent()
- << "\") of an incoming C-MOVE request to an integer, assuming zero";
- }
- }
-#endif
-
-
/**
* Retrieve the query level.
**/
@@ -241,7 +214,7 @@ namespace Orthanc
LookupIdentifier(publicId, ResourceType_Study, input) ||
LookupIdentifier(publicId, ResourceType_Patient, input))
{
- return new OrthancMoveRequestIterator(context_, targetAet, publicId, messageId);
+ return new OrthancMoveRequestIterator(context_, targetAet, publicId, originatorAet, originatorId);
}
else
{
@@ -262,7 +235,7 @@ namespace Orthanc
if (LookupIdentifier(publicId, level, input))
{
- return new OrthancMoveRequestIterator(context_, targetAet, publicId, messageId);
+ return new OrthancMoveRequestIterator(context_, targetAet, publicId, originatorAet, originatorId);
}
else
{
diff --git a/OrthancServer/OrthancMoveRequestHandler.h b/OrthancServer/OrthancMoveRequestHandler.h
index 18dc817..6d54eab 100644
--- a/OrthancServer/OrthancMoveRequestHandler.h
+++ b/OrthancServer/OrthancMoveRequestHandler.h
@@ -53,9 +53,9 @@ namespace Orthanc
virtual IMoveRequestIterator* Handle(const std::string& targetAet,
const DicomMap& input,
- const std::string& remoteIp,
- const std::string& remoteAet,
+ const std::string& originatorIp,
+ const std::string& originatorAet,
const std::string& calledAet,
- uint16_t messageId);
+ uint16_t originatorId);
};
}
diff --git a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
index 7168fbd..cb7f622 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestAnonymizeModify.cpp
@@ -34,7 +34,6 @@
#include "OrthancRestApi.h"
#include "../../Core/Logging.h"
-#include "../../Core/Uuid.h"
#include "../FromDcmtkBridge.h"
#include "../ServerContext.h"
#include "../OrthancInitialization.h"
@@ -137,6 +136,16 @@ namespace Orthanc
ParseReplacements(target, request["Replace"]);
}
+ // The "Keep" operation only makes sense for the tags
+ // StudyInstanceUID, SeriesInstanceUID and SOPInstanceUID. Avoid
+ // this feature as much as possible, as this breaks the DICOM
+ // model of the real world, except if you know exactly what
+ // you're doing!
+ if (request.isMember("Keep"))
+ {
+ ParseListOfTags(target, request["Keep"], TagOperation_Keep);
+ }
+
return true;
}
else
@@ -674,7 +683,7 @@ namespace Orthanc
throw OrthancException(ErrorCode_InternalError);
}
- context.ReadJson(siblingTags, siblingInstances.front());
+ context.ReadDicomAsJson(siblingTags, siblingInstances.front());
}
@@ -758,7 +767,7 @@ namespace Orthanc
// Inject time-related information
std::string date, time;
- Toolbox::GetNowDicom(date, time);
+ SystemToolbox::GetNowDicom(date, time);
dicom.ReplacePlainString(DICOM_TAG_ACQUISITION_DATE, date);
dicom.ReplacePlainString(DICOM_TAG_ACQUISITION_TIME, time);
dicom.ReplacePlainString(DICOM_TAG_CONTENT_DATE, date);
diff --git a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
index 66c2872..34ac44f 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestArchive.cpp
@@ -38,7 +38,7 @@
#include "../../Core/Compression/HierarchicalZipWriter.h"
#include "../../Core/HttpServer/FilesystemHttpSender.h"
#include "../../Core/Logging.h"
-#include "../../Core/Uuid.h"
+#include "../../Core/TemporaryFile.h"
#include "../ServerContext.h"
#include <stdio.h>
@@ -524,7 +524,7 @@ namespace Orthanc
const FileInfo& dicom)
{
std::string content;
- context_.ReadFile(content, dicom);
+ context_.ReadAttachment(content, dicom);
char filename[24];
snprintf(filename, sizeof(filename) - 1, instanceFormat_, countInstances_);
@@ -547,7 +547,7 @@ namespace Orthanc
const bool isZip64 = IsZip64Required(stats.GetUncompressedSize(), stats.GetInstancesCount());
// Create a RAII for the temporary file to manage the ZIP file
- Toolbox::TemporaryFile tmp;
+ TemporaryFile tmp;
{
// Create a ZIP writer
@@ -612,7 +612,7 @@ namespace Orthanc
writer_.OpenFile(filename.c_str());
std::string content;
- context_.ReadFile(content, dicom);
+ context_.ReadAttachment(content, dicom);
writer_.Write(content);
ParsedDicomFile parsed(content);
@@ -634,7 +634,7 @@ namespace Orthanc
const bool isZip64 = IsZip64Required(stats.GetUncompressedSize(), stats.GetInstancesCount());
// Create a RAII for the temporary file to manage the ZIP file
- Toolbox::TemporaryFile tmp;
+ TemporaryFile tmp;
{
// Create a ZIP writer
diff --git a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
index 3341a91..3f0ece0 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestModalities.cpp
@@ -178,7 +178,7 @@ namespace Orthanc
RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
- DicomFindAnswers answers;
+ DicomFindAnswers answers(false);
FindPatient(answers, locker.GetConnection(), fields);
Json::Value result;
@@ -208,7 +208,7 @@ namespace Orthanc
RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
- DicomFindAnswers answers;
+ DicomFindAnswers answers(false);
FindStudy(answers, locker.GetConnection(), fields);
Json::Value result;
@@ -239,7 +239,7 @@ namespace Orthanc
RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
- DicomFindAnswers answers;
+ DicomFindAnswers answers(false);
FindSeries(answers, locker.GetConnection(), fields);
Json::Value result;
@@ -271,7 +271,7 @@ namespace Orthanc
RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
- DicomFindAnswers answers;
+ DicomFindAnswers answers(false);
FindInstance(answers, locker.GetConnection(), fields);
Json::Value result;
@@ -308,7 +308,7 @@ namespace Orthanc
RemoteModalityParameters remote = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
- DicomFindAnswers patients;
+ DicomFindAnswers patients(false);
FindPatient(patients, locker.GetConnection(), m);
// Loop over the found patients
@@ -326,7 +326,7 @@ namespace Orthanc
CopyTagIfExists(m, patients.GetAnswer(i), DICOM_TAG_PATIENT_ID);
- DicomFindAnswers studies;
+ DicomFindAnswers studies(false);
FindStudy(studies, locker.GetConnection(), m);
patient["Studies"] = Json::arrayValue;
@@ -346,7 +346,7 @@ namespace Orthanc
CopyTagIfExists(m, studies.GetAnswer(j), DICOM_TAG_PATIENT_ID);
CopyTagIfExists(m, studies.GetAnswer(j), DICOM_TAG_STUDY_INSTANCE_UID);
- DicomFindAnswers series;
+ DicomFindAnswers series(false);
FindSeries(series, locker.GetConnection(), m);
// Loop over the found series
@@ -683,58 +683,45 @@ namespace Orthanc
return;
}
- static const char* LOCAL_AET = "LocalAet";
- std::string localAet = context.GetDefaultLocalApplicationEntityTitle();
- if (request.type() == Json::objectValue &&
- request.isMember(LOCAL_AET))
- {
- if (request[LOCAL_AET].type() == Json::stringValue)
- {
- localAet = request[LOCAL_AET].asString();
- }
- else
- {
- throw OrthancException(ErrorCode_BadFileFormat);
- }
- }
-
- uint16_t moveOriginatorID = 0; /* By default, not a C-MOVE */
+ std::string localAet = Toolbox::GetJsonStringField(request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle());
+ bool permissive = Toolbox::GetJsonBooleanField(request, "Permissive", false);
+ bool asynchronous = Toolbox::GetJsonBooleanField(request, "Asynchronous", false);
+ std::string moveOriginatorAET = Toolbox::GetJsonStringField(request, "MoveOriginatorAet", context.GetDefaultLocalApplicationEntityTitle());
+ int moveOriginatorID = Toolbox::GetJsonIntegerField(request, "MoveOriginatorID", 0 /* By default, not a C-MOVE */);
- static const char* MOVE_ORIGINATOR_ID = "MoveOriginatorID";
- if (request.type() == Json::objectValue &&
- request.isMember(MOVE_ORIGINATOR_ID))
+ if (moveOriginatorID < 0 ||
+ moveOriginatorID >= 65536)
{
- if (request[MOVE_ORIGINATOR_ID].type() != Json::intValue)
- {
- throw OrthancException(ErrorCode_BadFileFormat);
- }
-
- int v = request[MOVE_ORIGINATOR_ID].asInt();
- if (v <= 0 || v >= 65536)
- {
- throw OrthancException(ErrorCode_ParameterOutOfRange);
- }
- else
- {
- moveOriginatorID = boost::lexical_cast<uint16_t>(v);
- }
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
}
-
+
RemoteModalityParameters p = Configuration::GetModalityUsingSymbolicName(remote);
ServerJob job;
for (std::list<std::string>::const_iterator
it = instances.begin(); it != instances.end(); ++it)
{
- job.AddCommand(new StoreScuCommand(context, localAet, p, false,
- moveOriginatorID)).AddInput(*it);
+ std::auto_ptr<StoreScuCommand> command(new StoreScuCommand(context, localAet, p, permissive));
+
+ if (moveOriginatorID != 0)
+ {
+ command->SetMoveOriginator(moveOriginatorAET, static_cast<uint16_t>(moveOriginatorID));
+ }
+
+ job.AddCommand(command.release()).AddInput(*it);
}
job.SetDescription("HTTP request: Store-SCU to peer \"" + remote + "\"");
- if (context.GetScheduler().SubmitAndWait(job))
+ if (asynchronous)
{
- // Success
+ // Asynchronous mode: Submit the job, but don't wait for its completion
+ context.GetScheduler().Submit(job);
+ call.GetOutput().AnswerBuffer("{}", "application/json");
+ }
+ else if (context.GetScheduler().SubmitAndWait(job))
+ {
+ // Synchronous mode: We have submitted and waited for completion
call.GetOutput().AnswerBuffer("{}", "application/json");
}
else
@@ -769,33 +756,8 @@ namespace Orthanc
ResourceType level = StringToResourceType(request["Level"].asCString());
- static const char* LOCAL_AET = "LocalAet";
- std::string localAet = context.GetDefaultLocalApplicationEntityTitle();
- if (request.isMember(LOCAL_AET))
- {
- if (request[LOCAL_AET].type() == Json::stringValue)
- {
- localAet = request[LOCAL_AET].asString();
- }
- else
- {
- throw OrthancException(ErrorCode_BadFileFormat);
- }
- }
-
- static const char* TARGET_AET = "TargetAet";
- std::string targetAet = context.GetDefaultLocalApplicationEntityTitle();
- if (request.isMember(TARGET_AET))
- {
- if (request[TARGET_AET].type() == Json::stringValue)
- {
- targetAet = request[TARGET_AET].asString();
- }
- else
- {
- throw OrthancException(ErrorCode_BadFileFormat);
- }
- }
+ std::string localAet = Toolbox::GetJsonStringField(request, "LocalAet", context.GetDefaultLocalApplicationEntityTitle());
+ std::string targetAet = Toolbox::GetJsonStringField(request, "TargetAet", context.GetDefaultLocalApplicationEntityTitle());
const RemoteModalityParameters source = Configuration::GetModalityUsingSymbolicName(call.GetUriComponent("id", ""));
@@ -864,6 +826,8 @@ namespace Orthanc
return;
}
+ bool asynchronous = Toolbox::GetJsonBooleanField(request, "Asynchronous", false);
+
WebServiceParameters peer;
Configuration::GetOrthancPeer(peer, remote);
@@ -876,9 +840,15 @@ namespace Orthanc
job.SetDescription("HTTP request: POST to peer \"" + remote + "\"");
- if (context.GetScheduler().SubmitAndWait(job))
+ if (asynchronous)
+ {
+ // Asynchronous mode: Submit the job, but don't wait for its completion
+ context.GetScheduler().Submit(job);
+ call.GetOutput().AnswerBuffer("{}", "application/json");
+ }
+ else if (context.GetScheduler().SubmitAndWait(job))
{
- // Success
+ // Synchronous mode: We have submitted and waited for completion
call.GetOutput().AnswerBuffer("{}", "application/json");
}
else
@@ -979,7 +949,7 @@ namespace Orthanc
std::auto_ptr<ParsedDicomFile> query(ParsedDicomFile::CreateFromJson(json, static_cast<DicomFromJsonFlags>(0)));
- DicomFindAnswers answers;
+ DicomFindAnswers answers(true);
{
ReusableDicomUserConnection::Locker locker(context.GetReusableDicomUserConnection(), localAet, remote);
diff --git a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp
index dad9728..33c217f 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestResources.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestResources.cpp
@@ -33,13 +33,15 @@
#include "../PrecompiledHeadersServer.h"
#include "OrthancRestApi.h"
-#include "../../Core/Logging.h"
#include "../../Core/HttpServer/HttpContentNegociation.h"
-#include "../ServerToolbox.h"
+#include "../../Core/Logging.h"
#include "../FromDcmtkBridge.h"
+#include "../Internals/DicomImageDecoder.h"
+#include "../OrthancInitialization.h"
+#include "../Search/LookupResource.h"
#include "../ServerContext.h"
+#include "../ServerToolbox.h"
#include "../SliceOrdering.h"
-#include "../Internals/DicomImageDecoder.h"
namespace Orthanc
@@ -186,11 +188,11 @@ namespace Orthanc
std::string publicId = call.GetUriComponent("id", "");
std::string dicom;
- context.ReadFile(dicom, publicId, FileContentType_Dicom);
+ context.ReadDicom(dicom, publicId);
std::string target;
call.BodyToString(target);
- Toolbox::WriteFile(dicom, target);
+ SystemToolbox::WriteFile(dicom, target);
call.GetOutput().AnswerBuffer("{}", "application/json");
}
@@ -206,15 +208,17 @@ namespace Orthanc
if (simplify)
{
Json::Value full;
- context.ReadJson(full, publicId);
+ context.ReadDicomAsJson(full, publicId);
Json::Value simplified;
- Toolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
+ ServerToolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
call.GetOutput().AnswerJson(simplified);
}
else
{
- context.AnswerAttachment(call.GetOutput(), publicId, FileContentType_DicomAsJson);
+ std::string full;
+ context.ReadDicomAsJson(full, publicId);
+ call.GetOutput().AnswerBuffer(full, "application/json");
}
}
@@ -374,12 +378,12 @@ namespace Orthanc
{
std::string publicId = call.GetUriComponent("id", "");
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
if (context.GetPlugins().HasCustomImageDecoder())
{
// TODO create a cache of file
std::string dicomContent;
- context.ReadFile(dicomContent, publicId, FileContentType_Dicom);
+ context.ReadDicom(dicomContent, publicId);
decoded.reset(context.GetPlugins().DecodeUnsafe(dicomContent.c_str(), dicomContent.size(), frame));
/**
@@ -449,9 +453,9 @@ namespace Orthanc
std::string publicId = call.GetUriComponent("id", "");
std::string dicomContent;
- context.ReadFile(dicomContent, publicId, FileContentType_Dicom);
+ context.ReadDicom(dicomContent, publicId);
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
IDicomImageDecoder& decoder = context.GetPlugins();
#else
DefaultDicomImageDecoder decoder; // This is Orthanc's built-in decoder
@@ -562,6 +566,10 @@ namespace Orthanc
OrthancRestApi::GetIndex(call).DeleteMetadata(publicId, metadata);
call.GetOutput().AnswerBuffer("", "text/plain");
}
+ else
+ {
+ call.GetOutput().SignalError(HttpStatus_403_Forbidden);
+ }
}
@@ -582,6 +590,10 @@ namespace Orthanc
OrthancRestApi::GetIndex(call).SetMetadata(publicId, metadata, value);
call.GetOutput().AnswerBuffer("", "text/plain");
}
+ else
+ {
+ call.GetOutput().SignalError(HttpStatus_403_Forbidden);
+ }
}
@@ -676,7 +688,7 @@ namespace Orthanc
{
// Return the raw data (possibly compressed), as stored on the filesystem
std::string content;
- context.ReadFile(content, publicId, type, false);
+ context.ReadAttachment(content, publicId, type, false);
call.GetOutput().AnswerBuffer(content, "application/octet-stream");
}
}
@@ -745,7 +757,7 @@ namespace Orthanc
// First check whether the compressed data is correctly stored in the disk
std::string data;
- context.ReadFile(data, publicId, StringToContentType(name), false);
+ context.ReadAttachment(data, publicId, StringToContentType(name), false);
std::string actualMD5;
Toolbox::ComputeMD5(actualMD5, data);
@@ -760,7 +772,7 @@ namespace Orthanc
}
else
{
- context.ReadFile(data, publicId, StringToContentType(name), true);
+ context.ReadAttachment(data, publicId, StringToContentType(name), true);
Toolbox::ComputeMD5(actualMD5, data);
ok = (actualMD5 == info.GetUncompressedMD5());
}
@@ -792,6 +804,10 @@ namespace Orthanc
{
call.GetOutput().AnswerBuffer("{}", "application/json");
}
+ else
+ {
+ call.GetOutput().SignalError(HttpStatus_403_Forbidden);
+ }
}
@@ -803,11 +819,33 @@ namespace Orthanc
std::string name = call.GetUriComponent("name", "");
FileContentType contentType = StringToContentType(name);
- if (IsUserContentType(contentType)) // It is forbidden to delete internal attachments
+ bool allowed;
+ if (IsUserContentType(contentType))
+ {
+ allowed = true;
+ }
+ else if (Configuration::GetGlobalBoolParameter("StoreDicom", true) &&
+ contentType == FileContentType_DicomAsJson)
+ {
+ allowed = true;
+ }
+ else
+ {
+ // It is forbidden to delete internal attachments, except for
+ // the "DICOM as JSON" summary as of Orthanc 1.2.0 (this summary
+ // would be automatically reconstructed on the next GET call)
+ allowed = false;
+ }
+
+ if (allowed)
{
OrthancRestApi::GetIndex(call).DeleteAttachment(publicId, contentType);
call.GetOutput().AnswerBuffer("{}", "application/json");
}
+ else
+ {
+ call.GetOutput().SignalError(HttpStatus_403_Forbidden);
+ }
}
@@ -870,7 +908,7 @@ namespace Orthanc
try
{
- context.ReadJson(tags, *it);
+ context.ReadDicomAsJson(tags, *it);
}
catch (OrthancException&)
{
@@ -937,7 +975,7 @@ namespace Orthanc
if (simplify)
{
Json::Value simplified;
- Toolbox::SimplifyTags(simplified, sharedTags, DicomToJsonFormat_Human);
+ ServerToolbox::SimplifyTags(simplified, sharedTags, DicomToJsonFormat_Human);
call.GetOutput().AnswerJson(simplified);
}
else
@@ -988,7 +1026,7 @@ namespace Orthanc
publicId = instances.front();
}
- context.ReadJson(tags, publicId);
+ context.ReadDicomAsJson(tags, publicId);
// Filter the tags of the instance according to the module
Json::Value result = Json::objectValue;
@@ -1004,7 +1042,7 @@ namespace Orthanc
if (simplify)
{
Json::Value simplified;
- Toolbox::SimplifyTags(simplified, result, DicomToJsonFormat_Human);
+ ServerToolbox::SimplifyTags(simplified, result, DicomToJsonFormat_Human);
call.GetOutput().AnswerJson(simplified);
}
else
@@ -1205,12 +1243,12 @@ namespace Orthanc
it != instances.end(); ++it)
{
Json::Value full;
- context.ReadJson(full, *it);
+ context.ReadDicomAsJson(full, *it);
if (simplify)
{
Json::Value simplified;
- Toolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
+ ServerToolbox::SimplifyTags(simplified, full, DicomToJsonFormat_Human);
result[*it] = simplified;
}
else
@@ -1294,7 +1332,7 @@ namespace Orthanc
bool simplify = call.HasArgument("simplify");
std::string dicomContent;
- context.ReadFile(dicomContent, publicId, FileContentType_Dicom);
+ context.ReadDicom(dicomContent, publicId);
// TODO Consider using "DicomMap::ParseDicomMetaInformation()" to
// speed up things here
@@ -1307,7 +1345,7 @@ namespace Orthanc
if (simplify)
{
Json::Value simplified;
- Toolbox::SimplifyTags(simplified, header, DicomToJsonFormat_Human);
+ ServerToolbox::SimplifyTags(simplified, header, DicomToJsonFormat_Human);
call.GetOutput().AnswerJson(simplified);
}
else
@@ -1317,6 +1355,41 @@ namespace Orthanc
}
+ static void InvalidateTags(RestApiPostCall& call)
+ {
+ ServerIndex& index = OrthancRestApi::GetIndex(call);
+
+ // Loop over the instances, grouping them by parent studies so as
+ // to avoid large memory consumption
+ std::list<std::string> studies;
+ index.GetAllUuids(studies, ResourceType_Study);
+
+ for (std::list<std::string>::const_iterator
+ study = studies.begin(); study != studies.end(); ++study)
+ {
+ std::list<std::string> instances;
+ index.GetChildInstances(instances, *study);
+
+ for (std::list<std::string>::const_iterator
+ instance = instances.begin(); instance != instances.end(); ++instance)
+ {
+ index.DeleteAttachment(*instance, FileContentType_DicomAsJson);
+ }
+ }
+
+ call.GetOutput().AnswerBuffer("", "text/plain");
+ }
+
+
+ template <enum ResourceType type>
+ static void ReconstructResource(RestApiPostCall& call)
+ {
+ ServerContext& context = OrthancRestApi::GetContext(call);
+ ServerToolbox::ReconstructResource(context, call.GetUriComponent("id", ""));
+ call.GetOutput().AnswerBuffer("", "text/plain");
+ }
+
+
void OrthancRestApi::RegisterResources()
{
Register("/instances", ListResources<ResourceType_Instance>);
@@ -1391,6 +1464,7 @@ namespace Orthanc
Register("/{resourceType}/{id}/attachments/{name}/uncompress", ChangeAttachmentCompression<CompressionType_None>);
Register("/{resourceType}/{id}/attachments/{name}/verify-md5", VerifyAttachment);
+ Register("/tools/invalidate-tags", InvalidateTags);
Register("/tools/lookup", Lookup);
Register("/tools/find", Find);
@@ -1415,5 +1489,10 @@ namespace Orthanc
Register("/instances/{id}/content/*", GetRawContent);
Register("/series/{id}/ordered-slices", OrderSlices);
+
+ Register("/patients/{id}/reconstruct", ReconstructResource<ResourceType_Patient>);
+ Register("/studies/{id}/reconstruct", ReconstructResource<ResourceType_Study>);
+ Register("/series/{id}/reconstruct", ReconstructResource<ResourceType_Series>);
+ Register("/instances/{id}/reconstruct", ReconstructResource<ResourceType_Instance>);
}
}
diff --git a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
index 7678674..f86cd73 100644
--- a/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
+++ b/OrthancServer/OrthancRestApi/OrthancRestSystem.cpp
@@ -55,15 +55,15 @@ namespace Orthanc
result["DatabaseVersion"] = OrthancRestApi::GetIndex(call).GetDatabaseVersion();
result["DicomAet"] = Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC");
- result["DicomPort"] = Configuration::GetGlobalIntegerParameter("DicomPort", 4242);
- result["HttpPort"] = Configuration::GetGlobalIntegerParameter("HttpPort", 8042);
+ result["DicomPort"] = Configuration::GetGlobalUnsignedIntegerParameter("DicomPort", 4242);
+ result["HttpPort"] = Configuration::GetGlobalUnsignedIntegerParameter("HttpPort", 8042);
result["Name"] = Configuration::GetGlobalStringParameter("Name", "");
result["Version"] = ORTHANC_VERSION;
result["StorageAreaPlugin"] = Json::nullValue;
result["DatabaseBackendPlugin"] = Json::nullValue;
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
result["PluginsEnabled"] = true;
const OrthancPlugins& plugins = OrthancRestApi::GetContext(call).GetPlugins();
@@ -131,7 +131,7 @@ namespace Orthanc
static void GetNowIsoString(RestApiGetCall& call)
{
- call.GetOutput().AnswerBuffer(Toolbox::GetNowIsoString(), "text/plain");
+ call.GetOutput().AnswerBuffer(SystemToolbox::GetNowIsoString(), "text/plain");
}
@@ -153,7 +153,7 @@ namespace Orthanc
if (OrthancRestApi::GetContext(call).HasPlugins())
{
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
std::list<std::string> plugins;
OrthancRestApi::GetContext(call).GetPlugins().GetManager().ListPlugins(plugins);
@@ -176,7 +176,7 @@ namespace Orthanc
return;
}
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
const PluginsManager& manager = OrthancRestApi::GetContext(call).GetPlugins().GetManager();
std::string id = call.GetUriComponent("id", "");
@@ -224,7 +224,7 @@ namespace Orthanc
if (OrthancRestApi::GetContext(call).HasPlugins())
{
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
const OrthancPlugins& plugins = OrthancRestApi::GetContext(call).GetPlugins();
const PluginsManager& manager = plugins.GetManager();
@@ -248,6 +248,23 @@ namespace Orthanc
}
+ static void GetDefaultEncoding(RestApiGetCall& call)
+ {
+ Encoding encoding = Configuration::GetDefaultEncoding();
+ call.GetOutput().AnswerBuffer(EnumerationToString(encoding), "text/plain");
+ }
+
+
+ static void SetDefaultEncoding(RestApiPutCall& call)
+ {
+ Encoding encoding = StringToEncoding(call.GetBodyData());
+
+ Configuration::SetDefaultEncoding(encoding);
+
+ call.GetOutput().AnswerBuffer(EnumerationToString(encoding), "text/plain");
+ }
+
+
void OrthancRestApi::RegisterSystem()
{
Register("/", ServeRoot);
@@ -257,6 +274,8 @@ namespace Orthanc
Register("/tools/execute-script", ExecuteScript);
Register("/tools/now", GetNowIsoString);
Register("/tools/dicom-conformance", GetDicomConformanceStatement);
+ Register("/tools/default-encoding", GetDefaultEncoding);
+ Register("/tools/default-encoding", SetDefaultEncoding);
Register("/plugins", ListPlugins);
Register("/plugins/{id}", GetPlugin);
diff --git a/OrthancServer/ParsedDicomFile.cpp b/OrthancServer/ParsedDicomFile.cpp
index 27b84f5..bc5ecf0 100644
--- a/OrthancServer/ParsedDicomFile.cpp
+++ b/OrthancServer/ParsedDicomFile.cpp
@@ -90,7 +90,6 @@ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#include "../Core/Logging.h"
#include "../Core/OrthancException.h"
#include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
#include <list>
#include <limits>
@@ -855,7 +854,7 @@ namespace Orthanc
// TODO Avoid using a temporary memory buffer, write directly on disk
std::string content;
SaveToMemoryBuffer(content);
- Toolbox::WriteFile(content, path);
+ SystemToolbox::WriteFile(content, path);
}
@@ -873,15 +872,55 @@ namespace Orthanc
}
- ParsedDicomFile::ParsedDicomFile(const DicomMap& map) : pimpl_(new PImpl)
+ void ParsedDicomFile::CreateFromDicomMap(const DicomMap& source,
+ Encoding defaultEncoding)
{
- std::auto_ptr<DcmDataset> dataset(ToDcmtkBridge::Convert(map));
+ pimpl_->file_.reset(new DcmFileFormat);
+
+ const DicomValue* tmp = source.TestAndGetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET);
+ if (tmp != NULL)
+ {
+ Encoding encoding;
+ if (tmp->IsNull() ||
+ tmp->IsBinary() ||
+ !GetDicomEncoding(encoding, tmp->GetContent().c_str()))
+ {
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+ else
+ {
+ SetEncoding(encoding);
+ }
+ }
+ else
+ {
+ SetEncoding(defaultEncoding);
+ }
+
+ for (DicomMap::Map::const_iterator
+ it = source.map_.begin(); it != source.map_.end(); ++it)
+ {
+ if (it->first != DICOM_TAG_SPECIFIC_CHARACTER_SET &&
+ !it->second->IsNull())
+ {
+ ReplacePlainString(it->first, it->second->GetContent());
+ }
+ }
+ }
- // NOTE: This implies an unnecessary memory copy of the dataset, but no way to get around
- // http://support.dcmtk.org/redmine/issues/544
- std::auto_ptr<DcmFileFormat> fileFormat(new DcmFileFormat(dataset.get()));
- pimpl_->file_.reset(fileFormat.release());
+ ParsedDicomFile::ParsedDicomFile(const DicomMap& map,
+ Encoding defaultEncoding) :
+ pimpl_(new PImpl)
+ {
+ CreateFromDicomMap(map, defaultEncoding);
+ }
+
+
+ ParsedDicomFile::ParsedDicomFile(const DicomMap& map) :
+ pimpl_(new PImpl)
+ {
+ CreateFromDicomMap(map, Configuration::GetDefaultEncoding());
}
@@ -1146,21 +1185,26 @@ namespace Orthanc
ReplacePlainString(DICOM_TAG_SPECIFIC_CHARACTER_SET, s);
}
- void ParsedDicomFile::ToJson(Json::Value& target,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength)
+ void ParsedDicomFile::DatasetToJson(Json::Value& target,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength)
+ {
+ FromDcmtkBridge::ExtractDicomAsJson(target, *pimpl_->file_->getDataset(),
+ format, flags, maxStringLength, Configuration::GetDefaultEncoding());
+ }
+
+
+ void ParsedDicomFile::DatasetToJson(Json::Value& target)
{
- FromDcmtkBridge::ToJson(target, *pimpl_->file_->getDataset(),
- format, flags, maxStringLength,
- Configuration::GetDefaultEncoding());
+ Configuration::ExtractDicomAsJson(target, *pimpl_->file_->getDataset());
}
void ParsedDicomFile::HeaderToJson(Json::Value& target,
DicomToJsonFormat format)
{
- FromDcmtkBridge::ToJson(target, *pimpl_->file_->getMetaInfo(), format, DicomToJsonFlags_None, 0);
+ FromDcmtkBridge::ExtractHeaderAsJson(target, *pimpl_->file_->getMetaInfo(), format, DicomToJsonFlags_None, 0);
}
@@ -1256,14 +1300,6 @@ namespace Orthanc
}
- void ParsedDicomFile::Convert(DicomMap& tags)
- {
- FromDcmtkBridge::Convert(tags, *pimpl_->file_->getDataset(),
- ORTHANC_MAXIMUM_TAG_LENGTH,
- Configuration::GetDefaultEncoding());
- }
-
-
ParsedDicomFile* ParsedDicomFile::CreateFromJson(const Json::Value& json,
DicomFromJsonFlags flags)
{
@@ -1342,4 +1378,34 @@ namespace Orthanc
{
return DicomFrameIndex::GetFramesCount(*pimpl_->file_);
}
+
+
+ void ParsedDicomFile::ChangeEncoding(Encoding target)
+ {
+ Encoding source = GetEncoding();
+
+ if (source != target) // Avoid unnecessary conversion
+ {
+ ReplacePlainString(DICOM_TAG_SPECIFIC_CHARACTER_SET, GetDicomSpecificCharacterSet(target));
+ FromDcmtkBridge::ChangeStringEncoding(*pimpl_->file_->getDataset(), source, target);
+ }
+ }
+
+
+ void ParsedDicomFile::ExtractDicomSummary(DicomMap& target) const
+ {
+ Configuration::ExtractDicomSummary(target, *pimpl_->file_->getDataset());
+ }
+
+
+ void ParsedDicomFile::ExtractDicomAsJson(Json::Value& target) const
+ {
+ Configuration::ExtractDicomAsJson(target, *pimpl_->file_->getDataset());
+ }
+
+
+ bool ParsedDicomFile::LookupTransferSyntax(std::string& result)
+ {
+ return FromDcmtkBridge::LookupTransferSyntax(result, *pimpl_->file_);
+ }
}
diff --git a/OrthancServer/ParsedDicomFile.h b/OrthancServer/ParsedDicomFile.h
index 011ff75..b5f7930 100644
--- a/OrthancServer/ParsedDicomFile.h
+++ b/OrthancServer/ParsedDicomFile.h
@@ -36,6 +36,7 @@
#include "../Core/Images/ImageAccessor.h"
#include "../Core/IDynamicObject.h"
#include "../Core/RestApi/RestApiOutput.h"
+#include "../Core/Toolbox.h"
#include "ServerEnumerations.h"
class DcmDataset;
@@ -51,6 +52,9 @@ namespace Orthanc
ParsedDicomFile(ParsedDicomFile& other);
+ void CreateFromDicomMap(const DicomMap& source,
+ Encoding defaultEncoding);
+
void RemovePrivateTagsInternal(const std::set<DicomTag>* toKeep);
void UpdateStorageUid(const DicomTag& tag,
@@ -64,6 +68,9 @@ namespace Orthanc
public:
ParsedDicomFile(bool createIdentifiers); // Create a minimal DICOM instance
+ ParsedDicomFile(const DicomMap& map,
+ Encoding defaultEncoding);
+
ParsedDicomFile(const DicomMap& map);
ParsedDicomFile(const void* content,
@@ -118,6 +125,7 @@ namespace Orthanc
RemovePrivateTagsInternal(&toKeep);
}
+ // WARNING: This function handles the decoding of strings to UTF8
bool GetTagValue(std::string& value,
const DicomTag& tag);
@@ -136,12 +144,18 @@ namespace Orthanc
Encoding GetEncoding() const;
+ // WARNING: This function only sets the encoding, it will not
+ // convert the encoding of the tags. Use "ChangeEncoding()" if need be.
void SetEncoding(Encoding encoding);
- void ToJson(Json::Value& target,
- DicomToJsonFormat format,
- DicomToJsonFlags flags,
- unsigned int maxStringLength);
+ void DatasetToJson(Json::Value& target,
+ DicomToJsonFormat format,
+ DicomToJsonFlags flags,
+ unsigned int maxStringLength);
+
+ // This version uses the default parameters for
+ // FileContentType_DicomAsJson
+ void DatasetToJson(Json::Value& target);
void HeaderToJson(Json::Value& target,
DicomToJsonFormat format);
@@ -152,8 +166,6 @@ namespace Orthanc
bool ExtractPdf(std::string& pdf);
- void Convert(DicomMap& tags);
-
void GetRawFrame(std::string& target, // OUT
std::string& mime, // OUT
unsigned int frameId); // IN
@@ -162,6 +174,13 @@ namespace Orthanc
static ParsedDicomFile* CreateFromJson(const Json::Value& value,
DicomFromJsonFlags flags);
- };
+ void ChangeEncoding(Encoding target);
+
+ void ExtractDicomSummary(DicomMap& target) const;
+
+ void ExtractDicomAsJson(Json::Value& target) const;
+
+ bool LookupTransferSyntax(std::string& result);
+ };
}
diff --git a/OrthancServer/QueryRetrieveHandler.cpp b/OrthancServer/QueryRetrieveHandler.cpp
index 3effdda..595d165 100644
--- a/OrthancServer/QueryRetrieveHandler.cpp
+++ b/OrthancServer/QueryRetrieveHandler.cpp
@@ -34,10 +34,43 @@
#include "QueryRetrieveHandler.h"
#include "OrthancInitialization.h"
+#include "FromDcmtkBridge.h"
namespace Orthanc
{
+ static void FixQuery(DicomMap& query,
+ ServerContext& context,
+ const std::string& modality)
+ {
+ static const char* LUA_CALLBACK = "OutgoingFindRequestFilter";
+
+ LuaScripting::Locker locker(context.GetLua());
+ if (locker.GetLua().IsExistingFunction(LUA_CALLBACK))
+ {
+ LuaFunctionCall call(locker.GetLua(), LUA_CALLBACK);
+ call.PushDicom(query);
+ call.PushJson(modality);
+ FromDcmtkBridge::ExecuteToDicom(query, call);
+ }
+ }
+
+
+ static void FixQuery(DicomMap& query,
+ ModalityManufacturer manufacturer)
+ {
+ /**
+ * Introduce patches for specific manufacturers below.
+ **/
+
+ switch (manufacturer)
+ {
+ default:
+ break;
+ }
+ }
+
+
void QueryRetrieveHandler::Invalidate()
{
done_ = false;
@@ -49,8 +82,20 @@ namespace Orthanc
{
if (!done_)
{
- ReusableDicomUserConnection::Locker locker(context_.GetReusableDicomUserConnection(), localAet_, modality_);
- locker.GetConnection().Find(answers_, level_, query_);
+ // Firstly, fix the content of the query for specific manufacturers
+ DicomMap fixed;
+ fixed.Assign(query_);
+ FixQuery(fixed, modality_.GetManufacturer());
+
+ // Secondly, possibly fix the query with the user-provider Lua callback
+ FixQuery(fixed, context_, modality_.GetApplicationEntityTitle());
+
+ {
+ // Finally, run the C-FIND SCU against the fixed query
+ ReusableDicomUserConnection::Locker locker(context_.GetReusableDicomUserConnection(), localAet_, modality_);
+ locker.GetConnection().Find(answers_, level_, fixed);
+ }
+
done_ = true;
}
}
@@ -60,7 +105,8 @@ namespace Orthanc
context_(context),
localAet_(context.GetDefaultLocalApplicationEntityTitle()),
done_(false),
- level_(ResourceType_Study)
+ level_(ResourceType_Study),
+ answers_(false)
{
}
@@ -99,7 +145,7 @@ namespace Orthanc
size_t i)
{
Run();
- answers_.GetAnswer(i).Convert(target);
+ answers_.GetAnswer(i).ExtractDicomSummary(target);
}
diff --git a/OrthancServer/Scheduler/CallSystemCommand.cpp b/OrthancServer/Scheduler/CallSystemCommand.cpp
index 135a788..751dc9b 100644
--- a/OrthancServer/Scheduler/CallSystemCommand.cpp
+++ b/OrthancServer/Scheduler/CallSystemCommand.cpp
@@ -35,7 +35,7 @@
#include "../../Core/Logging.h"
#include "../../Core/Toolbox.h"
-#include "../../Core/Uuid.h"
+#include "../../Core/TemporaryFile.h"
namespace Orthanc
{
@@ -59,15 +59,15 @@ namespace Orthanc
try
{
std::string dicom;
- context_.ReadFile(dicom, *it, FileContentType_Dicom);
+ context_.ReadDicom(dicom, *it);
- Toolbox::TemporaryFile tmp;
+ TemporaryFile tmp;
tmp.Write(dicom);
std::vector<std::string> args = arguments_;
args.push_back(tmp.GetPath());
- Toolbox::ExecuteSystemCommand(command_, args);
+ SystemToolbox::ExecuteSystemCommand(command_, args);
// Only chain with other commands if this command succeeds
outputs.push_back(*it);
diff --git a/OrthancServer/Scheduler/ServerJob.cpp b/OrthancServer/Scheduler/ServerJob.cpp
index c5ec396..a43ee1e 100644
--- a/OrthancServer/Scheduler/ServerJob.cpp
+++ b/OrthancServer/Scheduler/ServerJob.cpp
@@ -34,8 +34,8 @@
#include "ServerJob.h"
#include "../../Core/OrthancException.h"
+#include "../../Core/SystemToolbox.h"
#include "../../Core/Toolbox.h"
-#include "../../Core/Uuid.h"
namespace Orthanc
{
@@ -96,7 +96,7 @@ namespace Orthanc
ServerJob::ServerJob() :
- jobId_(Toolbox::GenerateUuid()),
+ jobId_(SystemToolbox::GenerateUuid()),
submitted_(false),
description_("no description")
{
diff --git a/OrthancServer/Scheduler/ServerScheduler.cpp b/OrthancServer/Scheduler/ServerScheduler.cpp
index 45831a3..dfe4b2c 100644
--- a/OrthancServer/Scheduler/ServerScheduler.cpp
+++ b/OrthancServer/Scheduler/ServerScheduler.cpp
@@ -47,7 +47,7 @@ namespace Orthanc
ListOfStrings& target_;
public:
- Sink(ListOfStrings& target) : target_(target)
+ explicit Sink(ListOfStrings& target) : target_(target)
{
}
@@ -192,6 +192,11 @@ namespace Orthanc
ServerScheduler::ServerScheduler(unsigned int maxJobs) : availableJob_(maxJobs)
{
+ if (maxJobs == 0)
+ {
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+
finish_ = false;
worker_ = boost::thread(Worker, this);
}
diff --git a/OrthancServer/Scheduler/ServerScheduler.h b/OrthancServer/Scheduler/ServerScheduler.h
index 341f829..0da65ff 100644
--- a/OrthancServer/Scheduler/ServerScheduler.h
+++ b/OrthancServer/Scheduler/ServerScheduler.h
@@ -82,7 +82,7 @@ namespace Orthanc
bool watched);
public:
- ServerScheduler(unsigned int maxjobs);
+ explicit ServerScheduler(unsigned int maxjobs);
~ServerScheduler();
diff --git a/OrthancServer/Scheduler/StorePeerCommand.cpp b/OrthancServer/Scheduler/StorePeerCommand.cpp
index ab9f677..8acbbb3 100644
--- a/OrthancServer/Scheduler/StorePeerCommand.cpp
+++ b/OrthancServer/Scheduler/StorePeerCommand.cpp
@@ -62,7 +62,7 @@ namespace Orthanc
try
{
- context_.ReadFile(client.GetBody(), *it, FileContentType_Dicom);
+ context_.ReadDicom(client.GetBody(), *it);
std::string answer;
if (!client.Apply(answer))
diff --git a/OrthancServer/Scheduler/StoreScuCommand.cpp b/OrthancServer/Scheduler/StoreScuCommand.cpp
index 7404064..c698b2d 100644
--- a/OrthancServer/Scheduler/StoreScuCommand.cpp
+++ b/OrthancServer/Scheduler/StoreScuCommand.cpp
@@ -40,16 +40,24 @@ namespace Orthanc
StoreScuCommand::StoreScuCommand(ServerContext& context,
const std::string& localAet,
const RemoteModalityParameters& modality,
- bool ignoreExceptions,
- uint16_t moveOriginatorID) :
+ bool ignoreExceptions) :
context_(context),
modality_(modality),
ignoreExceptions_(ignoreExceptions),
localAet_(localAet),
- moveOriginatorID_(moveOriginatorID)
+ moveOriginatorID_(0)
{
}
+
+ void StoreScuCommand::SetMoveOriginator(const std::string& aet,
+ uint16_t id)
+ {
+ moveOriginatorAET_ = aet;
+ moveOriginatorID_ = id;
+ }
+
+
bool StoreScuCommand::Apply(ListOfStrings& outputs,
const ListOfStrings& inputs)
{
@@ -64,9 +72,9 @@ namespace Orthanc
try
{
std::string dicom;
- context_.ReadFile(dicom, *it, FileContentType_Dicom);
+ context_.ReadDicom(dicom, *it);
- locker.GetConnection().Store(dicom, moveOriginatorID_);
+ locker.GetConnection().Store(dicom, moveOriginatorAET_, moveOriginatorID_);
// Only chain with other commands if this command succeeds
outputs.push_back(*it);
diff --git a/OrthancServer/Scheduler/StoreScuCommand.h b/OrthancServer/Scheduler/StoreScuCommand.h
index 1070c35..b1ead73 100644
--- a/OrthancServer/Scheduler/StoreScuCommand.h
+++ b/OrthancServer/Scheduler/StoreScuCommand.h
@@ -44,15 +44,17 @@ namespace Orthanc
RemoteModalityParameters modality_;
bool ignoreExceptions_;
std::string localAet_;
+ std::string moveOriginatorAET_;
uint16_t moveOriginatorID_;
public:
StoreScuCommand(ServerContext& context,
const std::string& localAet,
const RemoteModalityParameters& modality,
- bool ignoreExceptions,
- uint16_t moveOriginatorID /* only makes sense if this
- command results from a C-MOVE */);
+ bool ignoreExceptions);
+
+ void SetMoveOriginator(const std::string& aet,
+ uint16_t id);
virtual bool Apply(ListOfStrings& outputs,
const ListOfStrings& inputs);
diff --git a/OrthancServer/Search/HierarchicalMatcher.cpp b/OrthancServer/Search/HierarchicalMatcher.cpp
index daefa4c..9e71a03 100644
--- a/OrthancServer/Search/HierarchicalMatcher.cpp
+++ b/OrthancServer/Search/HierarchicalMatcher.cpp
@@ -86,9 +86,9 @@ namespace Orthanc
}
DicomTag tag(FromDcmtkBridge::Convert(element->getTag()));
- if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET)
+ if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET || // Ignore encoding
+ tag.GetElement() == 0x0000) // Ignore all "Group Length" tags
{
- // Ignore this specific tag
continue;
}
diff --git a/OrthancServer/Search/LookupIdentifierQuery.cpp b/OrthancServer/Search/LookupIdentifierQuery.cpp
index b56f95f..7b4c3f5 100644
--- a/OrthancServer/Search/LookupIdentifierQuery.cpp
+++ b/OrthancServer/Search/LookupIdentifierQuery.cpp
@@ -43,67 +43,6 @@
namespace Orthanc
{
- static const DicomTag patientIdentifiers[] =
- {
- DICOM_TAG_PATIENT_ID,
- DICOM_TAG_PATIENT_NAME,
- DICOM_TAG_PATIENT_BIRTH_DATE
- };
-
- static const DicomTag studyIdentifiers[] =
- {
- DICOM_TAG_PATIENT_ID,
- DICOM_TAG_PATIENT_NAME,
- DICOM_TAG_PATIENT_BIRTH_DATE,
- DICOM_TAG_STUDY_INSTANCE_UID,
- DICOM_TAG_ACCESSION_NUMBER,
- DICOM_TAG_STUDY_DESCRIPTION,
- DICOM_TAG_STUDY_DATE
- };
-
- static const DicomTag seriesIdentifiers[] =
- {
- DICOM_TAG_SERIES_INSTANCE_UID
- };
-
- static const DicomTag instanceIdentifiers[] =
- {
- DICOM_TAG_SOP_INSTANCE_UID
- };
-
-
- void LookupIdentifierQuery::LoadIdentifiers(const DicomTag*& tags,
- size_t& size,
- ResourceType level)
- {
- switch (level)
- {
- case ResourceType_Patient:
- tags = patientIdentifiers;
- size = sizeof(patientIdentifiers) / sizeof(DicomTag);
- break;
-
- case ResourceType_Study:
- tags = studyIdentifiers;
- size = sizeof(studyIdentifiers) / sizeof(DicomTag);
- break;
-
- case ResourceType_Series:
- tags = seriesIdentifiers;
- size = sizeof(seriesIdentifiers) / sizeof(DicomTag);
- break;
-
- case ResourceType_Instance:
- tags = instanceIdentifiers;
- size = sizeof(instanceIdentifiers) / sizeof(DicomTag);
- break;
-
- default:
- throw OrthancException(ErrorCode_ParameterOutOfRange);
- }
- }
-
-
LookupIdentifierQuery::Disjunction::~Disjunction()
{
for (size_t i = 0; i < disjunction_.size(); i++)
@@ -131,27 +70,6 @@ namespace Orthanc
}
-
- bool LookupIdentifierQuery::IsIdentifier(const DicomTag& tag,
- ResourceType level)
- {
- const DicomTag* tags;
- size_t size;
-
- LoadIdentifiers(tags, size, level);
-
- for (size_t i = 0; i < size; i++)
- {
- if (tag == tags[i])
- {
- return true;
- }
- }
-
- return false;
- }
-
-
void LookupIdentifierQuery::AddConstraint(DicomTag tag,
IdentifierConstraintType type,
const std::string& value)
@@ -169,56 +87,6 @@ namespace Orthanc
}
- std::string LookupIdentifierQuery::NormalizeIdentifier(const std::string& value)
- {
- std::string t;
- t.reserve(value.size());
-
- for (size_t i = 0; i < value.size(); i++)
- {
- if (value[i] == '%' ||
- value[i] == '_')
- {
- t.push_back(' '); // These characters might break wildcard queries in SQL
- }
- else if (isascii(value[i]) &&
- !iscntrl(value[i]) &&
- (!isspace(value[i]) || value[i] == ' '))
- {
- t.push_back(value[i]);
- }
- }
-
- Toolbox::ToUpperCase(t);
-
- return Toolbox::StripSpaces(t);
- }
-
-
- void LookupIdentifierQuery::StoreIdentifiers(IDatabaseWrapper& database,
- int64_t resource,
- ResourceType level,
- const DicomMap& map)
- {
- const DicomTag* tags;
- size_t size;
-
- LoadIdentifiers(tags, size, level);
-
- for (size_t i = 0; i < size; i++)
- {
- const DicomValue* value = map.TestAndGetValue(tags[i]);
- if (value != NULL &&
- !value->IsNull() &&
- !value->IsBinary())
- {
- std::string s = NormalizeIdentifier(value->GetContent());
- database.SetIdentifierTag(resource, tags[i], s);
- }
- }
- }
-
-
void LookupIdentifierQuery::Apply(std::list<std::string>& result,
IDatabaseWrapper& database)
{
@@ -264,7 +132,7 @@ namespace Orthanc
for (size_t j = 0; j < (*it)->GetSize(); j++)
{
const Constraint& c = (*it)->GetConstraint(j);
- s << FromDcmtkBridge::GetName(c.GetTag());
+ s << FromDcmtkBridge::GetTagName(c.GetTag(), "");
switch (c.GetType())
{
diff --git a/OrthancServer/Search/LookupIdentifierQuery.h b/OrthancServer/Search/LookupIdentifierQuery.h
index fa8d9c3..0ad2708 100644
--- a/OrthancServer/Search/LookupIdentifierQuery.h
+++ b/OrthancServer/Search/LookupIdentifierQuery.h
@@ -32,7 +32,7 @@
#pragma once
-#include "../ServerEnumerations.h"
+#include "../ServerToolbox.h"
#include "../IDatabaseWrapper.h"
#include "SetOfResources.h"
@@ -78,7 +78,7 @@ namespace Orthanc
const std::string& value) :
tag_(tag),
type_(type),
- value_(NormalizeIdentifier(value))
+ value_(ServerToolbox::NormalizeIdentifier(value))
{
}
@@ -138,7 +138,7 @@ namespace Orthanc
bool IsIdentifier(const DicomTag& tag)
{
- return IsIdentifier(tag, level_);
+ return ServerToolbox::IsIdentifier(tag, level_);
}
void AddConstraint(DicomTag tag,
@@ -164,20 +164,6 @@ namespace Orthanc
void Apply(SetOfResources& result,
IDatabaseWrapper& database);
- static void LoadIdentifiers(const DicomTag*& tags,
- size_t& size,
- ResourceType level);
-
- static bool IsIdentifier(const DicomTag& tag,
- ResourceType level);
-
- static void StoreIdentifiers(IDatabaseWrapper& database,
- int64_t resource,
- ResourceType level,
- const DicomMap& map);
-
- static std::string NormalizeIdentifier(const std::string& value);
-
void Print(std::ostream& s) const;
};
}
diff --git a/OrthancServer/Search/LookupResource.cpp b/OrthancServer/Search/LookupResource.cpp
index 2c62a1a..b073d92 100644
--- a/OrthancServer/Search/LookupResource.cpp
+++ b/OrthancServer/Search/LookupResource.cpp
@@ -46,7 +46,7 @@ namespace Orthanc
const DicomTag* tags = NULL;
size_t size;
- LookupIdentifierQuery::LoadIdentifiers(tags, size, level);
+ ServerToolbox::LoadIdentifiers(tags, size, level);
for (size_t i = 0; i < size; i++)
{
@@ -125,16 +125,16 @@ namespace Orthanc
levels_[ResourceType_Patient] = new Level(ResourceType_Patient);
break;
- case ResourceType_Study:
- levels_[ResourceType_Study] = new Level(ResourceType_Study);
+ case ResourceType_Instance:
+ levels_[ResourceType_Instance] = new Level(ResourceType_Instance);
// Do not add "break" here
case ResourceType_Series:
levels_[ResourceType_Series] = new Level(ResourceType_Series);
// Do not add "break" here
- case ResourceType_Instance:
- levels_[ResourceType_Instance] = new Level(ResourceType_Instance);
+ case ResourceType_Study:
+ levels_[ResourceType_Study] = new Level(ResourceType_Study);
break;
default:
diff --git a/OrthancServer/ServerContext.cpp b/OrthancServer/ServerContext.cpp
index e183296..87aedc8 100644
--- a/OrthancServer/ServerContext.cpp
+++ b/OrthancServer/ServerContext.cpp
@@ -52,6 +52,7 @@
#include "Scheduler/StorePeerCommand.h"
#include "OrthancRestApi/OrthancRestApi.h"
#include "../Plugins/Engine/OrthancPlugins.h"
+#include "Search/LookupResource.h"
#define ENABLE_DICOM_CACHE 1
@@ -85,12 +86,24 @@ namespace Orthanc
{
try
{
- it->GetListener().SignalChange(change);
+ try
+ {
+ it->GetListener().SignalChange(change);
+ }
+ catch (std::bad_alloc&)
+ {
+ LOG(ERROR) << "Not enough memory while signaling a change";
+ }
+ catch (...)
+ {
+ throw OrthancException(ErrorCode_InternalError);
+ }
}
catch (OrthancException& e)
{
LOG(ERROR) << "Error in the " << it->GetDescription()
- << " callback while signaling a change: " << e.What();
+ << " callback while signaling a change: " << e.What()
+ << " (code " << e.GetErrorCode() << ")";
}
}
}
@@ -106,16 +119,16 @@ namespace Orthanc
storeMD5_(true),
provider_(*this),
dicomCache_(provider_, DICOM_CACHE_SIZE),
- scheduler_(Configuration::GetGlobalIntegerParameter("LimitJobs", 10)),
+ scheduler_(Configuration::GetGlobalUnsignedIntegerParameter("LimitJobs", 10)),
lua_(*this),
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
plugins_(NULL),
#endif
done_(false),
- queryRetrieveArchive_(Configuration::GetGlobalIntegerParameter("QueryRetrieveSize", 10)),
+ queryRetrieveArchive_(Configuration::GetGlobalUnsignedIntegerParameter("QueryRetrieveSize", 10)),
defaultLocalAet_(Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC"))
{
- uint64_t s = Configuration::GetGlobalIntegerParameter("DicomAssociationCloseDelay", 5); // In seconds
+ uint64_t s = Configuration::GetGlobalUnsignedIntegerParameter("DicomAssociationCloseDelay", 5); // In seconds
scu_.SetMillisecondsBeforeClose(s * 1000); // Milliseconds are expected here
listeners_.push_back(ServerListener(lua_, "Lua"));
@@ -189,7 +202,7 @@ namespace Orthanc
resultPublicId = hasher.HashInstance();
Json::Value simplifiedTags;
- Toolbox::SimplifyTags(simplifiedTags, dicom.GetJson(), DicomToJsonFormat_Human);
+ ServerToolbox::SimplifyTags(simplifiedTags, dicom.GetJson(), DicomToJsonFormat_Human);
// Test if the instance must be filtered out
bool accepted = true;
@@ -210,7 +223,8 @@ namespace Orthanc
catch (OrthancException& e)
{
LOG(ERROR) << "Error in the " << it->GetDescription()
- << " callback while receiving an instance: " << e.What();
+ << " callback while receiving an instance: " << e.What()
+ << " (code " << e.GetErrorCode() << ")";
throw;
}
}
@@ -287,7 +301,8 @@ namespace Orthanc
catch (OrthancException& e)
{
LOG(ERROR) << "Error in the " << it->GetDescription()
- << " callback while receiving an instance: " << e.What();
+ << " callback while receiving an instance: " << e.What()
+ << " (code " << e.GetErrorCode() << ")";
}
}
}
@@ -298,7 +313,7 @@ namespace Orthanc
{
if (e.GetErrorCode() == ErrorCode_InexistentTag)
{
- Toolbox::LogMissingRequiredTag(dicom.GetSummary());
+ ServerToolbox::LogMissingRequiredTag(dicom.GetSummary());
}
throw;
@@ -367,35 +382,67 @@ namespace Orthanc
}
- void ServerContext::ReadJson(Json::Value& result,
- const std::string& instancePublicId)
+ void ServerContext::ReadDicomAsJson(std::string& result,
+ const std::string& instancePublicId)
+ {
+ FileInfo attachment;
+ if (index_.LookupAttachment(attachment, instancePublicId, FileContentType_DicomAsJson))
+ {
+ ReadAttachment(result, attachment);
+ return;
+ }
+
+ // The "DICOM as JSON" summary is not available from the Orthanc
+ // store (most probably deleted), reconstruct it from the DICOM file
+ std::string dicom;
+ ReadDicom(dicom, instancePublicId);
+
+ LOG(INFO) << "Reconstructing the missing DICOM-as-JSON summary for instance: " << instancePublicId;
+
+ ParsedDicomFile parsed(dicom);
+
+ Json::Value summary;
+ parsed.DatasetToJson(summary);
+
+ result = summary.toStyledString();
+
+ if (!AddAttachment(instancePublicId, FileContentType_DicomAsJson, result.c_str(), result.size()))
+ {
+ LOG(WARNING) << "Cannot associate the DICOM-as-JSON summary to instance: " << instancePublicId;
+ throw OrthancException(ErrorCode_InternalError);
+ }
+ }
+
+
+ void ServerContext::ReadDicomAsJson(Json::Value& result,
+ const std::string& instancePublicId)
{
- std::string s;
- ReadFile(s, instancePublicId, FileContentType_DicomAsJson);
+ std::string tmp;
+ ReadDicomAsJson(tmp, instancePublicId);
Json::Reader reader;
- if (!reader.parse(s, result))
+ if (!reader.parse(tmp, result))
{
throw OrthancException(ErrorCode_CorruptedFile);
}
}
- void ServerContext::ReadFile(std::string& result,
- const std::string& instancePublicId,
- FileContentType content,
- bool uncompressIfNeeded)
+ void ServerContext::ReadAttachment(std::string& result,
+ const std::string& instancePublicId,
+ FileContentType content,
+ bool uncompressIfNeeded)
{
FileInfo attachment;
if (!index_.LookupAttachment(attachment, instancePublicId, content))
{
+ LOG(WARNING) << "Unable to read attachment " << EnumerationToString(content) << " of instance " << instancePublicId;
throw OrthancException(ErrorCode_InternalError);
}
if (uncompressIfNeeded)
{
- StorageAccessor accessor(area_);
- accessor.Read(result, attachment);
+ ReadAttachment(result, attachment);
}
else
{
@@ -406,18 +453,19 @@ namespace Orthanc
}
- void ServerContext::ReadFile(std::string& result,
- const FileInfo& file)
+ void ServerContext::ReadAttachment(std::string& result,
+ const FileInfo& attachment)
{
+ // This will decompress the attachment
StorageAccessor accessor(area_);
- accessor.Read(result, file);
+ accessor.Read(result, attachment);
}
IDynamicObject* ServerContext::DicomCacheProvider::Provide(const std::string& instancePublicId)
{
std::string content;
- context_.ReadFile(content, instancePublicId, FileContentType_Dicom);
+ context_.ReadDicom(content, instancePublicId);
return new ParsedDicomFile(content);
}
@@ -489,7 +537,7 @@ namespace Orthanc
}
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
void ServerContext::SetPlugins(OrthancPlugins& plugins)
{
boost::recursive_mutex::scoped_lock lock(listenersMutex_);
@@ -544,7 +592,7 @@ namespace Orthanc
bool ServerContext::HasPlugins() const
{
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
return (plugins_ != NULL);
#else
return false;
@@ -566,7 +614,7 @@ namespace Orthanc
for (size_t i = 0; i < instances.size(); i++)
{
Json::Value dicom;
- ReadJson(dicom, instances[i]);
+ ReadDicomAsJson(dicom, instances[i]);
if (lookup.IsMatch(dicom))
{
diff --git a/OrthancServer/ServerContext.h b/OrthancServer/ServerContext.h
index 95d320b..2d97d65 100644
--- a/OrthancServer/ServerContext.h
+++ b/OrthancServer/ServerContext.h
@@ -47,7 +47,6 @@
#include "Scheduler/ServerScheduler.h"
#include "ServerIndex.h"
#include "OrthancHttpHandler.h"
-#include "Search/LookupResource.h"
#include <boost/filesystem.hpp>
#include <boost/thread.hpp>
@@ -121,7 +120,7 @@ namespace Orthanc
LuaScripting lua_;
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
OrthancPlugins* plugins_;
#endif
@@ -192,17 +191,26 @@ namespace Orthanc
FileContentType attachmentType,
CompressionType compression);
- void ReadJson(Json::Value& result,
- const std::string& instancePublicId);
+ void ReadDicomAsJson(std::string& result,
+ const std::string& instancePublicId);
- // TODO CACHING MECHANISM AT THIS POINT
- void ReadFile(std::string& result,
- const std::string& instancePublicId,
- FileContentType content,
- bool uncompressIfNeeded = true);
+ void ReadDicomAsJson(Json::Value& result,
+ const std::string& instancePublicId);
- void ReadFile(std::string& result,
- const FileInfo& file);
+ void ReadDicom(std::string& dicom,
+ const std::string& instancePublicId)
+ {
+ ReadAttachment(dicom, instancePublicId, FileContentType_Dicom, true);
+ }
+
+ // TODO CACHING MECHANISM AT THIS POINT
+ void ReadAttachment(std::string& result,
+ const std::string& instancePublicId,
+ FileContentType content,
+ bool uncompressIfNeeded);
+
+ void ReadAttachment(std::string& result,
+ const FileInfo& attachment);
void SetStoreMD5ForAttachments(bool storeMD5);
@@ -258,7 +266,7 @@ namespace Orthanc
* Management of the plugins
**/
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
void SetPlugins(OrthancPlugins& plugins);
void ResetPlugins();
diff --git a/OrthancServer/ServerEnumerations.cpp b/OrthancServer/ServerEnumerations.cpp
index 8e3fdf3..a69ef0c 100644
--- a/OrthancServer/ServerEnumerations.cpp
+++ b/OrthancServer/ServerEnumerations.cpp
@@ -64,6 +64,8 @@ namespace Orthanc
dictMetadataType_.Add(MetadataType_AnonymizedFrom, "AnonymizedFrom");
dictMetadataType_.Add(MetadataType_LastUpdate, "LastUpdate");
dictMetadataType_.Add(MetadataType_Instance_Origin, "Origin");
+ dictMetadataType_.Add(MetadataType_Instance_TransferSyntax, "TransferSyntax");
+ dictMetadataType_.Add(MetadataType_Instance_SopClassUid, "SopClassUid");
dictContentType_.Add(FileContentType_Dicom, "dicom");
dictContentType_.Add(FileContentType_DicomAsJson, "dicom-as-json");
diff --git a/OrthancServer/ServerEnumerations.h b/OrthancServer/ServerEnumerations.h
index 8765680..be3f69a 100644
--- a/OrthancServer/ServerEnumerations.h
+++ b/OrthancServer/ServerEnumerations.h
@@ -157,7 +157,9 @@ namespace Orthanc
MetadataType_ModifiedFrom = 5,
MetadataType_AnonymizedFrom = 6,
MetadataType_LastUpdate = 7,
- MetadataType_Instance_Origin = 8, // New in Orthanc 0.9.5
+ MetadataType_Instance_Origin = 8, // New in Orthanc 0.9.5
+ MetadataType_Instance_TransferSyntax = 9, // New in Orthanc 1.2.0
+ MetadataType_Instance_SopClassUid = 10, // New in Orthanc 1.2.0
// Make sure that the value "65535" can be stored into this enumeration
MetadataType_StartUser = 1024,
diff --git a/OrthancServer/ServerIndex.cpp b/OrthancServer/ServerIndex.cpp
index 5cf4702..29dcfe5 100644
--- a/OrthancServer/ServerIndex.cpp
+++ b/OrthancServer/ServerIndex.cpp
@@ -40,17 +40,16 @@
#include "ServerIndexChange.h"
#include "EmbeddedResources.h"
#include "OrthancInitialization.h"
+#include "ParsedDicomFile.h"
#include "ServerToolbox.h"
#include "../Core/Toolbox.h"
#include "../Core/Logging.h"
-#include "../Core/Uuid.h"
#include "../Core/DicomFormat/DicomArray.h"
-#include "Search/LookupIdentifierQuery.h"
-#include "Search/LookupResource.h"
#include "FromDcmtkBridge.h"
#include "ServerContext.h"
#include "DicomInstanceToStore.h"
+#include "Search/LookupResource.h"
#include <boost/lexical_cast.hpp>
#include <stdio.h>
@@ -375,6 +374,8 @@ namespace Orthanc
continue;
}
+ Logging::Flush();
+
boost::mutex::scoped_lock lock(that->mutex_);
that->db_.FlushToDisk();
count = 0;
@@ -593,6 +594,17 @@ namespace Orthanc
+ void ServerIndex::SetInstanceMetadata(std::map<MetadataType, std::string>& instanceMetadata,
+ int64_t instance,
+ MetadataType metadata,
+ const std::string& value)
+ {
+ db_.SetMetadata(instance, metadata, value);
+ instanceMetadata[metadata] = value;
+ }
+
+
+
StoreStatus ServerIndex::Store(std::map<MetadataType, std::string>& instanceMetadata,
DicomInstanceToStore& instanceToStore,
const Attachments& attachments)
@@ -634,7 +646,7 @@ namespace Orthanc
// Create the instance
int64_t instance = CreateResource(hasher.HashInstance(), ResourceType_Instance);
- Toolbox::SetMainDicomTags(db_, instance, ResourceType_Instance, dicomSummary);
+ ServerToolbox::StoreMainDicomTags(db_, instance, ResourceType_Instance, dicomSummary);
// Detect up to which level the patient/study/series/instance
// hierarchy must be created
@@ -686,21 +698,21 @@ namespace Orthanc
if (isNewSeries)
{
series = CreateResource(hasher.HashSeries(), ResourceType_Series);
- Toolbox::SetMainDicomTags(db_, series, ResourceType_Series, dicomSummary);
+ ServerToolbox::StoreMainDicomTags(db_, series, ResourceType_Series, dicomSummary);
}
// Create the study if needed
if (isNewStudy)
{
study = CreateResource(hasher.HashStudy(), ResourceType_Study);
- Toolbox::SetMainDicomTags(db_, study, ResourceType_Study, dicomSummary);
+ ServerToolbox::StoreMainDicomTags(db_, study, ResourceType_Study, dicomSummary);
}
// Create the patient if needed
if (isNewPatient)
{
patient = CreateResource(hasher.HashPatient(), ResourceType_Patient);
- Toolbox::SetMainDicomTags(db_, patient, ResourceType_Patient, dicomSummary);
+ ServerToolbox::StoreMainDicomTags(db_, patient, ResourceType_Patient, dicomSummary);
}
// Create the parent-to-child links
@@ -748,8 +760,7 @@ namespace Orthanc
break;
case ResourceType_Instance:
- db_.SetMetadata(instance, it->first.second, it->second);
- instanceMetadata[it->first.second] = it->second;
+ SetInstanceMetadata(instanceMetadata, instance, it->first.second, it->second);
break;
default:
@@ -758,34 +769,41 @@ namespace Orthanc
}
// Attach the auto-computed metadata for the patient/study/series levels
- std::string now = Toolbox::GetNowIsoString();
+ std::string now = SystemToolbox::GetNowIsoString();
db_.SetMetadata(series, MetadataType_LastUpdate, now);
db_.SetMetadata(study, MetadataType_LastUpdate, now);
db_.SetMetadata(patient, MetadataType_LastUpdate, now);
// Attach the auto-computed metadata for the instance level,
// reflecting these additions into the input metadata map
- db_.SetMetadata(instance, MetadataType_Instance_ReceptionDate, now);
- instanceMetadata[MetadataType_Instance_ReceptionDate] = now;
-
- db_.SetMetadata(instance, MetadataType_Instance_RemoteAet, instanceToStore.GetRemoteAet());
- instanceMetadata[MetadataType_Instance_RemoteAet] = instanceToStore.GetRemoteAet();
-
+ SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_ReceptionDate, now);
+ SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_RemoteAet, instanceToStore.GetRemoteAet());
+ SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_Origin,
+ EnumerationToString(instanceToStore.GetRequestOrigin()));
+
{
- std::string s = EnumerationToString(instanceToStore.GetRequestOrigin());
- db_.SetMetadata(instance, MetadataType_Instance_Origin, s);
- instanceMetadata[MetadataType_Instance_Origin] = s;
+ std::string s;
+ if (instanceToStore.LookupTransferSyntax(s))
+ {
+ SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_TransferSyntax, s);
+ }
}
const DicomValue* value;
+ if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL &&
+ !value->IsNull() &&
+ !value->IsBinary())
+ {
+ SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_SopClassUid, value->GetContent());
+ }
+
if ((value = dicomSummary.TestAndGetValue(DICOM_TAG_INSTANCE_NUMBER)) != NULL ||
(value = dicomSummary.TestAndGetValue(DICOM_TAG_IMAGE_INDEX)) != NULL)
{
if (!value->IsNull() &&
!value->IsBinary())
{
- db_.SetMetadata(instance, MetadataType_Instance_IndexInSeries, value->GetContent());
- instanceMetadata[MetadataType_Instance_IndexInSeries] = value->GetContent();
+ SetInstanceMetadata(instanceMetadata, instance, MetadataType_Instance_IndexInSeries, value->GetContent());
}
}
@@ -1214,22 +1232,34 @@ namespace Orthanc
switch (currentType)
{
case ResourceType_Patient:
- patientId = map.GetValue(DICOM_TAG_PATIENT_ID).GetContent();
+ if (map.HasTag(DICOM_TAG_PATIENT_ID))
+ {
+ patientId = map.GetValue(DICOM_TAG_PATIENT_ID).GetContent();
+ }
done = true;
break;
case ResourceType_Study:
- studyInstanceUid = map.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent();
+ if (map.HasTag(DICOM_TAG_STUDY_INSTANCE_UID))
+ {
+ studyInstanceUid = map.GetValue(DICOM_TAG_STUDY_INSTANCE_UID).GetContent();
+ }
currentType = ResourceType_Patient;
break;
case ResourceType_Series:
- seriesInstanceUid = map.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent();
+ if (map.HasTag(DICOM_TAG_SERIES_INSTANCE_UID))
+ {
+ seriesInstanceUid = map.GetValue(DICOM_TAG_SERIES_INSTANCE_UID).GetContent();
+ }
currentType = ResourceType_Study;
break;
case ResourceType_Instance:
- sopInstanceUid = map.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent();
+ if (map.HasTag(DICOM_TAG_SOP_INSTANCE_UID))
+ {
+ sopInstanceUid = map.GetValue(DICOM_TAG_SOP_INSTANCE_UID).GetContent();
+ }
currentType = ResourceType_Series;
break;
@@ -1250,7 +1280,7 @@ namespace Orthanc
type,
publicId,
remoteModality,
- Toolbox::GetNowIsoString(),
+ SystemToolbox::GetNowIsoString(),
patientId,
studyInstanceUid,
seriesInstanceUid,
@@ -1848,7 +1878,7 @@ namespace Orthanc
void ServerIndex::UnstableResourcesMonitorThread(ServerIndex* that)
{
- int stableAge = Configuration::GetGlobalIntegerParameter("StableAge", 60);
+ int stableAge = Configuration::GetGlobalUnsignedIntegerParameter("StableAge", 60);
if (stableAge <= 0)
{
stableAge = 60;
@@ -2168,7 +2198,7 @@ namespace Orthanc
assert(db_.GetResourceType(*it) == lookup.GetLevel());
int64_t instance;
- if (!Toolbox::FindOneChildInstance(instance, db_, *it, lookup.GetLevel()))
+ if (!ServerToolbox::FindOneChildInstance(instance, db_, *it, lookup.GetLevel()))
{
throw OrthancException(ErrorCode_InternalError);
}
@@ -2209,4 +2239,67 @@ namespace Orthanc
target = db_.GetPublicId(id);
return true;
}
+
+
+ void ServerIndex::ReconstructInstance(ParsedDicomFile& dicom)
+ {
+ DicomMap summary;
+ dicom.ExtractDicomSummary(summary);
+
+ DicomInstanceHasher hasher(summary);
+
+ boost::mutex::scoped_lock lock(mutex_);
+
+ try
+ {
+ Transaction t(*this);
+
+ int64_t patient = -1, study = -1, series = -1, instance = -1;
+
+ ResourceType dummy;
+ if (!db_.LookupResource(patient, dummy, hasher.HashPatient()) ||
+ !db_.LookupResource(study, dummy, hasher.HashStudy()) ||
+ !db_.LookupResource(series, dummy, hasher.HashSeries()) ||
+ !db_.LookupResource(instance, dummy, hasher.HashInstance()) ||
+ patient == -1 ||
+ study == -1 ||
+ series == -1 ||
+ instance == -1)
+ {
+ throw OrthancException(ErrorCode_InternalError);
+ }
+
+ db_.ClearMainDicomTags(patient);
+ db_.ClearMainDicomTags(study);
+ db_.ClearMainDicomTags(series);
+ db_.ClearMainDicomTags(instance);
+
+ ServerToolbox::StoreMainDicomTags(db_, patient, ResourceType_Patient, summary);
+ ServerToolbox::StoreMainDicomTags(db_, study, ResourceType_Study, summary);
+ ServerToolbox::StoreMainDicomTags(db_, series, ResourceType_Series, summary);
+ ServerToolbox::StoreMainDicomTags(db_, instance, ResourceType_Instance, summary);
+
+ {
+ std::string s;
+ if (dicom.LookupTransferSyntax(s))
+ {
+ db_.SetMetadata(instance, MetadataType_Instance_TransferSyntax, s);
+ }
+ }
+
+ const DicomValue* value;
+ if ((value = summary.TestAndGetValue(DICOM_TAG_SOP_CLASS_UID)) != NULL &&
+ !value->IsNull() &&
+ !value->IsBinary())
+ {
+ db_.SetMetadata(instance, MetadataType_Instance_SopClassUid, value->GetContent());
+ }
+
+ t.Commit(0); // No change in the DB size
+ }
+ catch (OrthancException& e)
+ {
+ LOG(ERROR) << "EXCEPTION [" << e.What() << "]";
+ }
+ }
}
diff --git a/OrthancServer/ServerIndex.h b/OrthancServer/ServerIndex.h
index dece92d..dc2e84b 100644
--- a/OrthancServer/ServerIndex.h
+++ b/OrthancServer/ServerIndex.h
@@ -47,6 +47,7 @@ namespace Orthanc
class LookupResource;
class ServerContext;
class DicomInstanceToStore;
+ class ParsedDicomFile;
class ServerIndex : public boost::noncopyable
{
@@ -115,6 +116,11 @@ namespace Orthanc
int64_t CreateResource(const std::string& publicId,
ResourceType type);
+ void SetInstanceMetadata(std::map<MetadataType, std::string>& instanceMetadata,
+ int64_t instance,
+ MetadataType metadata,
+ const std::string& value);
+
public:
ServerIndex(ServerContext& context,
IDatabaseWrapper& database);
@@ -268,5 +274,7 @@ namespace Orthanc
bool LookupParent(std::string& target,
const std::string& publicId,
ResourceType parentType);
+
+ void ReconstructInstance(ParsedDicomFile& dicom);
};
}
diff --git a/OrthancServer/ServerIndexChange.h b/OrthancServer/ServerIndexChange.h
index d779840..836c5b3 100644
--- a/OrthancServer/ServerIndexChange.h
+++ b/OrthancServer/ServerIndexChange.h
@@ -34,7 +34,7 @@
#include "ServerEnumerations.h"
#include "../Core/IDynamicObject.h"
-#include "../Core/Toolbox.h"
+#include "../Core/SystemToolbox.h"
#include <string>
#include <json/value.h>
@@ -58,7 +58,7 @@ namespace Orthanc
changeType_(changeType),
resourceType_(resourceType),
publicId_(publicId),
- date_(Toolbox::GetNowIsoString())
+ date_(SystemToolbox::GetNowIsoString())
{
}
diff --git a/OrthancServer/ServerToolbox.cpp b/OrthancServer/ServerToolbox.cpp
index 0d7a877..e8589d8 100644
--- a/OrthancServer/ServerToolbox.cpp
+++ b/OrthancServer/ServerToolbox.cpp
@@ -37,15 +37,42 @@
#include "../Core/FileStorage/StorageAccessor.h"
#include "../Core/Logging.h"
#include "../Core/OrthancException.h"
-#include "ParsedDicomFile.h"
-#include "Search/LookupIdentifierQuery.h"
#include <cassert>
namespace Orthanc
{
- namespace Toolbox
+ namespace ServerToolbox
{
+ static const DicomTag patientIdentifiers[] =
+ {
+ DICOM_TAG_PATIENT_ID,
+ DICOM_TAG_PATIENT_NAME,
+ DICOM_TAG_PATIENT_BIRTH_DATE
+ };
+
+ static const DicomTag studyIdentifiers[] =
+ {
+ DICOM_TAG_PATIENT_ID,
+ DICOM_TAG_PATIENT_NAME,
+ DICOM_TAG_PATIENT_BIRTH_DATE,
+ DICOM_TAG_STUDY_INSTANCE_UID,
+ DICOM_TAG_ACCESSION_NUMBER,
+ DICOM_TAG_STUDY_DESCRIPTION,
+ DICOM_TAG_STUDY_DATE
+ };
+
+ static const DicomTag seriesIdentifiers[] =
+ {
+ DICOM_TAG_SERIES_INSTANCE_UID
+ };
+
+ static const DicomTag instanceIdentifiers[] =
+ {
+ DICOM_TAG_SOP_INSTANCE_UID
+ };
+
+
void SimplifyTags(Json::Value& target,
const Json::Value& source,
DicomToJsonFormat format)
@@ -189,9 +216,9 @@ namespace Orthanc
}
- static void SetMainDicomTagsInternal(IDatabaseWrapper& database,
- int64_t resource,
- const DicomMap& tags)
+ static void StoreMainDicomTagsInternal(IDatabaseWrapper& database,
+ int64_t resource,
+ const DicomMap& tags)
{
DicomArray flattened(tags);
@@ -209,14 +236,38 @@ namespace Orthanc
}
- void SetMainDicomTags(IDatabaseWrapper& database,
- int64_t resource,
- ResourceType level,
- const DicomMap& dicomSummary)
+ static void StoreIdentifiers(IDatabaseWrapper& database,
+ int64_t resource,
+ ResourceType level,
+ const DicomMap& map)
+ {
+ const DicomTag* tags;
+ size_t size;
+
+ LoadIdentifiers(tags, size, level);
+
+ for (size_t i = 0; i < size; i++)
+ {
+ const DicomValue* value = map.TestAndGetValue(tags[i]);
+ if (value != NULL &&
+ !value->IsNull() &&
+ !value->IsBinary())
+ {
+ std::string s = NormalizeIdentifier(value->GetContent());
+ database.SetIdentifierTag(resource, tags[i], s);
+ }
+ }
+ }
+
+
+ void StoreMainDicomTags(IDatabaseWrapper& database,
+ int64_t resource,
+ ResourceType level,
+ const DicomMap& dicomSummary)
{
// WARNING: The database should be locked with a transaction!
- LookupIdentifierQuery::StoreIdentifiers(database, resource, level, dicomSummary);
+ StoreIdentifiers(database, resource, level, dicomSummary);
DicomMap tags;
@@ -229,7 +280,7 @@ namespace Orthanc
case ResourceType_Study:
// Duplicate the patient tags at the study level (new in Orthanc 0.9.5 - db v6)
dicomSummary.ExtractPatientInformation(tags);
- SetMainDicomTagsInternal(database, resource, tags);
+ StoreMainDicomTagsInternal(database, resource, tags);
dicomSummary.ExtractStudyInformation(tags);
break;
@@ -246,7 +297,7 @@ namespace Orthanc
throw OrthancException(ErrorCode_InternalError);
}
- SetMainDicomTagsInternal(database, resource, tags);
+ StoreMainDicomTagsInternal(database, resource, tags);
}
@@ -282,6 +333,13 @@ namespace Orthanc
{
// WARNING: The database should be locked with a transaction!
+ // TODO: This function might consume much memory if level ==
+ // ResourceType_Instance. To improve this, first download the
+ // list of studies, then remove the instances for each single
+ // study (check out OrthancRestApi::InvalidateTags for an
+ // example). Take this improvement into consideration for the
+ // next upgrade of the database schema.
+
const char* plural = NULL;
switch (level)
@@ -347,10 +405,10 @@ namespace Orthanc
// Update the tags of this resource
DicomMap dicomSummary;
- dicom.Convert(dicomSummary);
+ dicom.ExtractDicomSummary(dicomSummary);
database.ClearMainDicomTags(resource);
- Toolbox::SetMainDicomTags(database, resource, level, dicomSummary);
+ StoreMainDicomTags(database, resource, level, dicomSummary);
}
catch (OrthancException&)
{
@@ -360,5 +418,107 @@ namespace Orthanc
}
}
}
+
+
+ void LoadIdentifiers(const DicomTag*& tags,
+ size_t& size,
+ ResourceType level)
+ {
+ switch (level)
+ {
+ case ResourceType_Patient:
+ tags = patientIdentifiers;
+ size = sizeof(patientIdentifiers) / sizeof(DicomTag);
+ break;
+
+ case ResourceType_Study:
+ tags = studyIdentifiers;
+ size = sizeof(studyIdentifiers) / sizeof(DicomTag);
+ break;
+
+ case ResourceType_Series:
+ tags = seriesIdentifiers;
+ size = sizeof(seriesIdentifiers) / sizeof(DicomTag);
+ break;
+
+ case ResourceType_Instance:
+ tags = instanceIdentifiers;
+ size = sizeof(instanceIdentifiers) / sizeof(DicomTag);
+ break;
+
+ default:
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+ }
+
+
+ std::string NormalizeIdentifier(const std::string& value)
+ {
+ std::string t;
+ t.reserve(value.size());
+
+ for (size_t i = 0; i < value.size(); i++)
+ {
+ if (value[i] == '%' ||
+ value[i] == '_')
+ {
+ t.push_back(' '); // These characters might break wildcard queries in SQL
+ }
+ else if (isascii(value[i]) &&
+ !iscntrl(value[i]) &&
+ (!isspace(value[i]) || value[i] == ' '))
+ {
+ t.push_back(value[i]);
+ }
+ }
+
+ Toolbox::ToUpperCase(t);
+
+ return Toolbox::StripSpaces(t);
+ }
+
+
+ bool IsIdentifier(const DicomTag& tag,
+ ResourceType level)
+ {
+ const DicomTag* tags;
+ size_t size;
+
+ LoadIdentifiers(tags, size, level);
+
+ for (size_t i = 0; i < size; i++)
+ {
+ if (tag == tags[i])
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+
+ void ReconstructResource(ServerContext& context,
+ const std::string& resource)
+ {
+ LOG(WARNING) << "Reconstructing resource " << resource;
+
+ std::list<std::string> instances;
+ context.GetIndex().GetChildInstances(instances, resource);
+
+ for (std::list<std::string>::const_iterator
+ it = instances.begin(); it != instances.end(); ++it)
+ {
+ ServerContext::DicomCacheLocker locker(context, *it);
+
+ Json::Value dicomAsJson;
+ locker.GetDicom().ExtractDicomAsJson(dicomAsJson);
+
+ std::string s = dicomAsJson.toStyledString();
+ context.AddAttachment(*it, FileContentType_DicomAsJson, s.c_str(), s.size());
+
+ context.GetIndex().ReconstructInstance(locker.GetDicom());
+ }
+ }
}
}
diff --git a/OrthancServer/ServerToolbox.h b/OrthancServer/ServerToolbox.h
index 891f38a..61a02a5 100644
--- a/OrthancServer/ServerToolbox.h
+++ b/OrthancServer/ServerToolbox.h
@@ -32,14 +32,13 @@
#pragma once
-#include "../Core/DicomFormat/DicomMap.h"
-#include "IDatabaseWrapper.h"
+#include "ServerContext.h"
#include <json/json.h>
namespace Orthanc
{
- namespace Toolbox
+ namespace ServerToolbox
{
void SimplifyTags(Json::Value& target,
const Json::Value& source,
@@ -47,10 +46,10 @@ namespace Orthanc
void LogMissingRequiredTag(const DicomMap& summary);
- void SetMainDicomTags(IDatabaseWrapper& database,
- int64_t resource,
- ResourceType level,
- const DicomMap& dicomSummary);
+ void StoreMainDicomTags(IDatabaseWrapper& database,
+ int64_t resource,
+ ResourceType level,
+ const DicomMap& dicomSummary);
bool FindOneChildInstance(int64_t& result,
IDatabaseWrapper& database,
@@ -60,5 +59,17 @@ namespace Orthanc
void ReconstructMainDicomTags(IDatabaseWrapper& database,
IStorageArea& storageArea,
ResourceType level);
+
+ void LoadIdentifiers(const DicomTag*& tags,
+ size_t& size,
+ ResourceType level);
+
+ bool IsIdentifier(const DicomTag& tag,
+ ResourceType level);
+
+ std::string NormalizeIdentifier(const std::string& value);
+
+ void ReconstructResource(ServerContext& context,
+ const std::string& resource);
}
}
diff --git a/OrthancServer/ToDcmtkBridge.cpp b/OrthancServer/ToDcmtkBridge.cpp
index 708293a..0fec3f4 100644
--- a/OrthancServer/ToDcmtkBridge.cpp
+++ b/OrthancServer/ToDcmtkBridge.cpp
@@ -41,24 +41,6 @@
namespace Orthanc
{
- DcmDataset* ToDcmtkBridge::Convert(const DicomMap& map)
- {
- std::auto_ptr<DcmDataset> result(new DcmDataset);
-
- for (DicomMap::Map::const_iterator
- it = map.map_.begin(); it != map.map_.end(); ++it)
- {
- if (!it->second->IsNull())
- {
- std::string s = it->second->GetContent();
- DU_putStringDOElement(result.get(), Convert(it->first), s.c_str());
- }
- }
-
- return result.release();
- }
-
-
DcmEVR ToDcmtkBridge::Convert(ValueRepresentation vr)
{
switch (vr)
diff --git a/OrthancServer/ToDcmtkBridge.h b/OrthancServer/ToDcmtkBridge.h
index fff8bd4..9a78367 100644
--- a/OrthancServer/ToDcmtkBridge.h
+++ b/OrthancServer/ToDcmtkBridge.h
@@ -45,8 +45,6 @@ namespace Orthanc
return DcmTagKey(tag.GetGroup(), tag.GetElement());
}
- static DcmDataset* Convert(const DicomMap& map);
-
static DcmEVR Convert(ValueRepresentation vr);
};
}
diff --git a/OrthancServer/main.cpp b/OrthancServer/main.cpp
index fc27b4a..92c4cf7 100644
--- a/OrthancServer/main.cpp
+++ b/OrthancServer/main.cpp
@@ -36,7 +36,6 @@
#include <boost/algorithm/string/predicate.hpp>
#include "../Core/Logging.h"
-#include "../Core/Uuid.h"
#include "../Core/HttpServer/EmbeddedResourceHttpHandler.h"
#include "../Core/HttpServer/FilesystemHttpHandler.h"
#include "../Core/Lua/LuaFunctionCall.h"
@@ -111,8 +110,8 @@ public:
{
std::auto_ptr<OrthancFindRequestHandler> result(new OrthancFindRequestHandler(context_));
- result->SetMaxResults(Configuration::GetGlobalIntegerParameter("LimitFindResults", 0));
- result->SetMaxInstances(Configuration::GetGlobalIntegerParameter("LimitFindInstances", 0));
+ result->SetMaxResults(Configuration::GetGlobalUnsignedIntegerParameter("LimitFindResults", 0));
+ result->SetMaxInstances(Configuration::GetGlobalUnsignedIntegerParameter("LimitFindInstances", 0));
if (result->GetMaxResults() == 0)
{
@@ -370,7 +369,7 @@ public:
{
bool isPlugin = false;
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
if (plugins_ != NULL)
{
plugins_->GetErrorDictionary().LogError(exception.GetErrorCode(), true);
@@ -391,7 +390,7 @@ public:
{
bool isPlugin = false;
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
if (plugins_ != NULL &&
plugins_->GetErrorDictionary().Format(message, httpStatus, exception))
{
@@ -504,7 +503,7 @@ static void PrintErrors(const char* path)
PrintErrorCode(ErrorCode_Plugin, "Error encountered within the plugin engine");
PrintErrorCode(ErrorCode_NotImplemented, "Not implemented yet");
PrintErrorCode(ErrorCode_ParameterOutOfRange, "Parameter out of range");
- PrintErrorCode(ErrorCode_NotEnoughMemory, "Not enough memory");
+ PrintErrorCode(ErrorCode_NotEnoughMemory, "The server hosting Orthanc is running out of memory");
PrintErrorCode(ErrorCode_BadParameterType, "Bad type for a parameter");
PrintErrorCode(ErrorCode_BadSequenceOfCalls, "Bad sequence of calls");
PrintErrorCode(ErrorCode_InexistentItem, "Accessing an inexistent item");
@@ -535,6 +534,7 @@ static void PrintErrors(const char* path)
PrintErrorCode(ErrorCode_StorageAreaPlugin, "Error in the plugin implementing a custom storage area");
PrintErrorCode(ErrorCode_EmptyRequest, "The request is empty");
PrintErrorCode(ErrorCode_NotAcceptable, "Cannot send a response which is acceptable according to the Accept HTTP header");
+ PrintErrorCode(ErrorCode_NullPointer, "Cannot handle a NULL pointer");
PrintErrorCode(ErrorCode_SQLiteNotOpened, "SQLite: The database is not opened");
PrintErrorCode(ErrorCode_SQLiteAlreadyOpened, "SQLite: Connection is already open");
PrintErrorCode(ErrorCode_SQLiteCannotOpen, "SQLite: Unable to open the database");
@@ -611,7 +611,7 @@ static void LoadLuaScripts(ServerContext& context)
std::string path = Configuration::InterpretStringParameterAsPath(*it);
LOG(WARNING) << "Installing the Lua scripts from: " << path;
std::string script;
- Toolbox::ReadFile(script, path);
+ SystemToolbox::ReadFile(script, path);
LuaScripting::Locker locker(context.GetLua());
locker.GetLua().Execute(script);
@@ -620,7 +620,7 @@ static void LoadLuaScripts(ServerContext& context)
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
static void LoadPlugins(OrthancPlugins& plugins)
{
std::list<std::string> path;
@@ -643,7 +643,7 @@ static bool WaitForExit(ServerContext& context,
{
LOG(WARNING) << "Orthanc has started";
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
if (context.HasPlugins())
{
context.GetPlugins().SignalOrthancStarted();
@@ -656,7 +656,7 @@ static bool WaitForExit(ServerContext& context,
for (;;)
{
- ServerBarrierEvent event = Toolbox::ServerBarrier(restApi.LeaveBarrierFlag());
+ ServerBarrierEvent event = SystemToolbox::ServerBarrier(restApi.LeaveBarrierFlag());
restart = restApi.IsResetRequestReceived();
if (!restart &&
@@ -686,7 +686,7 @@ static bool WaitForExit(ServerContext& context,
context.GetLua().Execute("Finalize");
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
if (context.HasPlugins())
{
context.GetPlugins().SignalOrthancStopped();
@@ -722,7 +722,7 @@ static bool StartHttpServer(ServerContext& context,
// HTTP server
MyIncomingHttpRequestFilter httpFilter(context, plugins);
MongooseServer httpServer;
- httpServer.SetPortNumber(Configuration::GetGlobalIntegerParameter("HttpPort", 8042));
+ httpServer.SetPortNumber(Configuration::GetGlobalUnsignedIntegerParameter("HttpPort", 8042));
httpServer.SetRemoteAccessAllowed(Configuration::GetGlobalBoolParameter("RemoteAccessAllowed", false));
httpServer.SetKeepAliveEnabled(Configuration::GetGlobalBoolParameter("KeepAlive", false));
httpServer.SetHttpCompressionEnabled(Configuration::GetGlobalBoolParameter("HttpCompressionEnabled", true));
@@ -784,8 +784,10 @@ static bool StartDicomServer(ServerContext& context,
dicomServer.SetStoreRequestHandlerFactory(serverFactory);
dicomServer.SetMoveRequestHandlerFactory(serverFactory);
dicomServer.SetFindRequestHandlerFactory(serverFactory);
+ dicomServer.SetAssociationTimeout(Configuration::GetGlobalUnsignedIntegerParameter("DicomScpTimeout", 30));
-#if ORTHANC_PLUGINS_ENABLED == 1
+
+#if ORTHANC_ENABLE_PLUGINS == 1
if (plugins != NULL)
{
if (plugins->HasWorklistHandler())
@@ -805,7 +807,7 @@ static bool StartDicomServer(ServerContext& context,
}
#endif
- dicomServer.SetPortNumber(Configuration::GetGlobalIntegerParameter("DicomPort", 4242));
+ dicomServer.SetPortNumber(Configuration::GetGlobalUnsignedIntegerParameter("DicomPort", 4242));
dicomServer.SetApplicationEntityTitle(Configuration::GetGlobalStringParameter("DicomAet", "ORTHANC"));
dicomServer.SetApplicationEntityFilter(dicomFilter);
@@ -849,7 +851,7 @@ static bool StartDicomServer(ServerContext& context,
static bool ConfigureHttpHandler(ServerContext& context,
OrthancPlugins *plugins)
{
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
// By order of priority, first apply the "plugins" layer, so that
// plugins can overwrite the built-in REST API of Orthanc
if (plugins)
@@ -912,7 +914,7 @@ static bool UpgradeDatabase(IDatabaseWrapper& database,
catch (OrthancException&)
{
LOG(ERROR) << "Unable to run the automated upgrade, please use the replication instructions: "
- << "https://orthanc.chu.ulg.ac.be/book/users/replication.html";
+ << "http://book.orthanc-server.com//users/replication.html";
throw;
}
@@ -932,18 +934,24 @@ static bool ConfigureServerContext(IDatabaseWrapper& database,
IStorageArea& storageArea,
OrthancPlugins *plugins)
{
- ServerContext context(database, storageArea);
-
+ // These configuration options must be set before creating the
+ // ServerContext, otherwise the possible Lua scripts will not be
+ // able to properly issue HTTP/HTTPS queries
HttpClient::ConfigureSsl(Configuration::GetGlobalBoolParameter("HttpsVerifyPeers", true),
- Configuration::GetGlobalStringParameter("HttpsCACertificates", ""));
- HttpClient::SetDefaultTimeout(Configuration::GetGlobalIntegerParameter("HttpTimeout", 0));
+ Configuration::InterpretStringParameterAsPath
+ (Configuration::GetGlobalStringParameter("HttpsCACertificates", "")));
+ HttpClient::SetDefaultTimeout(Configuration::GetGlobalUnsignedIntegerParameter("HttpTimeout", 0));
HttpClient::SetDefaultProxy(Configuration::GetGlobalStringParameter("HttpProxy", ""));
+
+ DicomUserConnection::SetDefaultTimeout(Configuration::GetGlobalUnsignedIntegerParameter("DicomScuTimeout", 10));
+
+ ServerContext context(database, storageArea);
context.SetCompressionEnabled(Configuration::GetGlobalBoolParameter("StorageCompression", false));
context.SetStoreMD5ForAttachments(Configuration::GetGlobalBoolParameter("StoreMD5ForAttachments", true));
try
{
- context.GetIndex().SetMaximumPatientCount(Configuration::GetGlobalIntegerParameter("MaximumPatientCount", 0));
+ context.GetIndex().SetMaximumPatientCount(Configuration::GetGlobalUnsignedIntegerParameter("MaximumPatientCount", 0));
}
catch (...)
{
@@ -952,7 +960,7 @@ static bool ConfigureServerContext(IDatabaseWrapper& database,
try
{
- uint64_t size = Configuration::GetGlobalIntegerParameter("MaximumStorageSize", 0);
+ uint64_t size = Configuration::GetGlobalUnsignedIntegerParameter("MaximumStorageSize", 0);
context.GetIndex().SetMaximumStorageSize(size * 1024 * 1024);
}
catch (...)
@@ -962,7 +970,7 @@ static bool ConfigureServerContext(IDatabaseWrapper& database,
LoadLuaScripts(context);
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
if (plugins)
{
plugins->SetServerContext(context);
@@ -984,7 +992,7 @@ static bool ConfigureServerContext(IDatabaseWrapper& database,
context.Stop();
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
if (plugins)
{
plugins->ResetServerContext();
@@ -1028,7 +1036,7 @@ static bool ConfigurePlugins(int argc,
std::auto_ptr<IDatabaseWrapper> databasePtr;
std::auto_ptr<IStorageArea> storage;
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
OrthancPlugins plugins;
plugins.SetCommandLineArguments(argc, argv);
LoadPlugins(plugins);
@@ -1060,7 +1068,7 @@ static bool ConfigurePlugins(int argc,
return ConfigureDatabase(*database, *storage, &plugins, allowDatabaseUpgrade);
-#elif ORTHANC_PLUGINS_ENABLED == 0
+#elif ORTHANC_ENABLE_PLUGINS == 0
// The plugins are disabled
databasePtr.reset(Configuration::CreateDatabaseWrapper());
storage.reset(Configuration::CreateStorageArea());
@@ -1068,7 +1076,7 @@ static bool ConfigurePlugins(int argc,
return ConfigureDatabase(*databasePtr, *storage, NULL, allowDatabaseUpgrade);
#else
-# error The macro ORTHANC_PLUGINS_ENABLED must be set to 0 or 1
+# error The macro ORTHANC_ENABLE_PLUGINS must be set to 0 or 1
#endif
}
@@ -1081,6 +1089,14 @@ static bool StartOrthanc(int argc,
}
+static bool DisplayPerformanceWarning()
+{
+ (void) DisplayPerformanceWarning; // Disable warning about unused function
+ LOG(WARNING) << "Performance warning: Non-release build, runtime debug assertions are turned on";
+ return true;
+}
+
+
int main(int argc, char* argv[])
{
Logging::Initialize();
@@ -1188,7 +1204,7 @@ int main(int argc, char* argv[])
#endif
std::string target = argument.substr(9);
- Toolbox::WriteFile(configurationSample, target);
+ SystemToolbox::WriteFile(configurationSample, target);
return 0;
}
else
@@ -1209,7 +1225,7 @@ int main(int argc, char* argv[])
{
try
{
- boost::filesystem::path exe(Toolbox::GetPathToExecutable());
+ boost::filesystem::path exe(SystemToolbox::GetPathToExecutable());
std::time_t creation = boost::filesystem::last_write_time(exe);
boost::posix_time::ptime converted(boost::posix_time::from_time_t(creation));
version += " (" + boost::posix_time::to_iso_string(converted) + ")";
@@ -1220,6 +1236,7 @@ int main(int argc, char* argv[])
}
LOG(WARNING) << "Orthanc version: " << version;
+ assert(DisplayPerformanceWarning());
}
int status = 0;
diff --git a/Plugins/Engine/IPluginServiceProvider.h b/Plugins/Engine/IPluginServiceProvider.h
index e6fde58..3656f22 100644
--- a/Plugins/Engine/IPluginServiceProvider.h
+++ b/Plugins/Engine/IPluginServiceProvider.h
@@ -32,7 +32,7 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
#include "../Include/orthanc/OrthancCPlugin.h"
diff --git a/Plugins/Engine/OrthancPluginDatabase.cpp b/Plugins/Engine/OrthancPluginDatabase.cpp
index f10ab99..03b3280 100644
--- a/Plugins/Engine/OrthancPluginDatabase.cpp
+++ b/Plugins/Engine/OrthancPluginDatabase.cpp
@@ -33,7 +33,7 @@
#include "../../OrthancServer/PrecompiledHeadersServer.h"
#include "OrthancPluginDatabase.h"
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
#error The plugin support is disabled
#endif
diff --git a/Plugins/Engine/OrthancPluginDatabase.h b/Plugins/Engine/OrthancPluginDatabase.h
index 3d77948..5788eeb 100644
--- a/Plugins/Engine/OrthancPluginDatabase.h
+++ b/Plugins/Engine/OrthancPluginDatabase.h
@@ -32,7 +32,7 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
#include "../../OrthancServer/IDatabaseWrapper.h"
#include "../Include/orthanc/OrthancCDatabasePlugin.h"
diff --git a/Plugins/Engine/OrthancPlugins.cpp b/Plugins/Engine/OrthancPlugins.cpp
index a492bbf..53a5780 100644
--- a/Plugins/Engine/OrthancPlugins.cpp
+++ b/Plugins/Engine/OrthancPlugins.cpp
@@ -33,7 +33,7 @@
#include "../../OrthancServer/PrecompiledHeadersServer.h"
#include "OrthancPlugins.h"
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
#error The plugin support is disabled
#endif
@@ -563,8 +563,8 @@ namespace Orthanc
case _OrthancPluginService_GetFindQueryTagName:
{
- const DicomTag& tag = currentQuery_->GetElement(operation.index).GetTag();
- *operation.resultString = CopyString(FromDcmtkBridge::GetName(tag));
+ const DicomElement& element = currentQuery_->GetElement(operation.index);
+ *operation.resultString = CopyString(FromDcmtkBridge::GetTagName(element));
break;
}
@@ -687,10 +687,10 @@ namespace Orthanc
virtual IMoveRequestIterator* Handle(const std::string& targetAet,
const DicomMap& input,
- const std::string& remoteIp,
- const std::string& remoteAet,
+ const std::string& originatorIp,
+ const std::string& originatorAet,
const std::string& calledAet,
- uint16_t messageId)
+ uint16_t originatorId)
{
std::string levelString = ReadTag(input, DICOM_TAG_QUERY_RETRIEVE_LEVEL);
std::string patientId = ReadTag(input, DICOM_TAG_PATIENT_ID);
@@ -712,10 +712,10 @@ namespace Orthanc
studyInstanceUid.empty() ? NULL : studyInstanceUid.c_str(),
seriesInstanceUid.empty() ? NULL : seriesInstanceUid.c_str(),
sopInstanceUid.empty() ? NULL : sopInstanceUid.c_str(),
- remoteAet.c_str(),
+ originatorAet.c_str(),
calledAet.c_str(),
targetAet.c_str(),
- messageId);
+ originatorId);
if (driver == NULL)
{
@@ -940,7 +940,7 @@ namespace Orthanc
}
else
{
- GetErrorDictionary().LogError(error, true);
+ GetErrorDictionary().LogError(error, false);
throw OrthancException(static_cast<ErrorCode>(error));
}
}
@@ -1278,7 +1278,7 @@ namespace Orthanc
{
PImpl::ServerContextLock lock(*pimpl_);
- lock.GetContext().ReadFile(dicom, p.instanceId, FileContentType_Dicom);
+ lock.GetContext().ReadDicom(dicom, p.instanceId);
}
CopyToMemoryBuffer(*p.target, dicom);
@@ -1563,7 +1563,7 @@ namespace Orthanc
else
{
Json::Value simplified;
- Toolbox::SimplifyTags(simplified, instance.GetJson(), DicomToJsonFormat_Human);
+ ServerToolbox::SimplifyTags(simplified, instance.GetJson(), DicomToJsonFormat_Human);
s = writer.write(simplified);
}
@@ -1646,7 +1646,7 @@ namespace Orthanc
if (image->IsReadOnly())
{
- std::auto_ptr<Image> copy(new Image(image->GetFormat(), image->GetWidth(), image->GetHeight()));
+ std::auto_ptr<Image> copy(new Image(image->GetFormat(), image->GetWidth(), image->GetHeight(), false));
ImageProcessing::Copy(*copy, *image);
image.reset(NULL);
return reinterpret_cast<OrthancPluginImage*>(copy.release());
@@ -1885,7 +1885,7 @@ namespace Orthanc
const _OrthancPluginConvertPixelFormat& p = *reinterpret_cast<const _OrthancPluginConvertPixelFormat*>(parameters);
const ImageAccessor& source = *reinterpret_cast<const ImageAccessor*>(p.source);
- std::auto_ptr<ImageAccessor> target(new Image(Plugins::Convert(p.targetFormat), source.GetWidth(), source.GetHeight()));
+ std::auto_ptr<ImageAccessor> target(new Image(Plugins::Convert(p.targetFormat), source.GetWidth(), source.GetHeight(), false));
ImageProcessing::Convert(*target, source);
*(p.target) = ReturnImage(target);
@@ -1948,15 +1948,15 @@ namespace Orthanc
{
PImpl::ServerContextLock lock(*pimpl_);
- lock.GetContext().ReadFile(content, p.instanceId, FileContentType_Dicom);
+ lock.GetContext().ReadDicom(content, p.instanceId);
}
dicom.reset(new ParsedDicomFile(content));
}
Json::Value json;
- dicom->ToJson(json, Plugins::Convert(p.format),
- static_cast<DicomToJsonFlags>(p.flags), p.maxStringLength);
+ dicom->DatasetToJson(json, Plugins::Convert(p.format),
+ static_cast<DicomToJsonFlags>(p.flags), p.maxStringLength);
Json::FastWriter writer;
*p.result = CopyString(writer.write(json));
@@ -2038,7 +2038,7 @@ namespace Orthanc
switch (service)
{
case _OrthancPluginService_CreateImage:
- result.reset(new Image(Plugins::Convert(p.format), p.width, p.height));
+ result.reset(new Image(Plugins::Convert(p.format), p.width, p.height, false));
break;
case _OrthancPluginService_CreateImageAccessor:
@@ -2172,14 +2172,14 @@ namespace Orthanc
{
case _OrthancPluginService_GetOrthancPath:
{
- std::string s = Toolbox::GetPathToExecutable();
+ std::string s = SystemToolbox::GetPathToExecutable();
*reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = CopyString(s);
return true;
}
case _OrthancPluginService_GetOrthancDirectory:
{
- std::string s = Toolbox::GetDirectoryOfExecutable();
+ std::string s = SystemToolbox::GetDirectoryOfExecutable();
*reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result = CopyString(s);
return true;
}
@@ -2366,7 +2366,7 @@ namespace Orthanc
*reinterpret_cast<const _OrthancPluginReadFile*>(parameters);
std::string content;
- Toolbox::ReadFile(content, p.path);
+ SystemToolbox::ReadFile(content, p.path);
CopyToMemoryBuffer(*p.target, content.size() > 0 ? content.c_str() : NULL, content.size());
return true;
@@ -2376,7 +2376,7 @@ namespace Orthanc
{
const _OrthancPluginWriteFile& p =
*reinterpret_cast<const _OrthancPluginWriteFile*>(parameters);
- Toolbox::WriteFile(p.data, p.size, p.path);
+ SystemToolbox::WriteFile(p.data, p.size, p.path);
return true;
}
@@ -2588,10 +2588,53 @@ namespace Orthanc
case _OrthancPluginService_GenerateUuid:
{
*reinterpret_cast<const _OrthancPluginRetrieveDynamicString*>(parameters)->result =
- CopyString(Toolbox::GenerateUuid());
+ CopyString(SystemToolbox::GenerateUuid());
+ return true;
+ }
+
+ case _OrthancPluginService_CreateFindMatcher:
+ {
+ const _OrthancPluginCreateFindMatcher& p =
+ *reinterpret_cast<const _OrthancPluginCreateFindMatcher*>(parameters);
+ ParsedDicomFile query(p.query, p.size);
+ *(p.target) = reinterpret_cast<OrthancPluginFindMatcher*>
+ (new HierarchicalMatcher(query, Configuration::GetGlobalBoolParameter("CaseSensitivePN", false)));
return true;
}
+ case _OrthancPluginService_FreeFindMatcher:
+ {
+ const _OrthancPluginFreeFindMatcher& p =
+ *reinterpret_cast<const _OrthancPluginFreeFindMatcher*>(parameters);
+
+ if (p.matcher == NULL)
+ {
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+ else
+ {
+ delete reinterpret_cast<HierarchicalMatcher*>(p.matcher);
+ return true;
+ }
+ }
+
+ case _OrthancPluginService_FindMatcherIsMatch:
+ {
+ const _OrthancPluginFindMatcherIsMatch& p =
+ *reinterpret_cast<const _OrthancPluginFindMatcherIsMatch*>(parameters);
+
+ if (p.matcher == NULL)
+ {
+ throw OrthancException(ErrorCode_ParameterOutOfRange);
+ }
+ else
+ {
+ ParsedDicomFile query(p.dicom, p.size);
+ *p.isMatch = reinterpret_cast<const HierarchicalMatcher*>(p.matcher)->Match(query) ? 1 : 0;
+ return true;
+ }
+ }
+
default:
return false;
}
@@ -2758,7 +2801,17 @@ namespace Orthanc
*reinterpret_cast<const _OrthancPluginRegisterDictionaryTag*>(parameters);
FromDcmtkBridge::RegisterDictionaryTag(DicomTag(p.group, p.element),
Plugins::Convert(p.vr), p.name,
- p.minMultiplicity, p.maxMultiplicity);
+ p.minMultiplicity, p.maxMultiplicity, "");
+ return true;
+ }
+
+ case _OrthancPluginService_RegisterPrivateDictionaryTag:
+ {
+ const _OrthancPluginRegisterPrivateDictionaryTag& p =
+ *reinterpret_cast<const _OrthancPluginRegisterPrivateDictionaryTag*>(parameters);
+ FromDcmtkBridge::RegisterDictionaryTag(DicomTag(p.group, p.element),
+ Plugins::Convert(p.vr), p.name,
+ p.minMultiplicity, p.maxMultiplicity, p.privateCreator);
return true;
}
@@ -2774,7 +2827,7 @@ namespace Orthanc
}
IStorageArea& storage = *reinterpret_cast<IStorageArea*>(p.storageArea);
- Toolbox::ReconstructMainDicomTags(*pimpl_->database_, storage, Plugins::Convert(p.level));
+ ServerToolbox::ReconstructMainDicomTags(*pimpl_->database_, storage, Plugins::Convert(p.level));
return true;
}
diff --git a/Plugins/Engine/OrthancPlugins.h b/Plugins/Engine/OrthancPlugins.h
index e191c04..d8cd8a5 100644
--- a/Plugins/Engine/OrthancPlugins.h
+++ b/Plugins/Engine/OrthancPlugins.h
@@ -34,7 +34,12 @@
#include "PluginsErrorDictionary.h"
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if !defined(ORTHANC_ENABLE_PLUGINS)
+# error The macro ORTHANC_ENABLE_PLUGINS must be defined
+#endif
+
+
+#if ORTHANC_ENABLE_PLUGINS != 1
#include <boost/noncopyable.hpp>
diff --git a/Plugins/Engine/PluginsEnumerations.cpp b/Plugins/Engine/PluginsEnumerations.cpp
index 2d2a47c..9814b4e 100644
--- a/Plugins/Engine/PluginsEnumerations.cpp
+++ b/Plugins/Engine/PluginsEnumerations.cpp
@@ -33,7 +33,7 @@
#include "../../OrthancServer/PrecompiledHeadersServer.h"
#include "PluginsEnumerations.h"
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
#error The plugin support is disabled
#endif
diff --git a/Plugins/Engine/PluginsEnumerations.h b/Plugins/Engine/PluginsEnumerations.h
index bb42773..1540232 100644
--- a/Plugins/Engine/PluginsEnumerations.h
+++ b/Plugins/Engine/PluginsEnumerations.h
@@ -32,7 +32,7 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
#include "../Include/orthanc/OrthancCPlugin.h"
#include "../../OrthancServer/ServerEnumerations.h"
diff --git a/Plugins/Engine/PluginsErrorDictionary.cpp b/Plugins/Engine/PluginsErrorDictionary.cpp
index aba9a86..c64c5f8 100644
--- a/Plugins/Engine/PluginsErrorDictionary.cpp
+++ b/Plugins/Engine/PluginsErrorDictionary.cpp
@@ -33,7 +33,7 @@
#include "../../OrthancServer/PrecompiledHeadersServer.h"
#include "PluginsErrorDictionary.h"
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
#error The plugin support is disabled
#endif
diff --git a/Plugins/Engine/PluginsErrorDictionary.h b/Plugins/Engine/PluginsErrorDictionary.h
index 018156d..5e5214d 100644
--- a/Plugins/Engine/PluginsErrorDictionary.h
+++ b/Plugins/Engine/PluginsErrorDictionary.h
@@ -32,7 +32,7 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
#include "../Include/orthanc/OrthancCPlugin.h"
#include "../../Core/OrthancException.h"
diff --git a/Plugins/Engine/PluginsManager.cpp b/Plugins/Engine/PluginsManager.cpp
index 7a8659e..a3becba 100644
--- a/Plugins/Engine/PluginsManager.cpp
+++ b/Plugins/Engine/PluginsManager.cpp
@@ -33,7 +33,7 @@
#include "../../OrthancServer/PrecompiledHeadersServer.h"
#include "PluginsManager.h"
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
#error The plugin support is disabled
#endif
diff --git a/Plugins/Engine/PluginsManager.h b/Plugins/Engine/PluginsManager.h
index de9f45f..f04bff9 100644
--- a/Plugins/Engine/PluginsManager.h
+++ b/Plugins/Engine/PluginsManager.h
@@ -32,7 +32,7 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
#include "SharedLibrary.h"
#include "IPluginServiceProvider.h"
diff --git a/Plugins/Engine/SharedLibrary.cpp b/Plugins/Engine/SharedLibrary.cpp
index 7fefc49..1adc878 100644
--- a/Plugins/Engine/SharedLibrary.cpp
+++ b/Plugins/Engine/SharedLibrary.cpp
@@ -33,7 +33,7 @@
#include "../../OrthancServer/PrecompiledHeadersServer.h"
#include "SharedLibrary.h"
-#if ORTHANC_PLUGINS_ENABLED != 1
+#if ORTHANC_ENABLE_PLUGINS != 1
#error The plugin support is disabled
#endif
diff --git a/Plugins/Engine/SharedLibrary.h b/Plugins/Engine/SharedLibrary.h
index 5a7913a..330966c 100644
--- a/Plugins/Engine/SharedLibrary.h
+++ b/Plugins/Engine/SharedLibrary.h
@@ -32,7 +32,7 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
#include "../../Core/OrthancException.h"
@@ -60,7 +60,7 @@ namespace Orthanc
FunctionPointer GetFunctionInternal(const std::string& name);
public:
- SharedLibrary(const std::string& path);
+ explicit SharedLibrary(const std::string& path);
~SharedLibrary();
diff --git a/Plugins/Include/orthanc/OrthancCPlugin.h b/Plugins/Include/orthanc/OrthancCPlugin.h
index cb653d9..b9aa629 100644
--- a/Plugins/Include/orthanc/OrthancCPlugin.h
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h
@@ -116,7 +116,7 @@
#endif
#define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER 1
-#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER 1
+#define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER 2
#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER 0
@@ -191,7 +191,7 @@ extern "C"
OrthancPluginErrorCode_Plugin = 1 /*!< Error encountered within the plugin engine */,
OrthancPluginErrorCode_NotImplemented = 2 /*!< Not implemented yet */,
OrthancPluginErrorCode_ParameterOutOfRange = 3 /*!< Parameter out of range */,
- OrthancPluginErrorCode_NotEnoughMemory = 4 /*!< Not enough memory */,
+ OrthancPluginErrorCode_NotEnoughMemory = 4 /*!< The server hosting Orthanc is running out of memory */,
OrthancPluginErrorCode_BadParameterType = 5 /*!< Bad type for a parameter */,
OrthancPluginErrorCode_BadSequenceOfCalls = 6 /*!< Bad sequence of calls */,
OrthancPluginErrorCode_InexistentItem = 7 /*!< Accessing an inexistent item */,
@@ -222,6 +222,7 @@ extern "C"
OrthancPluginErrorCode_StorageAreaPlugin = 32 /*!< Error in the plugin implementing a custom storage area */,
OrthancPluginErrorCode_EmptyRequest = 33 /*!< The request is empty */,
OrthancPluginErrorCode_NotAcceptable = 34 /*!< Cannot send a response which is acceptable according to the Accept HTTP header */,
+ OrthancPluginErrorCode_NullPointer = 35 /*!< Cannot handle a NULL pointer */,
OrthancPluginErrorCode_SQLiteNotOpened = 1000 /*!< SQLite: The database is not opened */,
OrthancPluginErrorCode_SQLiteAlreadyOpened = 1001 /*!< SQLite: Connection is already open */,
OrthancPluginErrorCode_SQLiteCannotOpen = 1002 /*!< SQLite: Unable to open the database */,
@@ -407,6 +408,7 @@ extern "C"
_OrthancPluginService_LookupDictionary = 26,
_OrthancPluginService_CallHttpClient2 = 27,
_OrthancPluginService_GenerateUuid = 28,
+ _OrthancPluginService_RegisterPrivateDictionaryTag = 29,
/* Registration of callbacks */
_OrthancPluginService_RegisterRestCallback = 1000,
@@ -499,6 +501,9 @@ extern "C"
_OrthancPluginService_GetFindQueryTag = 7007,
_OrthancPluginService_GetFindQueryTagName = 7008,
_OrthancPluginService_GetFindQueryValue = 7009,
+ _OrthancPluginService_CreateFindMatcher = 7010,
+ _OrthancPluginService_FreeFindMatcher = 7011,
+ _OrthancPluginService_FindMatcherIsMatch = 7012,
_OrthancPluginService_INTERNAL = 0x7fffffff
} _OrthancPluginService;
@@ -712,6 +717,7 @@ extern "C"
**/
typedef enum
{
+ OrthancPluginDicomToJsonFlags_None = 0,
OrthancPluginDicomToJsonFlags_IncludeBinary = (1 << 0), /*!< Include the binary tags */
OrthancPluginDicomToJsonFlags_IncludePrivateTags = (1 << 1), /*!< Include the private tags */
OrthancPluginDicomToJsonFlags_IncludeUnknownTags = (1 << 2), /*!< Include the tags unknown by the dictionary */
@@ -730,6 +736,7 @@ extern "C"
**/
typedef enum
{
+ OrthancPluginCreateDicomFlags_None = 0,
OrthancPluginCreateDicomFlags_DecodeDataUriScheme = (1 << 0), /*!< Decode fields encoded using data URI scheme */
OrthancPluginCreateDicomFlags_GenerateIdentifiers = (1 << 1), /*!< Automatically generate DICOM identifiers */
@@ -854,6 +861,14 @@ extern "C"
/**
+ * @brief Opaque structure to an object that can be used to check whether a DICOM instance matches a C-Find query.
+ * @ingroup Toolbox
+ **/
+ typedef struct _OrthancPluginFindAnswers_t OrthancPluginFindMatcher;
+
+
+
+ /**
* @brief Signature of a callback function that answers to a REST request.
* @ingroup Callbacks
**/
@@ -1044,18 +1059,20 @@ extern "C"
* @param resourceType The type of the resource of interest. Note
* that this might be set to ResourceType_None if the
* QueryRetrieveLevel (0008,0052) tag was not provided by the
- * issuer.
+ * issuer (i.e. the originator modality).
* @param patientId Content of the PatientID (0x0010, 0x0020) tag of the resource of interest. Might be NULL.
* @param accessionNumber Content of the AccessionNumber (0x0008, 0x0050) tag. Might be NULL.
* @param studyInstanceUid Content of the StudyInstanceUID (0x0020, 0x000d) tag. Might be NULL.
* @param seriesInstanceUid Content of the SeriesInstanceUID (0x0020, 0x000e) tag. Might be NULL.
* @param sopInstanceUid Content of the SOPInstanceUID (0x0008, 0x0018) tag. Might be NULL.
- * @param issuerAet The Application Entity Title (AET) of the
+ * @param originatorAet The Application Entity Title (AET) of the
* modality from which the request originates.
* @param sourceAet The Application Entity Title (AET) of the
* modality that should send its DICOM files to another modality.
* @param targetAet The Application Entity Title (AET) of the
* modality that should receive the DICOM files.
+ * @param originatorId The Message ID issued by the originator modality,
+ * as found in tag (0000,0110) of the DICOM query emitted by the issuer.
*
* @return The NULL value if the plugin cannot deal with this query,
* or a pointer to the driver object that is responsible for
@@ -1071,10 +1088,10 @@ extern "C"
const char* studyInstanceUid,
const char* seriesInstanceUid,
const char* sopInstanceUid,
- const char* issuerAet,
+ const char* originatorAet,
const char* sourceAet,
const char* targetAet,
- uint16_t moveOriginatorId);
+ uint16_t originatorId);
/**
@@ -4091,9 +4108,9 @@ extern "C"
/**
* @brief Register a new tag into the DICOM dictionary.
*
- * This function declares a new tag in the dictionary of DICOM tags
- * that are known to Orthanc. This function should be used in the
- * OrthancPluginInitialize() callback.
+ * This function declares a new public tag in the dictionary of
+ * DICOM tags that are known to Orthanc. This function should be
+ * used in the OrthancPluginInitialize() callback.
*
* @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
* @param group The group of the tag.
@@ -4104,6 +4121,7 @@ extern "C"
* @param maxMultiplicity The maximum multiplicity of the tag. A value of 0 means
* an arbitrary multiplicity ("<tt>n</tt>").
* @return 0 if success, other value if error.
+ * @see OrthancPluginRegisterPrivateDictionaryTag()
* @ingroup Toolbox
**/
ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterDictionaryTag(
@@ -4128,6 +4146,60 @@ extern "C"
+ typedef struct
+ {
+ uint16_t group;
+ uint16_t element;
+ OrthancPluginValueRepresentation vr;
+ const char* name;
+ uint32_t minMultiplicity;
+ uint32_t maxMultiplicity;
+ const char* privateCreator;
+ } _OrthancPluginRegisterPrivateDictionaryTag;
+
+ /**
+ * @brief Register a new private tag into the DICOM dictionary.
+ *
+ * This function declares a new private tag in the dictionary of
+ * DICOM tags that are known to Orthanc. This function should be
+ * used in the OrthancPluginInitialize() callback.
+ *
+ * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+ * @param group The group of the tag.
+ * @param element The element of the tag.
+ * @param vr The value representation of the tag.
+ * @param name The nickname of the tag.
+ * @param minMultiplicity The minimum multiplicity of the tag (must be above 0).
+ * @param maxMultiplicity The maximum multiplicity of the tag. A value of 0 means
+ * an arbitrary multiplicity ("<tt>n</tt>").
+ * @param privateCreator The private creator of this private tag.
+ * @return 0 if success, other value if error.
+ * @see OrthancPluginRegisterDictionaryTag()
+ * @ingroup Toolbox
+ **/
+ ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginRegisterPrivateDictionaryTag(
+ OrthancPluginContext* context,
+ uint16_t group,
+ uint16_t element,
+ OrthancPluginValueRepresentation vr,
+ const char* name,
+ uint32_t minMultiplicity,
+ uint32_t maxMultiplicity,
+ const char* privateCreator)
+ {
+ _OrthancPluginRegisterPrivateDictionaryTag params;
+ params.group = group;
+ params.element = element;
+ params.vr = vr;
+ params.name = name;
+ params.minMultiplicity = minMultiplicity;
+ params.maxMultiplicity = maxMultiplicity;
+ params.privateCreator = privateCreator;
+
+ return context->InvokeService(context, _OrthancPluginService_RegisterPrivateDictionaryTag, ¶ms);
+ }
+
+
typedef struct
{
@@ -5355,6 +5427,123 @@ extern "C"
+ typedef struct
+ {
+ OrthancPluginFindMatcher** target;
+ const void* query;
+ uint32_t size;
+ } _OrthancPluginCreateFindMatcher;
+
+
+ /**
+ * @brief Create a C-Find matcher.
+ *
+ * This function creates a "matcher" object that can be used to
+ * check whether a DICOM instance matches a C-Find query. The C-Find
+ * query must be expressed as a DICOM buffer.
+ *
+ * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+ * @param query The C-Find DICOM query.
+ * @param size The size of the DICOM query.
+ * @return The newly allocated matcher. It must be freed with OrthancPluginFreeFindMatcher().
+ * @ingroup Toolbox
+ **/
+ ORTHANC_PLUGIN_INLINE OrthancPluginFindMatcher* OrthancPluginCreateFindMatcher(
+ OrthancPluginContext* context,
+ const void* query,
+ uint32_t size)
+ {
+ OrthancPluginFindMatcher* target = NULL;
+
+ _OrthancPluginCreateFindMatcher params;
+ memset(¶ms, 0, sizeof(params));
+ params.target = ⌖
+ params.query = query;
+ params.size = size;
+
+ if (context->InvokeService(context, _OrthancPluginService_CreateFindMatcher, ¶ms) != OrthancPluginErrorCode_Success)
+ {
+ return NULL;
+ }
+ else
+ {
+ return target;
+ }
+ }
+
+
+ typedef struct
+ {
+ OrthancPluginFindMatcher* matcher;
+ } _OrthancPluginFreeFindMatcher;
+
+ /**
+ * @brief Free a C-Find matcher.
+ *
+ * This function frees a matcher that was created using OrthancPluginCreateFindMatcher().
+ *
+ * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+ * @param matcher The matcher of interest.
+ * @ingroup Toolbox
+ **/
+ ORTHANC_PLUGIN_INLINE void OrthancPluginFreeFindMatcher(
+ OrthancPluginContext* context,
+ OrthancPluginFindMatcher* matcher)
+ {
+ _OrthancPluginFreeFindMatcher params;
+ params.matcher = matcher;
+
+ context->InvokeService(context, _OrthancPluginService_FreeFindMatcher, ¶ms);
+ }
+
+
+ typedef struct
+ {
+ const OrthancPluginFindMatcher* matcher;
+ const void* dicom;
+ uint32_t size;
+ int32_t* isMatch;
+ } _OrthancPluginFindMatcherIsMatch;
+
+ /**
+ * @brief Test whether a DICOM instance matches a C-Find query.
+ *
+ * This function checks whether one DICOM instance matches C-Find
+ * matcher that was previously allocated using
+ * OrthancPluginCreateFindMatcher().
+ *
+ * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+ * @param matcher The matcher of interest.
+ * @param dicom The DICOM instance to be matched.
+ * @param size The size of the DICOM instance.
+ * @return 1 if the DICOM instance matches the query, 0 otherwise.
+ * @ingroup Toolbox
+ **/
+ ORTHANC_PLUGIN_INLINE int32_t OrthancPluginFindMatcherIsMatch(
+ OrthancPluginContext* context,
+ const OrthancPluginFindMatcher* matcher,
+ const void* dicom,
+ uint32_t size)
+ {
+ int32_t isMatch = 0;
+
+ _OrthancPluginFindMatcherIsMatch params;
+ params.matcher = matcher;
+ params.dicom = dicom;
+ params.size = size;
+ params.isMatch = &isMatch;
+
+ if (context->InvokeService(context, _OrthancPluginService_FindMatcherIsMatch, ¶ms) == OrthancPluginErrorCode_Success)
+ {
+ return isMatch;
+ }
+ else
+ {
+ /* Error: Assume non-match */
+ return 0;
+ }
+ }
+
#ifdef __cplusplus
}
diff --git a/Plugins/Samples/Basic/Plugin.c b/Plugins/Samples/Basic/Plugin.c
index 36b30bb..b30e4da 100644
--- a/Plugins/Samples/Basic/Plugin.c
+++ b/Plugins/Samples/Basic/Plugin.c
@@ -28,9 +28,9 @@ static OrthancPluginContext* context = NULL;
static OrthancPluginErrorCode customError;
-ORTHANC_PLUGINS_API int32_t Callback1(OrthancPluginRestOutput* output,
- const char* url,
- const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback1(OrthancPluginRestOutput* output,
+ const char* url,
+ const OrthancPluginHttpRequest* request)
{
char buffer[1024];
uint32_t i;
@@ -57,7 +57,7 @@ ORTHANC_PLUGINS_API int32_t Callback1(OrthancPluginRestOutput* output,
OrthancPluginLogWarning(context, buffer);
}
- OrthancPluginLogWarning(context, "");
+ OrthancPluginLogWarning(context, "");
for (i = 0; i < request->headersCount; i++)
{
@@ -67,13 +67,13 @@ ORTHANC_PLUGINS_API int32_t Callback1(OrthancPluginRestOutput* output,
OrthancPluginLogWarning(context, "");
- return 1;
+ return OrthancPluginErrorCode_Success;
}
-ORTHANC_PLUGINS_API int32_t Callback2(OrthancPluginRestOutput* output,
- const char* url,
- const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback2(OrthancPluginRestOutput* output,
+ const char* url,
+ const OrthancPluginHttpRequest* request)
{
/* Answer with a sample 16bpp image. */
@@ -99,13 +99,13 @@ ORTHANC_PLUGINS_API int32_t Callback2(OrthancPluginRestOutput* output,
256, 256, sizeof(uint16_t) * 256, buffer);
}
- return 0;
+ return OrthancPluginErrorCode_Success;
}
-ORTHANC_PLUGINS_API int32_t Callback3(OrthancPluginRestOutput* output,
- const char* url,
- const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback3(OrthancPluginRestOutput* output,
+ const char* url,
+ const OrthancPluginHttpRequest* request)
{
if (request->method != OrthancPluginHttpMethod_Get)
{
@@ -124,13 +124,13 @@ ORTHANC_PLUGINS_API int32_t Callback3(OrthancPluginRestOutput* output,
}
}
- return 0;
+ return OrthancPluginErrorCode_Success;
}
-ORTHANC_PLUGINS_API int32_t Callback4(OrthancPluginRestOutput* output,
- const char* url,
- const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback4(OrthancPluginRestOutput* output,
+ const char* url,
+ const OrthancPluginHttpRequest* request)
{
/* Answer with a sample 8bpp image. */
@@ -156,13 +156,13 @@ ORTHANC_PLUGINS_API int32_t Callback4(OrthancPluginRestOutput* output,
256, 256, 256, buffer);
}
- return 0;
+ return OrthancPluginErrorCode_Success;
}
-ORTHANC_PLUGINS_API int32_t Callback5(OrthancPluginRestOutput* output,
- const char* url,
- const OrthancPluginHttpRequest* request)
+ORTHANC_PLUGINS_API OrthancPluginErrorCode Callback5(OrthancPluginRestOutput* output,
+ const char* url,
+ const OrthancPluginHttpRequest* request)
{
/**
* Demonstration the difference between the
@@ -199,13 +199,13 @@ ORTHANC_PLUGINS_API int32_t Callback5(OrthancPluginRestOutput* output,
if (error)
{
- return -1;
+ return OrthancPluginErrorCode_InternalError;
}
else
{
OrthancPluginAnswerBuffer(context, output, tmp.data, tmp.size, "application/octet-stream");
OrthancPluginFreeMemoryBuffer(context, &tmp);
- return 0;
+ return OrthancPluginErrorCode_Success;
}
}
diff --git a/Plugins/Samples/Common/DicomDatasetReader.cpp b/Plugins/Samples/Common/DicomDatasetReader.cpp
new file mode 100644
index 0000000..b354bb1
--- /dev/null
+++ b/Plugins/Samples/Common/DicomDatasetReader.cpp
@@ -0,0 +1,122 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "DicomDatasetReader.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+#include <boost/lexical_cast.hpp>
+
+namespace OrthancPlugins
+{
+ // This function is copied-pasted from "../../../Core/Toolbox.cpp",
+ // in order to avoid the dependency of plugins against the Orthanc core
+ static std::string StripSpaces(const std::string& source)
+ {
+ size_t first = 0;
+
+ while (first < source.length() &&
+ isspace(source[first]))
+ {
+ first++;
+ }
+
+ if (first == source.length())
+ {
+ // String containing only spaces
+ return "";
+ }
+
+ size_t last = source.length();
+ while (last > first &&
+ isspace(source[last - 1]))
+ {
+ last--;
+ }
+
+ assert(first <= last);
+ return source.substr(first, last - first);
+ }
+
+
+ DicomDatasetReader::DicomDatasetReader(IDicomDataset* dataset) : // takes ownership
+ dataset_(dataset)
+ {
+ if (dataset == NULL)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
+ }
+ }
+
+
+ std::string DicomDatasetReader::GetMandatoryStringValue(const DicomPath& path) const
+ {
+ std::string s;
+ if (dataset_->GetStringValue(s, path))
+ {
+ return s;
+ }
+ else
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InexistentTag);
+ }
+ }
+
+
+ int DicomDatasetReader::GetIntegerValue(const DicomPath& path)
+ {
+ try
+ {
+ std::string s = StripSpaces(GetMandatoryStringValue(path));
+ return boost::lexical_cast<int>(s);
+ }
+ catch (boost::bad_lexical_cast&)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ }
+
+
+ unsigned int DicomDatasetReader::GetUnsignedIntegerValue(const DicomPath& path)
+ {
+ int value = GetIntegerValue(path);
+
+ if (value >= 0)
+ {
+ return static_cast<unsigned int>(value);
+ }
+ else
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
+ }
+ }
+}
diff --git a/Core/DicomFormat/DicomArray.h b/Plugins/Samples/Common/DicomDatasetReader.h
similarity index 77%
copy from Core/DicomFormat/DicomArray.h
copy to Plugins/Samples/Common/DicomDatasetReader.h
index a223685..0074071 100644
--- a/Core/DicomFormat/DicomArray.h
+++ b/Plugins/Samples/Common/DicomDatasetReader.h
@@ -32,35 +32,29 @@
#pragma once
-#include "DicomElement.h"
-#include "DicomMap.h"
+#include "IDicomDataset.h"
-#include <vector>
+#include <memory>
-namespace Orthanc
+namespace OrthancPlugins
{
- class DicomArray : public boost::noncopyable
+ class DicomDatasetReader : public boost::noncopyable
{
private:
- typedef std::vector<DicomElement*> Elements;
-
- Elements elements_;
+ std::auto_ptr<IDicomDataset> dataset_;
public:
- DicomArray(const DicomMap& map);
-
- ~DicomArray();
+ DicomDatasetReader(IDicomDataset* dataset); // takes ownership
- size_t GetSize() const
+ IDicomDataset& GetDataset() const
{
- return elements_.size();
+ return *dataset_;
}
- const DicomElement& GetElement(size_t i) const
- {
- return *elements_[i];
- }
+ std::string GetMandatoryStringValue(const DicomPath& path) const;
+
+ int GetIntegerValue(const DicomPath& path);
- void Print(FILE* fp) const;
+ unsigned int GetUnsignedIntegerValue(const DicomPath& path);
};
}
diff --git a/Core/DicomFormat/DicomValue.cpp b/Plugins/Samples/Common/DicomPath.cpp
similarity index 57%
copy from Core/DicomFormat/DicomValue.cpp
copy to Plugins/Samples/Common/DicomPath.cpp
index 32a17b5..3437e60 100644
--- a/Core/DicomFormat/DicomValue.cpp
+++ b/Plugins/Samples/Common/DicomPath.cpp
@@ -30,64 +30,57 @@
**/
-#include "../PrecompiledHeaders.h"
-#include "DicomValue.h"
+#include "DicomPath.h"
-#include "../OrthancException.h"
-#include "../Toolbox.h"
+#include "OrthancPluginCppWrapper.h"
-namespace Orthanc
+namespace OrthancPlugins
{
- DicomValue::DicomValue(const DicomValue& other) :
- type_(other.type_),
- content_(other.content_)
+ const DicomPath::Prefix& DicomPath::GetPrefixItem(size_t depth) const
{
- }
-
-
- DicomValue::DicomValue(const std::string& content,
- bool isBinary) :
- type_(isBinary ? Type_Binary : Type_String),
- content_(content)
- {
- }
-
-
- DicomValue::DicomValue(const char* data,
- size_t size,
- bool isBinary) :
- type_(isBinary ? Type_Binary : Type_String)
- {
- content_.assign(data, size);
- }
-
-
- const std::string& DicomValue::GetContent() const
- {
- if (type_ == Type_Null)
+ if (depth >= prefix_.size())
{
- throw OrthancException(ErrorCode_BadParameterType);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
else
{
- return content_;
+ return prefix_[depth];
}
}
- DicomValue* DicomValue::Clone() const
+ DicomPath::DicomPath(const DicomTag& sequence,
+ size_t index,
+ const DicomTag& tag) :
+ finalTag_(tag)
{
- return new DicomValue(*this);
+ AddToPrefix(sequence, index);
}
-
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
- void DicomValue::FormatDataUriScheme(std::string& target,
- const std::string& mime) const
+
+ DicomPath::DicomPath(const DicomTag& sequence1,
+ size_t index1,
+ const DicomTag& sequence2,
+ size_t index2,
+ const DicomTag& tag) :
+ finalTag_(tag)
{
- Toolbox::EncodeBase64(target, GetContent());
- target.insert(0, "data:" + mime + ";base64,");
+ AddToPrefix(sequence1, index1);
+ AddToPrefix(sequence2, index2);
}
-#endif
+
+ DicomPath::DicomPath(const DicomTag& sequence1,
+ size_t index1,
+ const DicomTag& sequence2,
+ size_t index2,
+ const DicomTag& sequence3,
+ size_t index3,
+ const DicomTag& tag) :
+ finalTag_(tag)
+ {
+ AddToPrefix(sequence1, index1);
+ AddToPrefix(sequence2, index2);
+ AddToPrefix(sequence3, index3);
+ }
}
diff --git a/Core/Images/ImageBuffer.h b/Plugins/Samples/Common/DicomPath.h
similarity index 56%
copy from Core/Images/ImageBuffer.h
copy to Plugins/Samples/Common/DicomPath.h
index 381269e..f14f051 100644
--- a/Core/Images/ImageBuffer.h
+++ b/Plugins/Samples/Common/DicomPath.h
@@ -32,84 +32,76 @@
#pragma once
-#include "ImageAccessor.h"
+#include "DicomTag.h"
#include <vector>
-#include <stdint.h>
-#include <boost/noncopyable.hpp>
+#include <stddef.h>
-namespace Orthanc
+namespace OrthancPlugins
{
- class ImageBuffer : public boost::noncopyable
+ class DicomPath
{
private:
- bool changed_;
+ typedef std::pair<DicomTag, size_t> Prefix;
- bool forceMinimalPitch_; // Currently unused
- PixelFormat format_;
- unsigned int width_;
- unsigned int height_;
- unsigned int pitch_;
- void *buffer_;
+ std::vector<Prefix> prefix_;
+ DicomTag finalTag_;
- void Initialize();
-
- void Allocate();
-
- void Deallocate();
+ const Prefix& GetPrefixItem(size_t depth) const;
public:
- ImageBuffer(PixelFormat format,
- unsigned int width,
- unsigned int height);
-
- ImageBuffer()
+ DicomPath(const DicomTag& finalTag) :
+ finalTag_(finalTag)
{
- Initialize();
}
- ~ImageBuffer()
+ DicomPath(const DicomTag& sequence,
+ size_t index,
+ const DicomTag& tag);
+
+ DicomPath(const DicomTag& sequence1,
+ size_t index1,
+ const DicomTag& sequence2,
+ size_t index2,
+ const DicomTag& tag);
+
+ DicomPath(const DicomTag& sequence1,
+ size_t index1,
+ const DicomTag& sequence2,
+ size_t index2,
+ const DicomTag& sequence3,
+ size_t index3,
+ const DicomTag& tag);
+
+ void AddToPrefix(const DicomTag& tag,
+ size_t position)
{
- Deallocate();
+ prefix_.push_back(std::make_pair(tag, position));
}
- PixelFormat GetFormat() const
+ size_t GetPrefixLength() const
{
- return format_;
+ return prefix_.size();
}
-
- void SetFormat(PixelFormat format);
-
- unsigned int GetWidth() const
+
+ DicomTag GetPrefixTag(size_t depth) const
{
- return width_;
+ return GetPrefixItem(depth).first;
}
- void SetWidth(unsigned int width);
-
- unsigned int GetHeight() const
+ size_t GetPrefixIndex(size_t depth) const
{
- return height_;
+ return GetPrefixItem(depth).second;
}
-
- void SetHeight(unsigned int height);
-
- unsigned int GetBytesPerPixel() const
+
+ const DicomTag& GetFinalTag() const
{
- return ::Orthanc::GetBytesPerPixel(format_);
+ return finalTag_;
}
- ImageAccessor GetAccessor();
-
- ImageAccessor GetConstAccessor();
-
- bool IsMinimalPitchForced() const
+ void SetFinalTag(const DicomTag& tag)
{
- return forceMinimalPitch_;
+ finalTag_ = tag;
}
-
- void SetMinimalPitchForced(bool force);
-
- void AcquireOwnership(ImageBuffer& other);
};
}
diff --git a/Core/DicomFormat/DicomImageInformation.h b/Plugins/Samples/Common/DicomTag.cpp
similarity index 51%
copy from Core/DicomFormat/DicomImageInformation.h
copy to Plugins/Samples/Common/DicomTag.cpp
index 568e6e3..040d885 100644
--- a/Core/DicomFormat/DicomImageInformation.h
+++ b/Plugins/Samples/Common/DicomTag.cpp
@@ -30,98 +30,81 @@
**/
-#pragma once
+#include "DicomTag.h"
-#include "DicomMap.h"
+#include "OrthancPluginCppWrapper.h"
-#include <stdint.h>
-
-namespace Orthanc
+namespace OrthancPlugins
{
- class DicomImageInformation
+ const char* DicomTag::GetName() const
{
- private:
- unsigned int width_;
- unsigned int height_;
- unsigned int samplesPerPixel_;
- unsigned int numberOfFrames_;
-
- bool isPlanar_;
- bool isSigned_;
- size_t bytesPerValue_;
-
- unsigned int bitsAllocated_;
- unsigned int bitsStored_;
- unsigned int highBit_;
-
- PhotometricInterpretation photometric_;
-
- public:
- DicomImageInformation(const DicomMap& values);
-
- unsigned int GetWidth() const
+ if (*this == DICOM_TAG_BITS_STORED)
{
- return width_;
+ return "BitsStored";
}
-
- unsigned int GetHeight() const
+ else if (*this == DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)
{
- return height_;
+ return "ColumnPositionInTotalImagePixelMatrix";
}
-
- unsigned int GetNumberOfFrames() const
+ else if (*this == DICOM_TAG_COLUMNS)
{
- return numberOfFrames_;
+ return "Columns";
}
-
- unsigned int GetChannelCount() const
+ else if (*this == DICOM_TAG_MODALITY)
{
- return samplesPerPixel_;
+ return "Modality";
}
-
- unsigned int GetBitsStored() const
+ else if (*this == DICOM_TAG_NUMBER_OF_FRAMES)
{
- return bitsStored_;
+ return "NumberOfFrames";
}
-
- size_t GetBytesPerValue() const
+ else if (*this == DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE)
{
- return bytesPerValue_;
+ return "PerFrameFunctionalGroupsSequence";
}
-
- bool IsSigned() const
+ else if (*this == DICOM_TAG_PHOTOMETRIC_INTERPRETATION)
{
- return isSigned_;
+ return "PhotometricInterpretation";
}
-
- unsigned int GetBitsAllocated() const
+ else if (*this == DICOM_TAG_PIXEL_REPRESENTATION)
{
- return bitsAllocated_;
+ return "PixelRepresentation";
}
-
- unsigned int GetHighBit() const
+ else if (*this == DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE)
{
- return highBit_;
+ return "PlanePositionSlideSequence";
}
-
- bool IsPlanar() const
+ else if (*this == DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX)
{
- return isPlanar_;
+ return "RowPositionInTotalImagePixelMatrix";
}
-
- unsigned int GetShift() const
+ else if (*this == DICOM_TAG_ROWS)
{
- return highBit_ + 1 - bitsStored_;
+ return "Rows";
}
-
- PhotometricInterpretation GetPhotometricInterpretation() const
+ else if (*this == DICOM_TAG_SOP_CLASS_UID)
{
- return photometric_;
+ return "SOPClassUID";
}
-
- bool ExtractPixelFormat(PixelFormat& format,
- bool ignorePhotometricInterpretation) const;
-
- size_t GetFrameSize() const;
- };
+ else if (*this == DICOM_TAG_SAMPLES_PER_PIXEL)
+ {
+ return "SamplesPerPixel";
+ }
+ else if (*this == DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS)
+ {
+ return "TotalPixelMatrixColumns";
+ }
+ else if (*this == DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS)
+ {
+ return "TotalPixelMatrixRows";
+ }
+ else if (*this == DICOM_TAG_TRANSFER_SYNTAX_UID)
+ {
+ return "TransferSyntaxUID";
+ }
+ else
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_NotImplemented);
+ }
+ }
}
diff --git a/Plugins/Samples/Common/DicomTag.h b/Plugins/Samples/Common/DicomTag.h
new file mode 100644
index 0000000..660d078
--- /dev/null
+++ b/Plugins/Samples/Common/DicomTag.h
@@ -0,0 +1,95 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#pragma once
+
+#include <stdint.h>
+
+namespace OrthancPlugins
+{
+ class DicomTag
+ {
+ private:
+ uint16_t group_;
+ uint16_t element_;
+
+ DicomTag(); // Forbidden
+
+ public:
+ DicomTag(uint16_t group,
+ uint16_t element) :
+ group_(group),
+ element_(element)
+ {
+ }
+
+ uint16_t GetGroup() const
+ {
+ return group_;
+ }
+
+ uint16_t GetElement() const
+ {
+ return element_;
+ }
+
+ const char* GetName() const;
+
+ bool operator== (const DicomTag& other) const
+ {
+ return group_ == other.group_ && element_ == other.element_;
+ }
+
+ bool operator!= (const DicomTag& other) const
+ {
+ return !(*this == other);
+ }
+ };
+
+
+ static const DicomTag DICOM_TAG_BITS_STORED(0x0028, 0x0101);
+ static const DicomTag DICOM_TAG_COLUMN_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021e);
+ static const DicomTag DICOM_TAG_COLUMNS(0x0028, 0x0011);
+ static const DicomTag DICOM_TAG_MODALITY(0x0008, 0x0060);
+ static const DicomTag DICOM_TAG_NUMBER_OF_FRAMES(0x0028, 0x0008);
+ static const DicomTag DICOM_TAG_PER_FRAME_FUNCTIONAL_GROUPS_SEQUENCE(0x5200, 0x9230);
+ static const DicomTag DICOM_TAG_PHOTOMETRIC_INTERPRETATION(0x0028, 0x0004);
+ static const DicomTag DICOM_TAG_PIXEL_REPRESENTATION(0x0028, 0x0103);
+ static const DicomTag DICOM_TAG_PLANE_POSITION_SLIDE_SEQUENCE(0x0048, 0x021a);
+ static const DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f);
+ static const DicomTag DICOM_TAG_ROWS(0x0028, 0x0010);
+ static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016);
+ static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002);
+ static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_COLUMNS(0x0048, 0x0006);
+ static const DicomTag DICOM_TAG_TOTAL_PIXEL_MATRIX_ROWS(0x0048, 0x0007);
+ static const DicomTag DICOM_TAG_TRANSFER_SYNTAX_UID(0x0002, 0x0010);
+}
diff --git a/Plugins/Samples/Common/FullOrthancDataset.cpp b/Plugins/Samples/Common/FullOrthancDataset.cpp
new file mode 100644
index 0000000..638654b
--- /dev/null
+++ b/Plugins/Samples/Common/FullOrthancDataset.cpp
@@ -0,0 +1,196 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "FullOrthancDataset.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+namespace OrthancPlugins
+{
+ static const Json::Value* AccessTag(const Json::Value& dataset,
+ const DicomTag& tag)
+ {
+ if (dataset.type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ char name[16];
+ sprintf(name, "%04x,%04x", tag.GetGroup(), tag.GetElement());
+
+ if (!dataset.isMember(name))
+ {
+ return NULL;
+ }
+
+ const Json::Value& value = dataset[name];
+ if (value.type() != Json::objectValue ||
+ !value.isMember("Name") ||
+ !value.isMember("Type") ||
+ !value.isMember("Value") ||
+ value["Name"].type() != Json::stringValue ||
+ value["Type"].type() != Json::stringValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ return &value;
+ }
+
+
+ static const Json::Value& GetSequenceContent(const Json::Value& sequence)
+ {
+ assert(sequence.type() == Json::objectValue);
+ assert(sequence.isMember("Type"));
+ assert(sequence.isMember("Value"));
+
+ const Json::Value& value = sequence["Value"];
+
+ if (sequence["Type"].asString() != "Sequence" ||
+ value.type() != Json::arrayValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ else
+ {
+ return value;
+ }
+ }
+
+
+ static bool GetStringInternal(std::string& result,
+ const Json::Value& tag)
+ {
+ assert(tag.type() == Json::objectValue);
+ assert(tag.isMember("Type"));
+ assert(tag.isMember("Value"));
+
+ const Json::Value& value = tag["Value"];
+
+ if (tag["Type"].asString() != "String" ||
+ value.type() != Json::stringValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ else
+ {
+ result = value.asString();
+ return true;
+ }
+ }
+
+
+ const Json::Value* FullOrthancDataset::LookupPath(const DicomPath& path) const
+ {
+ const Json::Value* content = &root_;
+
+ for (unsigned int depth = 0; depth < path.GetPrefixLength(); depth++)
+ {
+ const Json::Value* sequence = AccessTag(*content, path.GetPrefixTag(depth));
+ if (sequence == NULL)
+ {
+ return NULL;
+ }
+
+ const Json::Value& nextContent = GetSequenceContent(*sequence);
+
+ size_t index = path.GetPrefixIndex(depth);
+ if (index >= nextContent.size())
+ {
+ return NULL;
+ }
+ else
+ {
+ content = &nextContent[static_cast<Json::Value::ArrayIndex>(index)];
+ }
+ }
+
+ return AccessTag(*content, path.GetFinalTag());
+ }
+
+
+ void FullOrthancDataset::CheckRoot() const
+ {
+ if (root_.type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ }
+
+
+ FullOrthancDataset::FullOrthancDataset(IOrthancConnection& orthanc,
+ const std::string& uri)
+ {
+ IOrthancConnection::RestApiGet(root_, orthanc, uri);
+ CheckRoot();
+ }
+
+
+ FullOrthancDataset::FullOrthancDataset(const std::string& content)
+ {
+ IOrthancConnection::ParseJson(root_, content);
+ CheckRoot();
+ }
+
+
+ bool FullOrthancDataset::GetStringValue(std::string& result,
+ const DicomPath& path) const
+ {
+ const Json::Value* value = LookupPath(path);
+
+ if (value == NULL)
+ {
+ return false;
+ }
+ else
+ {
+ return GetStringInternal(result, *value);
+ }
+ }
+
+
+ bool FullOrthancDataset::GetSequenceSize(size_t& size,
+ const DicomPath& path) const
+ {
+ const Json::Value* sequence = LookupPath(path);
+
+ if (sequence == NULL)
+ {
+ return false;
+ }
+ else
+ {
+ size = GetSequenceContent(*sequence).size();
+ return true;
+ }
+ }
+}
diff --git a/Core/Images/PngReader.h b/Plugins/Samples/Common/FullOrthancDataset.h
similarity index 71%
copy from Core/Images/PngReader.h
copy to Plugins/Samples/Common/FullOrthancDataset.h
index b6ad811..18ab444 100644
--- a/Core/Images/PngReader.h
+++ b/Plugins/Samples/Common/FullOrthancDataset.h
@@ -32,38 +32,32 @@
#pragma once
-#include "ImageAccessor.h"
+#include "IOrthancConnection.h"
+#include "IDicomDataset.h"
-#include "../Enumerations.h"
+#include <json/value.h>
-#include <vector>
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/noncopyable.hpp>
-
-namespace Orthanc
+namespace OrthancPlugins
{
- class PngReader :
- public ImageAccessor,
- public boost::noncopyable
+ class FullOrthancDataset : public IDicomDataset
{
private:
- struct PngRabi;
-
- std::vector<uint8_t> data_;
+ Json::Value root_;
- void CheckHeader(const void* header);
+ const Json::Value* LookupPath(const DicomPath& path) const;
- void Read(PngRabi& rabi);
+ void CheckRoot() const;
public:
- PngReader();
+ FullOrthancDataset(IOrthancConnection& orthanc,
+ const std::string& uri);
- void ReadFromFile(const std::string& filename);
+ FullOrthancDataset(const std::string& content);
- void ReadFromMemory(const void* buffer,
- size_t size);
+ virtual bool GetStringValue(std::string& result,
+ const DicomPath& path) const;
- void ReadFromMemory(const std::string& buffer);
+ virtual bool GetSequenceSize(size_t& size,
+ const DicomPath& path) const;
};
}
diff --git a/Core/Images/JpegReader.h b/Plugins/Samples/Common/IDicomDataset.h
similarity index 81%
copy from Core/Images/JpegReader.h
copy to Plugins/Samples/Common/IDicomDataset.h
index 5cb5551..7fc549e 100644
--- a/Core/Images/JpegReader.h
+++ b/Plugins/Samples/Common/IDicomDataset.h
@@ -32,26 +32,24 @@
#pragma once
-#include "ImageAccessor.h"
+#include "DicomPath.h"
-#include <string>
#include <boost/noncopyable.hpp>
+#include <string>
-namespace Orthanc
+namespace OrthancPlugins
{
- class JpegReader :
- public ImageAccessor,
- public boost::noncopyable
+ class IDicomDataset : public boost::noncopyable
{
- private:
- std::string content_;
-
public:
- void ReadFromFile(const std::string& filename);
+ virtual ~IDicomDataset()
+ {
+ }
- void ReadFromMemory(const void* buffer,
- size_t size);
+ virtual bool GetStringValue(std::string& result,
+ const DicomPath& path) const = 0;
- void ReadFromMemory(const std::string& buffer);
+ virtual bool GetSequenceSize(size_t& size,
+ const DicomPath& path) const = 0;
};
}
diff --git a/Core/DicomFormat/DicomValue.cpp b/Plugins/Samples/Common/IOrthancConnection.cpp
similarity index 54%
copy from Core/DicomFormat/DicomValue.cpp
copy to Plugins/Samples/Common/IOrthancConnection.cpp
index 32a17b5..5a66912 100644
--- a/Core/DicomFormat/DicomValue.cpp
+++ b/Plugins/Samples/Common/IOrthancConnection.cpp
@@ -30,64 +30,54 @@
**/
-#include "../PrecompiledHeaders.h"
-#include "DicomValue.h"
+#include "IOrthancConnection.h"
-#include "../OrthancException.h"
-#include "../Toolbox.h"
-
-namespace Orthanc
-{
- DicomValue::DicomValue(const DicomValue& other) :
- type_(other.type_),
- content_(other.content_)
- {
- }
+#include "OrthancPluginCppWrapper.h"
+#include <json/reader.h>
- DicomValue::DicomValue(const std::string& content,
- bool isBinary) :
- type_(isBinary ? Type_Binary : Type_String),
- content_(content)
- {
- }
-
-
- DicomValue::DicomValue(const char* data,
- size_t size,
- bool isBinary) :
- type_(isBinary ? Type_Binary : Type_String)
+namespace OrthancPlugins
+{
+ void IOrthancConnection::ParseJson(Json::Value& result,
+ const std::string& content)
{
- content_.assign(data, size);
- }
+ Json::Reader reader;
-
- const std::string& DicomValue::GetContent() const
- {
- if (type_ == Type_Null)
- {
- throw OrthancException(ErrorCode_BadParameterType);
- }
- else
+ if (!reader.parse(content, result))
{
- return content_;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
- DicomValue* DicomValue::Clone() const
+ void IOrthancConnection::RestApiGet(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri)
{
- return new DicomValue(*this);
+ std::string content;
+ orthanc.RestApiGet(content, uri);
+ ParseJson(result, content);
}
-
-#if !defined(ORTHANC_ENABLE_BASE64) || ORTHANC_ENABLE_BASE64 == 1
- void DicomValue::FormatDataUriScheme(std::string& target,
- const std::string& mime) const
+
+ void IOrthancConnection::RestApiPost(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri,
+ const std::string& body)
{
- Toolbox::EncodeBase64(target, GetContent());
- target.insert(0, "data:" + mime + ";base64,");
+ std::string content;
+ orthanc.RestApiPost(content, uri, body);
+ ParseJson(result, content);
}
-#endif
+
+ void IOrthancConnection::RestApiPut(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri,
+ const std::string& body)
+ {
+ std::string content;
+ orthanc.RestApiPut(content, uri, body);
+ ParseJson(result, content);
+ }
}
diff --git a/Plugins/Engine/PluginsErrorDictionary.h b/Plugins/Samples/Common/IOrthancConnection.h
similarity index 56%
copy from Plugins/Engine/PluginsErrorDictionary.h
copy to Plugins/Samples/Common/IOrthancConnection.h
index 018156d..f64dd5a 100644
--- a/Plugins/Engine/PluginsErrorDictionary.h
+++ b/Plugins/Samples/Common/IOrthancConnection.h
@@ -32,61 +32,49 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#include "DicomPath.h"
-#include "../Include/orthanc/OrthancCPlugin.h"
-#include "../../Core/OrthancException.h"
-#include "SharedLibrary.h"
-
-#include <map>
-#include <string>
#include <boost/noncopyable.hpp>
-#include <boost/thread/mutex.hpp>
+#include <string>
#include <json/value.h>
-
-namespace Orthanc
+namespace OrthancPlugins
{
- class PluginsErrorDictionary : public boost::noncopyable
+ class IOrthancConnection : public boost::noncopyable
{
- private:
- struct Error
+ public:
+ virtual ~IOrthancConnection()
{
- std::string pluginName_;
- int32_t pluginCode_;
- HttpStatus httpStatus_;
- std::string message_;
- };
-
- typedef std::map<int32_t, Error*> Errors;
+ }
- boost::mutex mutex_;
- int32_t pos_;
- Errors errors_;
+ virtual void RestApiGet(std::string& result,
+ const std::string& uri) = 0;
- public:
- PluginsErrorDictionary();
+ virtual void RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body) = 0;
- ~PluginsErrorDictionary();
+ virtual void RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body) = 0;
- OrthancPluginErrorCode Register(SharedLibrary& library,
- int32_t pluginCode,
- uint16_t httpStatus,
- const char* message);
+ virtual void RestApiDelete(const std::string& uri) = 0;
- void LogError(ErrorCode code,
- bool ignoreBuiltinErrors);
+ static void ParseJson(Json::Value& result,
+ const std::string& content);
- void LogError(OrthancPluginErrorCode code,
- bool ignoreBuiltinErrors)
- {
- LogError(static_cast<ErrorCode>(code), ignoreBuiltinErrors);
- }
+ static void RestApiGet(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri);
- bool Format(Json::Value& message, /* out */
- HttpStatus& httpStatus, /* out */
- const OrthancException& exception);
+ static void RestApiPost(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri,
+ const std::string& body);
+
+ static void RestApiPut(Json::Value& result,
+ IOrthancConnection& orthanc,
+ const std::string& uri,
+ const std::string& body);
};
}
-
-#endif
diff --git a/Core/Cache/SharedArchive.cpp b/Plugins/Samples/Common/OrthancHttpConnection.cpp
similarity index 50%
copy from Core/Cache/SharedArchive.cpp
copy to Plugins/Samples/Common/OrthancHttpConnection.cpp
index 93303e8..a1f9846 100644
--- a/Core/Cache/SharedArchive.cpp
+++ b/Plugins/Samples/Common/OrthancHttpConnection.cpp
@@ -30,105 +30,78 @@
**/
-#include "../PrecompiledHeaders.h"
-#include "SharedArchive.h"
+#include "OrthancHttpConnection.h"
-
-#include "../Uuid.h"
-
-
-namespace Orthanc
+namespace OrthancPlugins
{
- void SharedArchive::RemoveInternal(const std::string& id)
+ void OrthancHttpConnection::Setup()
{
- Archive::iterator it = archive_.find(id);
+ url_ = client_.GetUrl();
- if (it != archive_.end())
- {
- delete it->second;
- archive_.erase(it);
- }
+ // Don't follow 3xx HTTP (avoid redirections to "unsupported.png" in Orthanc)
+ client_.SetRedirectionFollowed(false);
}
- SharedArchive::Accessor::Accessor(SharedArchive& that,
- const std::string& id) :
- lock_(that.mutex_)
+ OrthancHttpConnection::OrthancHttpConnection() :
+ client_(Orthanc::WebServiceParameters(), "")
{
- Archive::iterator it = that.archive_.find(id);
-
- if (it == that.archive_.end())
- {
- throw OrthancException(ErrorCode_InexistentItem);
- }
- else
- {
- that.lru_.MakeMostRecent(id);
- item_ = it->second;
- }
+ Setup();
}
- SharedArchive::SharedArchive(size_t maxSize) :
- maxSize_(maxSize)
+ OrthancHttpConnection::OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters) :
+ client_(parameters, "")
{
- if (maxSize == 0)
- {
- throw OrthancException(ErrorCode_ParameterOutOfRange);
- }
+ Setup();
}
- SharedArchive::~SharedArchive()
+ void OrthancHttpConnection::RestApiGet(std::string& result,
+ const std::string& uri)
{
- for (Archive::iterator it = archive_.begin();
- it != archive_.end(); ++it)
- {
- delete it->second;
- }
+ boost::mutex::scoped_lock lock(mutex_);
+
+ client_.SetMethod(Orthanc::HttpMethod_Get);
+ client_.SetUrl(url_ + uri);
+ client_.ApplyAndThrowException(result);
}
- std::string SharedArchive::Add(IDynamicObject* obj)
+ void OrthancHttpConnection::RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body)
{
boost::mutex::scoped_lock lock(mutex_);
- if (archive_.size() == maxSize_)
- {
- // The quota has been reached, remove the oldest element
- std::string oldest = lru_.RemoveOldest();
- RemoveInternal(oldest);
- }
-
- std::string id = Toolbox::GenerateUuid();
- RemoveInternal(id); // Should never be useful because of UUID
- archive_[id] = obj;
- lru_.Add(id);
-
- return id;
+ client_.SetMethod(Orthanc::HttpMethod_Post);
+ client_.SetUrl(url_ + uri);
+ client_.SetBody(body);
+ client_.ApplyAndThrowException(result);
}
- void SharedArchive::Remove(const std::string& id)
+ void OrthancHttpConnection::RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body)
{
boost::mutex::scoped_lock lock(mutex_);
- RemoveInternal(id);
- lru_.Invalidate(id);
+
+ client_.SetMethod(Orthanc::HttpMethod_Put);
+ client_.SetUrl(url_ + uri);
+ client_.SetBody(body);
+ client_.ApplyAndThrowException(result);
}
- void SharedArchive::List(std::list<std::string>& items)
+ void OrthancHttpConnection::RestApiDelete(const std::string& uri)
{
- items.clear();
-
boost::mutex::scoped_lock lock(mutex_);
- for (Archive::const_iterator it = archive_.begin();
- it != archive_.end(); ++it)
- {
- items.push_back(it->first);
- }
+ std::string result;
+
+ client_.SetMethod(Orthanc::HttpMethod_Delete);
+ client_.SetUrl(url_ + uri);
+ client_.ApplyAndThrowException(result);
}
}
-
-
diff --git a/Plugins/Engine/SharedLibrary.h b/Plugins/Samples/Common/OrthancHttpConnection.h
similarity index 61%
copy from Plugins/Engine/SharedLibrary.h
copy to Plugins/Samples/Common/OrthancHttpConnection.h
index 5a7913a..c1e69bd 100644
--- a/Plugins/Engine/SharedLibrary.h
+++ b/Plugins/Samples/Common/OrthancHttpConnection.h
@@ -32,47 +32,44 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#include "IOrthancConnection.h"
-#include "../../Core/OrthancException.h"
+#if HAS_ORTHANC_EXCEPTION != 1
+# error The macro HAS_ORTHANC_EXCEPTION must be set to 1 if using this header
+#endif
-#include <boost/noncopyable.hpp>
+#include "../../../Core/HttpClient.h"
-#if defined(_WIN32)
-#include <windows.h>
-#endif
+#include <boost/thread/mutex.hpp>
-namespace Orthanc
+namespace OrthancPlugins
{
- class SharedLibrary : public boost::noncopyable
+ // This class is thread-safe
+ class OrthancHttpConnection : public IOrthancConnection
{
- public:
-#if defined(_WIN32)
- typedef FARPROC FunctionPointer;
-#else
- typedef void* FunctionPointer;
-#endif
-
private:
- std::string path_;
- void *handle_;
+ boost::mutex mutex_;
+ Orthanc::HttpClient client_;
+ std::string url_;
- FunctionPointer GetFunctionInternal(const std::string& name);
+ void Setup();
public:
- SharedLibrary(const std::string& path);
+ OrthancHttpConnection();
+
+ OrthancHttpConnection(const Orthanc::WebServiceParameters& parameters);
- ~SharedLibrary();
+ virtual void RestApiGet(std::string& result,
+ const std::string& uri);
- const std::string& GetPath() const
- {
- return path_;
- }
+ virtual void RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body);
- bool HasFunction(const std::string& name);
+ virtual void RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body);
- FunctionPointer GetFunction(const std::string& name);
+ virtual void RestApiDelete(const std::string& uri);
};
}
-
-#endif
diff --git a/Core/DicomFormat/DicomImageInformation.h b/Plugins/Samples/Common/OrthancPluginConnection.cpp
similarity index 51%
copy from Core/DicomFormat/DicomImageInformation.h
copy to Plugins/Samples/Common/OrthancPluginConnection.cpp
index 568e6e3..fb82353 100644
--- a/Core/DicomFormat/DicomImageInformation.h
+++ b/Plugins/Samples/Common/OrthancPluginConnection.cpp
@@ -30,98 +30,69 @@
**/
-#pragma once
+#include "OrthancPluginConnection.h"
-#include "DicomMap.h"
+#include "OrthancPluginCppWrapper.h"
-#include <stdint.h>
-
-namespace Orthanc
+namespace OrthancPlugins
{
- class DicomImageInformation
+ void OrthancPluginConnection::RestApiGet(std::string& result,
+ const std::string& uri)
{
- private:
- unsigned int width_;
- unsigned int height_;
- unsigned int samplesPerPixel_;
- unsigned int numberOfFrames_;
-
- bool isPlanar_;
- bool isSigned_;
- size_t bytesPerValue_;
-
- unsigned int bitsAllocated_;
- unsigned int bitsStored_;
- unsigned int highBit_;
+ OrthancPlugins::MemoryBuffer buffer(context_);
- PhotometricInterpretation photometric_;
-
- public:
- DicomImageInformation(const DicomMap& values);
-
- unsigned int GetWidth() const
+ if (buffer.RestApiGet(uri, false))
{
- return width_;
+ buffer.ToString(result);
}
-
- unsigned int GetHeight() const
+ else
{
- return height_;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
}
+ }
- unsigned int GetNumberOfFrames() const
- {
- return numberOfFrames_;
- }
- unsigned int GetChannelCount() const
- {
- return samplesPerPixel_;
- }
+ void OrthancPluginConnection::RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body)
+ {
+ OrthancPlugins::MemoryBuffer buffer(context_);
- unsigned int GetBitsStored() const
+ if (buffer.RestApiPost(uri, body.c_str(), body.size(), false))
{
- return bitsStored_;
+ buffer.ToString(result);
}
-
- size_t GetBytesPerValue() const
+ else
{
- return bytesPerValue_;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
}
+ }
- bool IsSigned() const
- {
- return isSigned_;
- }
- unsigned int GetBitsAllocated() const
- {
- return bitsAllocated_;
- }
+ void OrthancPluginConnection::RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body)
+ {
+ OrthancPlugins::MemoryBuffer buffer(context_);
- unsigned int GetHighBit() const
+ if (buffer.RestApiPut(uri, body.c_str(), body.size(), false))
{
- return highBit_;
+ buffer.ToString(result);
}
-
- bool IsPlanar() const
+ else
{
- return isPlanar_;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
}
+ }
- unsigned int GetShift() const
- {
- return highBit_ + 1 - bitsStored_;
- }
- PhotometricInterpretation GetPhotometricInterpretation() const
+ void OrthancPluginConnection::RestApiDelete(const std::string& uri)
+ {
+ OrthancPlugins::MemoryBuffer buffer(context_);
+
+ if (!::OrthancPlugins::RestApiDelete(context_, uri, false))
{
- return photometric_;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_UnknownResource);
}
-
- bool ExtractPixelFormat(PixelFormat& format,
- bool ignorePhotometricInterpretation) const;
-
- size_t GetFrameSize() const;
- };
+ }
}
diff --git a/Plugins/Engine/SharedLibrary.h b/Plugins/Samples/Common/OrthancPluginConnection.h
similarity index 68%
copy from Plugins/Engine/SharedLibrary.h
copy to Plugins/Samples/Common/OrthancPluginConnection.h
index 5a7913a..f4b06ff 100644
--- a/Plugins/Engine/SharedLibrary.h
+++ b/Plugins/Samples/Common/OrthancPluginConnection.h
@@ -32,47 +32,35 @@
#pragma once
-#if ORTHANC_PLUGINS_ENABLED == 1
+#include "IOrthancConnection.h"
-#include "../../Core/OrthancException.h"
+#include <orthanc/OrthancCPlugin.h>
-#include <boost/noncopyable.hpp>
-
-#if defined(_WIN32)
-#include <windows.h>
-#endif
-
-namespace Orthanc
+namespace OrthancPlugins
{
- class SharedLibrary : public boost::noncopyable
+ // This class is thread-safe
+ class OrthancPluginConnection : public IOrthancConnection
{
- public:
-#if defined(_WIN32)
- typedef FARPROC FunctionPointer;
-#else
- typedef void* FunctionPointer;
-#endif
-
private:
- std::string path_;
- void *handle_;
-
- FunctionPointer GetFunctionInternal(const std::string& name);
+ OrthancPluginContext* context_;
public:
- SharedLibrary(const std::string& path);
-
- ~SharedLibrary();
-
- const std::string& GetPath() const
+ OrthancPluginConnection(OrthancPluginContext* context) :
+ context_(context)
{
- return path_;
}
- bool HasFunction(const std::string& name);
+ virtual void RestApiGet(std::string& result,
+ const std::string& uri);
+
+ virtual void RestApiPost(std::string& result,
+ const std::string& uri,
+ const std::string& body);
- FunctionPointer GetFunction(const std::string& name);
+ virtual void RestApiPut(std::string& result,
+ const std::string& uri,
+ const std::string& body);
+
+ virtual void RestApiDelete(const std::string& uri);
};
}
-
-#endif
diff --git a/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp b/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
index 6a7dbc0..b26c512 100644
--- a/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
+++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp
@@ -33,13 +33,15 @@
#include "OrthancPluginCppWrapper.h"
#include <json/reader.h>
+#include <json/writer.h>
namespace OrthancPlugins
{
- const char* PluginException::GetErrorDescription(OrthancPluginContext* context) const
+ const char* GetErrorDescription(OrthancPluginContext* context,
+ OrthancPluginErrorCode code)
{
- const char* description = OrthancPluginGetErrorDescription(context, code_);
+ const char* description = OrthancPluginGetErrorDescription(context, code);
if (description)
{
return description;
@@ -50,6 +52,29 @@ namespace OrthancPlugins
}
}
+
+#if HAS_ORTHANC_EXCEPTION == 0
+ void PluginException::Check(OrthancPluginErrorCode code)
+ {
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(code);
+ }
+ }
+#endif
+
+
+ void MemoryBuffer::Check(OrthancPluginErrorCode code)
+ {
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ // Prevent using garbage information
+ buffer_.data = NULL;
+ buffer_.size = 0;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(code);
+ }
+ }
+
MemoryBuffer::MemoryBuffer(OrthancPluginContext* context) :
context_(context)
@@ -100,7 +125,7 @@ namespace OrthancPlugins
if (buffer_.data == NULL ||
buffer_.size == 0)
{
- throw PluginException(OrthancPluginErrorCode_InternalError);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
}
const char* tmp = reinterpret_cast<const char*>(buffer_.data);
@@ -109,7 +134,7 @@ namespace OrthancPlugins
if (!reader.parse(tmp, tmp + buffer_.size, target))
{
OrthancPluginLogError(context_, "Cannot convert some memory buffer to JSON");
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
@@ -141,7 +166,7 @@ namespace OrthancPlugins
}
else
{
- throw PluginException(error);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(error);
}
}
@@ -175,7 +200,7 @@ namespace OrthancPlugins
}
else
{
- throw PluginException(error);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(error);
}
}
@@ -209,16 +234,66 @@ namespace OrthancPlugins
}
else
{
- throw PluginException(error);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(error);
}
}
- OrthancString::OrthancString(OrthancPluginContext* context,
- char* str) :
- context_(context),
- str_(str)
+ bool MemoryBuffer::RestApiPost(const std::string& uri,
+ const Json::Value& body,
+ bool applyPlugins)
+ {
+ Json::FastWriter writer;
+ return RestApiPost(uri, writer.write(body), applyPlugins);
+ }
+
+
+ bool MemoryBuffer::RestApiPut(const std::string& uri,
+ const Json::Value& body,
+ bool applyPlugins)
+ {
+ Json::FastWriter writer;
+ return RestApiPut(uri, writer.write(body), applyPlugins);
+ }
+
+
+ void MemoryBuffer::CreateDicom(const Json::Value& tags,
+ OrthancPluginCreateDicomFlags flags)
+ {
+ Clear();
+
+ Json::FastWriter writer;
+ std::string s = writer.write(tags);
+
+ Check(OrthancPluginCreateDicom(context_, &buffer_, s.c_str(), NULL, flags));
+ }
+
+
+ void MemoryBuffer::ReadFile(const std::string& path)
+ {
+ Clear();
+ Check(OrthancPluginReadFile(context_, &buffer_, path.c_str()));
+ }
+
+
+ void MemoryBuffer::GetDicomQuery(const OrthancPluginWorklistQuery* query)
+ {
+ Clear();
+ Check(OrthancPluginWorklistGetDicomQuery(context_, &buffer_, query));
+ }
+
+
+ void OrthancString::Assign(char* str)
{
+ if (str == NULL)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
+ }
+ else
+ {
+ Clear();
+ str_ = str;
+ }
}
@@ -250,27 +325,40 @@ namespace OrthancPlugins
if (str_ == NULL)
{
OrthancPluginLogError(context_, "Cannot convert an empty memory buffer to JSON");
- throw PluginException(OrthancPluginErrorCode_InternalError);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
}
Json::Reader reader;
if (!reader.parse(str_, target))
{
OrthancPluginLogError(context_, "Cannot convert some memory buffer to JSON");
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
+
+
+ void MemoryBuffer::DicomToJson(Json::Value& target,
+ OrthancPluginDicomToJsonFormat format,
+ OrthancPluginDicomToJsonFlags flags,
+ uint32_t maxStringLength)
+ {
+ OrthancString str(context_);
+ str.Assign(OrthancPluginDicomBufferToJson(context_, GetData(), GetSize(), format, flags, maxStringLength));
+ str.ToJson(target);
+ }
+
OrthancConfiguration::OrthancConfiguration(OrthancPluginContext* context) :
context_(context)
{
- OrthancString str(context, OrthancPluginGetConfiguration(context));
+ OrthancString str(context);
+ str.Assign(OrthancPluginGetConfiguration(context));
if (str.GetContent() == NULL)
{
OrthancPluginLogError(context, "Cannot access the Orthanc configuration");
- throw PluginException(OrthancPluginErrorCode_InternalError);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
}
str.ToJson(configuration_);
@@ -278,7 +366,7 @@ namespace OrthancPlugins
if (configuration_.type() != Json::objectValue)
{
OrthancPluginLogError(context, "Unable to read the Orthanc configuration");
- throw PluginException(OrthancPluginErrorCode_InternalError);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
}
}
@@ -287,7 +375,7 @@ namespace OrthancPlugins
{
if (context_ == NULL)
{
- throw PluginException(OrthancPluginErrorCode_Plugin);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_Plugin);
}
else
{
@@ -309,6 +397,15 @@ namespace OrthancPlugins
}
+ bool OrthancConfiguration::IsSection(const std::string& key) const
+ {
+ assert(configuration_.type() == Json::objectValue);
+
+ return (configuration_.isMember(key) &&
+ configuration_[key].type() == Json::objectValue);
+ }
+
+
void OrthancConfiguration::GetSection(OrthancConfiguration& target,
const std::string& key) const
{
@@ -331,7 +428,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
target.configuration_ = configuration_[key];
@@ -357,7 +454,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
target = configuration_[key].asString();
@@ -392,7 +489,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
@@ -414,7 +511,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
else
{
@@ -442,7 +539,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
target = configuration_[key].asBool();
@@ -467,11 +564,11 @@ namespace OrthancPlugins
return true;
case Json::intValue:
- target = configuration_[key].asInt();
+ target = static_cast<float>(configuration_[key].asInt());
return true;
case Json::uintValue:
- target = configuration_[key].asUInt();
+ target = static_cast<float>(configuration_[key].asUInt());
return true;
default:
@@ -481,7 +578,7 @@ namespace OrthancPlugins
OrthancPluginLogError(context_, s.c_str());
}
- throw PluginException(OrthancPluginErrorCode_BadFileFormat);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
}
@@ -576,7 +673,7 @@ namespace OrthancPlugins
if (image_ == NULL)
{
OrthancPluginLogError(context_, "Trying to access a NULL image");
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -587,7 +684,7 @@ namespace OrthancPlugins
{
if (context == NULL)
{
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -599,7 +696,7 @@ namespace OrthancPlugins
{
if (context == NULL)
{
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -612,7 +709,7 @@ namespace OrthancPlugins
{
if (context == NULL)
{
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
else
{
@@ -629,7 +726,7 @@ namespace OrthancPlugins
if (image_ == NULL)
{
OrthancPluginLogError(context_, "Cannot uncompress a PNG image");
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -642,7 +739,7 @@ namespace OrthancPlugins
if (image_ == NULL)
{
OrthancPluginLogError(context_, "Cannot uncompress a JPEG image");
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -656,7 +753,7 @@ namespace OrthancPlugins
if (image_ == NULL)
{
OrthancPluginLogError(context_, "Cannot uncompress a DICOM image");
- throw PluginException(OrthancPluginErrorCode_ParameterOutOfRange);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
}
}
@@ -738,10 +835,84 @@ namespace OrthancPlugins
}
- bool RestApiGetJson(Json::Value& result,
- OrthancPluginContext* context,
- const std::string& uri,
- bool applyPlugins)
+ FindMatcher::FindMatcher(OrthancPluginContext* context,
+ const OrthancPluginWorklistQuery* worklist) :
+ context_(context),
+ matcher_(NULL),
+ worklist_(worklist)
+ {
+ if (worklist_ == NULL)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_ParameterOutOfRange);
+ }
+ }
+
+
+ void FindMatcher::SetupDicom(OrthancPluginContext* context,
+ const void* query,
+ uint32_t size)
+ {
+ context_ = context;
+ worklist_ = NULL;
+
+ matcher_ = OrthancPluginCreateFindMatcher(context_, query, size);
+ if (matcher_ == NULL)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
+ }
+ }
+
+
+ FindMatcher::~FindMatcher()
+ {
+ // The "worklist_" field
+
+ if (matcher_ != NULL)
+ {
+ OrthancPluginFreeFindMatcher(context_, matcher_);
+ }
+ }
+
+
+
+ bool FindMatcher::IsMatch(const void* dicom,
+ uint32_t size) const
+ {
+ int32_t result;
+
+ if (matcher_ != NULL)
+ {
+ result = OrthancPluginFindMatcherIsMatch(context_, matcher_, dicom, size);
+ }
+ else if (worklist_ != NULL)
+ {
+ result = OrthancPluginWorklistIsMatch(context_, worklist_, dicom, size);
+ }
+ else
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
+ }
+
+ if (result == 0)
+ {
+ return false;
+ }
+ else if (result == 1)
+ {
+ return true;
+ }
+ else
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InternalError);
+ }
+ }
+
+
+
+ bool RestApiGet(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ bool applyPlugins)
{
MemoryBuffer answer(context);
if (!answer.RestApiGet(uri, applyPlugins))
@@ -756,12 +927,12 @@ namespace OrthancPlugins
}
- bool RestApiPostJson(Json::Value& result,
- OrthancPluginContext* context,
- const std::string& uri,
- const char* body,
- size_t bodySize,
- bool applyPlugins)
+ bool RestApiPost(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const char* body,
+ size_t bodySize,
+ bool applyPlugins)
{
MemoryBuffer answer(context);
if (!answer.RestApiPost(uri, body, bodySize, applyPlugins))
@@ -776,12 +947,23 @@ namespace OrthancPlugins
}
- bool RestApiPutJson(Json::Value& result,
- OrthancPluginContext* context,
- const std::string& uri,
- const char* body,
- size_t bodySize,
- bool applyPlugins)
+ bool RestApiPost(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const Json::Value& body,
+ bool applyPlugins)
+ {
+ Json::FastWriter writer;
+ return RestApiPost(result, context, uri, writer.write(body), applyPlugins);
+ }
+
+
+ bool RestApiPut(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const char* body,
+ size_t bodySize,
+ bool applyPlugins)
{
MemoryBuffer answer(context);
if (!answer.RestApiPut(uri, body, bodySize, applyPlugins))
@@ -796,6 +978,17 @@ namespace OrthancPlugins
}
+ bool RestApiPut(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const Json::Value& body,
+ bool applyPlugins)
+ {
+ Json::FastWriter writer;
+ return RestApiPut(result, context, uri, writer.write(body), applyPlugins);
+ }
+
+
bool RestApiDelete(OrthancPluginContext* context,
const std::string& uri,
bool applyPlugins)
@@ -822,7 +1015,99 @@ namespace OrthancPlugins
}
else
{
- throw PluginException(error);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(error);
+ }
+ }
+
+
+ static void ReportIncompatibleVersion(OrthancPluginContext* context,
+ unsigned int major,
+ unsigned int minor,
+ unsigned int revision)
+ {
+ char buf[128];
+ sprintf(buf, "Your version of the Orthanc core (%s) is too old to run this plugin (%d.%d.%d is required)",
+ context->orthancVersion, major, minor, revision);
+ OrthancPluginLogError(context, buf);
+ }
+
+
+ bool CheckMinimalOrthancVersion(OrthancPluginContext* context,
+ unsigned int major,
+ unsigned int minor,
+ unsigned int revision)
+ {
+ if (context == NULL)
+ {
+ OrthancPluginLogError(context, "Bad Orthanc context in the plugin");
+ return false;
+ }
+
+ if (!strcmp(context->orthancVersion, "mainline"))
+ {
+ // Assume compatibility with the mainline
+ return true;
+ }
+
+ // Parse the version of the Orthanc core
+ int aa, bb, cc;
+ if (
+#ifdef _MSC_VER
+ sscanf_s
+#else
+ sscanf
+#endif
+ (context->orthancVersion, "%4d.%4d.%4d", &aa, &bb, &cc) != 3 ||
+ aa < 0 ||
+ bb < 0 ||
+ cc < 0)
+ {
+ throw false;
+ }
+
+ unsigned int a = static_cast<unsigned int>(aa);
+ unsigned int b = static_cast<unsigned int>(bb);
+ unsigned int c = static_cast<unsigned int>(cc);
+
+ // Check the major version number
+
+ if (a > major)
+ {
+ return true;
+ }
+
+ if (a < major)
+ {
+ ReportIncompatibleVersion(context, major, minor, revision);
+ return false;
+ }
+
+
+ // Check the minor version number
+ assert(a == major);
+
+ if (b > minor)
+ {
+ return true;
+ }
+
+ if (b < minor)
+ {
+ ReportIncompatibleVersion(context, major, minor, revision);
+ return false;
+ }
+
+ // Check the patch level version number
+ assert(a == major && b == minor);
+
+ if (c >= revision)
+ {
+ return true;
+ }
+ else
+ {
+ ReportIncompatibleVersion(context, major, minor, revision);
+ return false;
}
}
}
diff --git a/Plugins/Samples/Common/OrthancPluginCppWrapper.h b/Plugins/Samples/Common/OrthancPluginCppWrapper.h
index 2b9966f..bbb69e8 100644
--- a/Plugins/Samples/Common/OrthancPluginCppWrapper.h
+++ b/Plugins/Samples/Common/OrthancPluginCppWrapper.h
@@ -37,18 +37,30 @@
#include <boost/lexical_cast.hpp>
#include <json/value.h>
+#if !defined(HAS_ORTHANC_EXCEPTION)
+# error The macro HAS_ORTHANC_EXCEPTION must be defined
+#endif
+
+
#if HAS_ORTHANC_EXCEPTION == 1
-# include <OrthancException.h>
+# include "../../../Core/OrthancException.h"
+# define ORTHANC_PLUGINS_THROW_EXCEPTION(code) throw ::Orthanc::OrthancException(static_cast<Orthanc::ErrorCode>(code))
+#else
+# define ORTHANC_PLUGINS_THROW_EXCEPTION(code) throw ::OrthancPlugins::PluginException(code)
#endif
+
namespace OrthancPlugins
{
typedef void (*RestCallback) (OrthancPluginRestOutput* output,
const char* url,
const OrthancPluginHttpRequest* request);
+ const char* GetErrorDescription(OrthancPluginContext* context,
+ OrthancPluginErrorCode code);
+#if HAS_ORTHANC_EXCEPTION == 0
class PluginException
{
private:
@@ -64,8 +76,14 @@ namespace OrthancPlugins
return code_;
}
- const char* GetErrorDescription(OrthancPluginContext* context) const;
+ const char* What(OrthancPluginContext* context) const
+ {
+ return ::OrthancPlugins::GetErrorDescription(context, code_);
+ }
+
+ static void Check(OrthancPluginErrorCode code);
};
+#endif
class MemoryBuffer : public boost::noncopyable
@@ -74,6 +92,8 @@ namespace OrthancPlugins
OrthancPluginContext* context_;
OrthancPluginMemoryBuffer buffer_;
+ void Check(OrthancPluginErrorCode code);
+
public:
MemoryBuffer(OrthancPluginContext* context);
@@ -127,6 +147,14 @@ namespace OrthancPlugins
bool applyPlugins);
bool RestApiPost(const std::string& uri,
+ const Json::Value& body,
+ bool applyPlugins);
+
+ bool RestApiPut(const std::string& uri,
+ const Json::Value& body,
+ bool applyPlugins);
+
+ bool RestApiPost(const std::string& uri,
const std::string& body,
bool applyPlugins)
{
@@ -139,6 +167,18 @@ namespace OrthancPlugins
{
return RestApiPut(uri, body.empty() ? NULL : body.c_str(), body.size(), applyPlugins);
}
+
+ void CreateDicom(const Json::Value& tags,
+ OrthancPluginCreateDicomFlags flags);
+
+ void ReadFile(const std::string& path);
+
+ void GetDicomQuery(const OrthancPluginWorklistQuery* query);
+
+ void DicomToJson(Json::Value& target,
+ OrthancPluginDicomToJsonFormat format,
+ OrthancPluginDicomToJsonFlags flags,
+ uint32_t maxStringLength);
};
@@ -148,16 +188,23 @@ namespace OrthancPlugins
OrthancPluginContext* context_;
char* str_;
+ void Clear();
+
public:
- OrthancString(OrthancPluginContext* context,
- char* str);
+ OrthancString(OrthancPluginContext* context) :
+ context_(context),
+ str_(NULL)
+ {
+ }
~OrthancString()
{
Clear();
}
- void Clear();
+ // This transfers ownership, warning: The string must have been
+ // allocated by the Orthanc core
+ void Assign(char* str);
const char* GetContent() const
{
@@ -174,7 +221,7 @@ namespace OrthancPlugins
{
private:
OrthancPluginContext* context_;
- Json::Value configuration_;
+ Json::Value configuration_; // Necessarily a Json::objectValue
std::string path_;
std::string GetPath(const std::string& key) const;
@@ -193,6 +240,8 @@ namespace OrthancPlugins
return configuration_;
}
+ bool IsSection(const std::string& key) const;
+
void GetSection(OrthancConfiguration& target,
const std::string& key) const;
@@ -227,7 +276,7 @@ namespace OrthancPlugins
float defaultValue) const;
};
- class OrthancImage
+ class OrthancImage : public boost::noncopyable
{
private:
OrthancPluginContext* context_;
@@ -285,52 +334,132 @@ namespace OrthancPlugins
};
- bool RestApiGetJson(Json::Value& result,
- OrthancPluginContext* context,
- const std::string& uri,
- bool applyPlugins);
-
- bool RestApiPostJson(Json::Value& result,
- OrthancPluginContext* context,
- const std::string& uri,
- const char* body,
- size_t bodySize,
- bool applyPlugins);
-
- bool RestApiPutJson(Json::Value& result,
- OrthancPluginContext* context,
- const std::string& uri,
- const char* body,
- size_t bodySize,
- bool applyPlugins);
-
- inline bool RestApiPostJson(Json::Value& result,
- OrthancPluginContext* context,
- const std::string& uri,
- const std::string& body,
- bool applyPlugins)
+ class FindMatcher : public boost::noncopyable
+ {
+ private:
+ OrthancPluginContext* context_;
+ OrthancPluginFindMatcher* matcher_;
+ const OrthancPluginWorklistQuery* worklist_;
+
+ void SetupDicom(OrthancPluginContext* context,
+ const void* query,
+ uint32_t size);
+
+ public:
+ FindMatcher(OrthancPluginContext* context,
+ const OrthancPluginWorklistQuery* worklist);
+
+ FindMatcher(OrthancPluginContext* context,
+ const void* query,
+ uint32_t size)
+ {
+ SetupDicom(context, query, size);
+ }
+
+ FindMatcher(OrthancPluginContext* context,
+ const MemoryBuffer& dicom)
+ {
+ SetupDicom(context, dicom.GetData(), dicom.GetSize());
+ }
+
+ ~FindMatcher();
+
+ bool IsMatch(const void* dicom,
+ uint32_t size) const;
+
+ bool IsMatch(const MemoryBuffer& dicom) const
+ {
+ return IsMatch(dicom.GetData(), dicom.GetSize());
+ }
+ };
+
+
+ bool RestApiGet(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ bool applyPlugins);
+
+ bool RestApiPost(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const char* body,
+ size_t bodySize,
+ bool applyPlugins);
+
+ bool RestApiPost(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const Json::Value& body,
+ bool applyPlugins);
+
+ inline bool RestApiPost(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const std::string& body,
+ bool applyPlugins)
{
- return RestApiPostJson(result, context, uri, body.empty() ? NULL : body.c_str(),
- body.size(), applyPlugins);
+ return RestApiPost(result, context, uri, body.empty() ? NULL : body.c_str(),
+ body.size(), applyPlugins);
+ }
+
+ bool RestApiPut(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const char* body,
+ size_t bodySize,
+ bool applyPlugins);
+
+ bool RestApiPut(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const Json::Value& body,
+ bool applyPlugins);
+
+ inline bool RestApiPut(Json::Value& result,
+ OrthancPluginContext* context,
+ const std::string& uri,
+ const std::string& body,
+ bool applyPlugins)
+ {
+ return RestApiPut(result, context, uri, body.empty() ? NULL : body.c_str(),
+ body.size(), applyPlugins);
}
bool RestApiDelete(OrthancPluginContext* context,
const std::string& uri,
bool applyPlugins);
- inline bool RestApiPutJson(Json::Value& result,
- OrthancPluginContext* context,
- const std::string& uri,
- const std::string& body,
- bool applyPlugins)
+ inline void LogError(OrthancPluginContext* context,
+ const std::string& message)
{
- return RestApiPutJson(result, context, uri, body.empty() ? NULL : body.c_str(),
- body.size(), applyPlugins);
+ if (context != NULL)
+ {
+ OrthancPluginLogError(context, message.c_str());
+ }
}
- bool RestApiDelete(OrthancPluginContext* context,
- const std::string& uri,
- bool applyPlugins);
+ inline void LogWarning(OrthancPluginContext* context,
+ const std::string& message)
+ {
+ if (context != NULL)
+ {
+ OrthancPluginLogWarning(context, message.c_str());
+ }
+ }
+
+ inline void LogInfo(OrthancPluginContext* context,
+ const std::string& message)
+ {
+ if (context != NULL)
+ {
+ OrthancPluginLogInfo(context, message.c_str());
+ }
+ }
+
+ bool CheckMinimalOrthancVersion(OrthancPluginContext* context,
+ unsigned int major,
+ unsigned int minor,
+ unsigned int revision);
namespace Internals
@@ -345,17 +474,18 @@ namespace OrthancPlugins
Callback(output, url, request);
return OrthancPluginErrorCode_Success;
}
- catch (OrthancPlugins::PluginException& e)
- {
- return e.GetErrorCode();
- }
#if HAS_ORTHANC_EXCEPTION == 1
catch (Orthanc::OrthancException& e)
{
return static_cast<OrthancPluginErrorCode>(e.GetErrorCode());
}
+#else
+ catch (OrthancPlugins::PluginException& e)
+ {
+ return e.GetErrorCode();
+ }
#endif
- catch (boost::bad_lexical_cast& e)
+ catch (boost::bad_lexical_cast&)
{
return OrthancPluginErrorCode_BadFileFormat;
}
diff --git a/Plugins/Samples/Common/OrthancPlugins.cmake b/Plugins/Samples/Common/OrthancPlugins.cmake
index d7228a1..90f5224 100644
--- a/Plugins/Samples/Common/OrthancPlugins.cmake
+++ b/Plugins/Samples/Common/OrthancPlugins.cmake
@@ -17,7 +17,7 @@ endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
# Linking with "pthread" is necessary, otherwise the software crashes
# http://sourceware.org/bugzilla/show_bug.cgi?id=10652#c17
- link_libraries(dl rt)
+ link_libraries(dl rt pthread)
endif()
@@ -27,3 +27,6 @@ include_directories(${SAMPLES_ROOT}/../Include/)
if (MSVC)
include_directories(${SAMPLES_ROOT}/../../Resources/ThirdParty/VisualStudio/)
endif()
+
+
+add_definitions(-DHAS_ORTHANC_EXCEPTION=0)
diff --git a/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp b/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp
new file mode 100644
index 0000000..1fa2bea
--- /dev/null
+++ b/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp
@@ -0,0 +1,156 @@
+/**
+ * Orthanc - A Lightweight, RESTful DICOM Store
+ * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics
+ * Department, University Hospital of Liege, Belgium
+ *
+ * This program is free software: you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License as
+ * published by the Free Software Foundation, either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * In addition, as a special exception, the copyright holders of this
+ * program give permission to link the code of its release with the
+ * OpenSSL project's "OpenSSL" library (or with modified versions of it
+ * that use the same license as the "OpenSSL" library), and distribute
+ * the linked executables. You must obey the GNU General Public License
+ * in all respects for all of the code used other than "OpenSSL". If you
+ * modify file(s) with this exception, you may extend this exception to
+ * your version of the file(s), but you are not obligated to do so. If
+ * you do not wish to do so, delete this exception statement from your
+ * version. If you delete this exception statement from all source files
+ * in the program, then also delete it here.
+ *
+ * This program is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ **/
+
+
+#include "SimplifiedOrthancDataset.h"
+
+#include "OrthancPluginCppWrapper.h"
+
+namespace OrthancPlugins
+{
+ const Json::Value* SimplifiedOrthancDataset::LookupPath(const DicomPath& path) const
+ {
+ const Json::Value* content = &root_;
+
+ for (unsigned int depth = 0; depth < path.GetPrefixLength(); depth++)
+ {
+ const char* name = path.GetPrefixTag(depth).GetName();
+ if (content->type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ if (!content->isMember(name))
+ {
+ return NULL;
+ }
+
+ const Json::Value& sequence = (*content) [name];
+ if (sequence.type() != Json::arrayValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ size_t index = path.GetPrefixIndex(depth);
+ if (index >= sequence.size())
+ {
+ return NULL;
+ }
+ else
+ {
+ content = &sequence[static_cast<Json::Value::ArrayIndex>(index)];
+ }
+ }
+
+ const char* name = path.GetFinalTag().GetName();
+
+ if (content->type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ if (!content->isMember(name))
+ {
+ return NULL;
+ }
+ else
+ {
+ return &((*content) [name]);
+ }
+ }
+
+
+ void SimplifiedOrthancDataset::CheckRoot() const
+ {
+ if (root_.type() != Json::objectValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ }
+
+
+ SimplifiedOrthancDataset::SimplifiedOrthancDataset(IOrthancConnection& orthanc,
+ const std::string& uri)
+ {
+ IOrthancConnection::RestApiGet(root_, orthanc, uri);
+ CheckRoot();
+ }
+
+
+ SimplifiedOrthancDataset::SimplifiedOrthancDataset(const std::string& content)
+ {
+ IOrthancConnection::ParseJson(root_, content);
+ CheckRoot();
+ }
+
+
+ bool SimplifiedOrthancDataset::GetStringValue(std::string& result,
+ const DicomPath& path) const
+ {
+ const Json::Value* value = LookupPath(path);
+
+ if (value == NULL)
+ {
+ return false;
+ }
+ else if (value->type() != Json::stringValue)
+ {
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ else
+ {
+ result = value->asString();
+ return true;
+ }
+ }
+
+
+ bool SimplifiedOrthancDataset::GetSequenceSize(size_t& size,
+ const DicomPath& path) const
+ {
+ const Json::Value* sequence = LookupPath(path);
+
+ if (sequence == NULL)
+ {
+ // Inexistent path
+ return false;
+ }
+ else if (sequence->type() != Json::arrayValue)
+ {
+ // Not a sequence
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+ else
+ {
+ size = sequence->size();
+ return true;
+ }
+ }
+}
diff --git a/Core/Images/PngReader.h b/Plugins/Samples/Common/SimplifiedOrthancDataset.h
similarity index 71%
copy from Core/Images/PngReader.h
copy to Plugins/Samples/Common/SimplifiedOrthancDataset.h
index b6ad811..a71e1e0 100644
--- a/Core/Images/PngReader.h
+++ b/Plugins/Samples/Common/SimplifiedOrthancDataset.h
@@ -32,38 +32,30 @@
#pragma once
-#include "ImageAccessor.h"
+#include "IOrthancConnection.h"
+#include "IDicomDataset.h"
-#include "../Enumerations.h"
-
-#include <vector>
-#include <stdint.h>
-#include <boost/shared_ptr.hpp>
-#include <boost/noncopyable.hpp>
-
-namespace Orthanc
+namespace OrthancPlugins
{
- class PngReader :
- public ImageAccessor,
- public boost::noncopyable
+ class SimplifiedOrthancDataset : public IDicomDataset
{
private:
- struct PngRabi;
-
- std::vector<uint8_t> data_;
+ Json::Value root_;
- void CheckHeader(const void* header);
+ const Json::Value* LookupPath(const DicomPath& path) const;
- void Read(PngRabi& rabi);
+ void CheckRoot() const;
public:
- PngReader();
+ SimplifiedOrthancDataset(IOrthancConnection& orthanc,
+ const std::string& uri);
- void ReadFromFile(const std::string& filename);
+ SimplifiedOrthancDataset(const std::string& content);
- void ReadFromMemory(const void* buffer,
- size_t size);
+ virtual bool GetStringValue(std::string& result,
+ const DicomPath& path) const;
- void ReadFromMemory(const std::string& buffer);
+ virtual bool GetSequenceSize(size_t& size,
+ const DicomPath& path) const;
};
}
diff --git a/Plugins/Samples/DatabasePlugin/CMakeLists.txt b/Plugins/Samples/DatabasePlugin/CMakeLists.txt
index be977d0..11c6cfd 100644
--- a/Plugins/Samples/DatabasePlugin/CMakeLists.txt
+++ b/Plugins/Samples/DatabasePlugin/CMakeLists.txt
@@ -29,11 +29,12 @@ message("Setting the version of the plugin to ${SAMPLE_DATABASE_VERSION}")
add_definitions(
-DORTHANC_SQLITE_STANDALONE=1
- -DORTHANC_ENABLE_LOGGING=0
-DORTHANC_ENABLE_BASE64=0
+ -DORTHANC_ENABLE_LOGGING=0
-DORTHANC_ENABLE_MD5=0
- -DORTHANC_ENABLE_DCMTK=0
- -DORTHANC_PLUGINS_ENABLED=1
+ -DORTHANC_ENABLE_PLUGINS=1
+ -DORTHANC_ENABLE_PUGIXML=0
+ -DORTHANC_SANDBOXED=0
-DSAMPLE_DATABASE_VERSION="${SAMPLE_DATABASE_VERSION}"
)
diff --git a/Plugins/Samples/ModalityWorklists/CMakeLists.txt b/Plugins/Samples/ModalityWorklists/CMakeLists.txt
index eee38f1..fcf6606 100644
--- a/Plugins/Samples/ModalityWorklists/CMakeLists.txt
+++ b/Plugins/Samples/ModalityWorklists/CMakeLists.txt
@@ -16,6 +16,7 @@ include(${ORTHANC_ROOT}/Resources/CMake/BoostConfiguration.cmake)
add_library(ModalityWorklists SHARED
Plugin.cpp
+ ../Common/OrthancPluginCppWrapper.cpp
${JSONCPP_SOURCES}
${BOOST_SOURCES}
)
diff --git a/Plugins/Samples/ModalityWorklists/Plugin.cpp b/Plugins/Samples/ModalityWorklists/Plugin.cpp
index f68fc29..8aebfa8 100644
--- a/Plugins/Samples/ModalityWorklists/Plugin.cpp
+++ b/Plugins/Samples/ModalityWorklists/Plugin.cpp
@@ -18,7 +18,7 @@
**/
-#include <orthanc/OrthancCPlugin.h>
+#include "../Common/OrthancPluginCppWrapper.h"
#include <boost/filesystem.hpp>
#include <json/value.h>
@@ -31,92 +31,99 @@ static OrthancPluginContext* context_ = NULL;
static std::string folder_;
-static bool ReadFile(std::string& result,
- const std::string& path)
-{
- OrthancPluginMemoryBuffer tmp;
- if (OrthancPluginReadFile(context_, &tmp, path.c_str()))
- {
- return false;
- }
- else
- {
- result.assign(reinterpret_cast<const char*>(tmp.data), tmp.size);
- OrthancPluginFreeMemoryBuffer(context_, &tmp);
- return true;
- }
-}
-
-
/**
* This is the main function for matching a DICOM worklist against a query.
**/
-static OrthancPluginErrorCode MatchWorklist(OrthancPluginWorklistAnswers* answers,
- const OrthancPluginWorklistQuery* query,
- const std::string& path)
+static void MatchWorklist(OrthancPluginWorklistAnswers* answers,
+ const OrthancPluginWorklistQuery* query,
+ const OrthancPlugins::FindMatcher& matcher,
+ const std::string& path)
{
- std::string dicom;
- if (!ReadFile(dicom, path))
- {
- // Cannot read this file, ignore this error
- return OrthancPluginErrorCode_Success;
- }
+ OrthancPlugins::MemoryBuffer dicom(context_);
+ dicom.ReadFile(path);
- if (OrthancPluginWorklistIsMatch(context_, query, dicom.c_str(), dicom.size()))
+ if (matcher.IsMatch(dicom))
{
// This DICOM file matches the worklist query, add it to the answers
- return OrthancPluginWorklistAddAnswer
- (context_, answers, query, dicom.c_str(), dicom.size());
- }
- else
- {
- // This DICOM file does not match
- return OrthancPluginErrorCode_Success;
+ OrthancPluginErrorCode code = OrthancPluginWorklistAddAnswer
+ (context_, answers, query, dicom.GetData(), dicom.GetSize());
+
+ if (code != OrthancPluginErrorCode_Success)
+ {
+ OrthancPlugins::LogError(context_, "Error while adding an answer to a worklist request");
+ ORTHANC_PLUGINS_THROW_EXCEPTION(code);
+ }
}
}
-
-static bool ConvertToJson(Json::Value& result,
- char* content)
+static OrthancPlugins::FindMatcher* CreateMatcher(const OrthancPluginWorklistQuery* query,
+ const char* remoteAet)
{
- if (content == NULL)
+ // Extract the DICOM instance underlying the C-Find query
+ OrthancPlugins::MemoryBuffer dicom(context_);
+ dicom.GetDicomQuery(query);
+
+ // Convert the DICOM as JSON, and dump it to the user in "--verbose" mode
+ Json::Value json;
+ dicom.DicomToJson(json, OrthancPluginDicomToJsonFormat_Short,
+ static_cast<OrthancPluginDicomToJsonFlags>(0), 0);
+
+ OrthancPlugins::LogInfo(context_, "Received worklist query from remote modality " +
+ std::string(remoteAet) + ":\n" + json.toStyledString());
+
+#if 1
+ return new OrthancPlugins::FindMatcher(context_, query);
+
+#else
+ // Alternative sample showing how to fine-tune an incoming C-Find
+ // request, before matching it against the worklist database. The
+ // code below will restrict the original DICOM request by requesting
+ // the ScheduledStationAETitle to correspond to the AET of the
+ // issuer. This code will make the integration test "test_other_aet"
+ // succeed (cf. the orthanc-tests repository).
+
+ static const char* SCHEDULED_PROCEDURE_STEP_SEQUENCE = "0040,0100";
+ static const char* SCHEDULED_STATION_AETITLE = "0040,0001";
+
+ if (!json.isMember(SCHEDULED_PROCEDURE_STEP_SEQUENCE))
{
- return false;
+ // Create a ScheduledProcedureStepSequence sequence, with one empty element
+ json[SCHEDULED_PROCEDURE_STEP_SEQUENCE] = Json::arrayValue;
+ json[SCHEDULED_PROCEDURE_STEP_SEQUENCE].append(Json::objectValue);
}
- else
+
+ Json::Value& v = json[SCHEDULED_PROCEDURE_STEP_SEQUENCE];
+
+ if (v.type() != Json::arrayValue ||
+ v.size() != 1 ||
+ v[0].type() != Json::objectValue)
{
- Json::Reader reader;
- bool success = reader.parse(content, content + strlen(content), result);
- OrthancPluginFreeString(context_, content);
- return success;
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
-}
-
-static bool GetQueryDicom(Json::Value& value,
- const OrthancPluginWorklistQuery* query)
-{
- OrthancPluginMemoryBuffer dicom;
- if (OrthancPluginWorklistGetDicomQuery(context_, &dicom, query))
+ // Set the ScheduledStationAETitle if none was provided
+ if (!v[0].isMember(SCHEDULED_STATION_AETITLE) ||
+ v[0].type() != Json::stringValue ||
+ v[0][SCHEDULED_STATION_AETITLE].asString().size() == 0 ||
+ v[0][SCHEDULED_STATION_AETITLE].asString() == "*")
{
- return false;
+ v[0][SCHEDULED_STATION_AETITLE] = remoteAet;
}
- char* json = OrthancPluginDicomBufferToJson(context_, reinterpret_cast<const char*>(dicom.data),
- dicom.size,
- OrthancPluginDicomToJsonFormat_Short,
- static_cast<OrthancPluginDicomToJsonFlags>(0), 0);
- OrthancPluginFreeMemoryBuffer(context_, &dicom);
+ if (json.isMember("0010,21c0") &&
+ json["0010,21c0"].asString().size() == 0)
+ {
+ json.removeMember("0010,21c0");
+ }
- return ConvertToJson(value, json);
+ // Encode the modified JSON as a DICOM instance, then convert it to a C-Find matcher
+ OrthancPlugins::MemoryBuffer modified(context_);
+ modified.CreateDicom(json, OrthancPluginCreateDicomFlags_None);
+ return new OrthancPlugins::FindMatcher(context_, modified);
+#endif
}
-
-static void ToLowerCase(std::string& s)
-{
- std::transform(s.begin(), s.end(), s.begin(), tolower);
-}
OrthancPluginErrorCode Callback(OrthancPluginWorklistAnswers* answers,
@@ -124,59 +131,52 @@ OrthancPluginErrorCode Callback(OrthancPluginWorklistAnswers* answers,
const char* remoteAet,
const char* calledAet)
{
- namespace fs = boost::filesystem;
-
- Json::Value json;
-
- if (!GetQueryDicom(json, query))
+ try
{
- return OrthancPluginErrorCode_InternalError;
- }
+ // Construct an object to match the worklists in the database against the C-Find query
+ std::auto_ptr<OrthancPlugins::FindMatcher> matcher(CreateMatcher(query, remoteAet));
- {
- std::string msg = ("Received worklist query from remote modality " +
- std::string(remoteAet) + ":\n" + json.toStyledString());
- OrthancPluginLogInfo(context_, msg.c_str());
- }
+ // Loop over the regular files in the database folder
+ namespace fs = boost::filesystem;
- fs::path source(folder_);
- fs::directory_iterator end;
+ fs::path source(folder_);
+ fs::directory_iterator end;
- try
- {
- for (fs::directory_iterator it(source); it != end; ++it)
+ try
{
- fs::file_type type(it->status().type());
-
- if (type == fs::regular_file ||
- type == fs::reparse_file) // cf. BitBucket issue #11
+ for (fs::directory_iterator it(source); it != end; ++it)
{
- std::string extension = fs::extension(it->path());
- ToLowerCase(extension);
+ fs::file_type type(it->status().type());
- if (extension == ".wl")
+ if (type == fs::regular_file ||
+ type == fs::reparse_file) // cf. BitBucket issue #11
{
- OrthancPluginErrorCode error = MatchWorklist(answers, query, it->path().string());
- if (error)
+ std::string extension = fs::extension(it->path());
+ std::transform(extension.begin(), extension.end(), extension.begin(), tolower); // Convert to lowercase
+
+ if (extension == ".wl")
{
- OrthancPluginLogError(context_, "Error while adding an answer to a worklist request");
- return error;
+ // We found a worklist (i.e. a DICOM find with extension ".wl"), match it against the query
+ MatchWorklist(answers, query, *matcher, it->path().string());
}
}
}
}
+ catch (fs::filesystem_error&)
+ {
+ OrthancPlugins::LogError(context_, "Inexistent folder while scanning for worklists: " + source.string());
+ return OrthancPluginErrorCode_DirectoryExpected;
+ }
+
+ // Uncomment the following line if too many answers are to be returned
+ // OrthancPluginMarkWorklistAnswersIncomplete(context_, answers);
+
+ return OrthancPluginErrorCode_Success;
}
- catch (fs::filesystem_error&)
+ catch (OrthancPlugins::PluginException& e)
{
- std::string description = std::string("Inexistent folder while scanning for worklists: ") + source.string();
- OrthancPluginLogError(context_, description.c_str());
- return OrthancPluginErrorCode_DirectoryExpected;
+ return e.GetErrorCode();
}
-
- // Uncomment the following line if too many answers are to be returned
- // OrthancPluginMarkWorklistAnswersIncomplete(context_, answers);
-
- return OrthancPluginErrorCode_Success;
}
@@ -185,8 +185,6 @@ extern "C"
ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* c)
{
context_ = c;
- OrthancPluginLogWarning(context_, "Sample worklist plugin is initializing");
- OrthancPluginSetDescription(context_, "Serve DICOM modality worklists from a folder with Orthanc.");
/* Check the version of the Orthanc core */
if (OrthancPluginCheckVersion(c) == 0)
@@ -201,55 +199,31 @@ extern "C"
return -1;
}
- Json::Value configuration;
- if (!ConvertToJson(configuration, OrthancPluginGetConfiguration(context_)))
- {
- OrthancPluginLogError(context_, "Cannot access the configuration of the worklist server");
- return -1;
- }
+ OrthancPlugins::LogWarning(context_, "Sample worklist plugin is initializing");
+ OrthancPluginSetDescription(context_, "Serve DICOM modality worklists from a folder with Orthanc.");
+
+ OrthancPlugins::OrthancConfiguration configuration(context_);
- bool enabled = false;
+ OrthancPlugins::OrthancConfiguration worklists;
+ configuration.GetSection(worklists, "Worklists");
- if (configuration.isMember("Worklists"))
+ bool enabled = worklists.GetBooleanValue("Enable", false);
+ if (enabled)
{
- const Json::Value& config = configuration["Worklists"];
- if (!config.isMember("Enable") ||
- config["Enable"].type() != Json::booleanValue)
+ if (worklists.LookupStringValue(folder_, "Database"))
{
- OrthancPluginLogError(context_, "The configuration option \"Worklists.Enable\" must contain a Boolean");
- return -1;
+ OrthancPlugins::LogWarning(context_, "The database of worklists will be read from folder: " + folder_);
+ OrthancPluginRegisterWorklistCallback(context_, Callback);
}
else
{
- enabled = config["Enable"].asBool();
- if (enabled)
- {
- if (!config.isMember("Database") ||
- config["Database"].type() != Json::stringValue)
- {
- OrthancPluginLogError(context_, "The configuration option \"Worklists.Database\" must contain a path");
- return -1;
- }
-
- folder_ = config["Database"].asString();
- }
- else
- {
- OrthancPluginLogWarning(context_, "Worklists server is disabled by the configuration file");
- }
+ OrthancPlugins::LogError(context_, "The configuration option \"Worklists.Database\" must contain a path");
+ return -1;
}
}
else
{
- OrthancPluginLogWarning(context_, "Worklists server is disabled, no suitable configuration section was provided");
- }
-
- if (enabled)
- {
- std::string message = "The database of worklists will be read from folder: " + folder_;
- OrthancPluginLogWarning(context_, message.c_str());
-
- OrthancPluginRegisterWorklistCallback(context_, Callback);
+ OrthancPlugins::LogWarning(context_, "Worklists server is disabled by the configuration file");
}
return 0;
diff --git a/Plugins/Samples/ModalityWorklists/README b/Plugins/Samples/ModalityWorklists/README
index 58ea61b..f54f4e0 100644
--- a/Plugins/Samples/ModalityWorklists/README
+++ b/Plugins/Samples/ModalityWorklists/README
@@ -4,57 +4,8 @@ Introduction
This sample plugin enables Orthanc to serve DICOM modality worklists
that are read from some folder.
-Whenever a C-Find SCP request is issued to Orthanc, it will read the
-content of this folder to locate the worklists that match the request.
-An external application can dynamically modify the content of this
-folder while Orthanc is running to add/remove worklists.
+The shared library containing the plugin is created as part of the
+build process of Orthanc.
-This sample mimics the behavior of the "wlmscpfs" tool from the
-DCMTK package:
-http://support.dcmtk.org/docs/wlmscpfs.html
-
-
-Compilation for Linux
-=====================
-
-# mkdir Build
-# cd Build
-# cmake ..
-# make
-
-
-Cross-compilation for Windows using MinGW
-=========================================
-
-# mkdir Build
-# cd Build
-# cmake .. -DCMAKE_TOOLCHAIN_FILE=../../../Resources/MinGWToolchain.cmake
-# make
-
-
-Configuration
-=============
-
-First, generate the default configuration of Orthanc:
-https://orthanc.chu.ulg.ac.be/book/users/configuration.html
-
-Then, modify the "Plugins" option to point to the folder containing
-the built plugins. Finally, create a section "ModalityWorklists" in
-the configuration file to configure the worklist server. If using the
-build commands above, a sample configuration would read as follows:
-
-{
- [...]
- "Plugins" : [
- "."
- ],
- "Worklists" : {
- "Enable": true,
- "Database": "../WorklistsDatabase"
- }
-}
-
-The folder "WorklistsDatabase" contains a database of sample
-worklists, that come from the DCMTK source distribution, as described
-in the FAQ entry #37 of the DCMTK project:
-http://forum.dcmtk.org/viewtopic.php?t=84
+Documentation is available in the Orthanc Book:
+http://book.orthanc-server.com/plugins/worklists-plugin.html
diff --git a/Plugins/Samples/ServeFolders/CMakeLists.txt b/Plugins/Samples/ServeFolders/CMakeLists.txt
index e9a3480..e9c611f 100644
--- a/Plugins/Samples/ServeFolders/CMakeLists.txt
+++ b/Plugins/Samples/ServeFolders/CMakeLists.txt
@@ -16,10 +16,13 @@ include(${ORTHANC_ROOT}/Resources/CMake/BoostConfiguration.cmake)
add_library(ServeFolders SHARED
Plugin.cpp
+ ${CMAKE_SOURCE_DIR}/../Common/OrthancPluginCppWrapper.cpp
${JSONCPP_SOURCES}
${BOOST_SOURCES}
)
+add_definitions(-DHAS_ORTHANC_EXCEPTION=0)
+
message("Setting the version of the plugin to ${SERVE_FOLDERS_VERSION}")
add_definitions(-DSERVE_FOLDERS_VERSION="${SERVE_FOLDERS_VERSION}")
diff --git a/Plugins/Samples/ServeFolders/Plugin.cpp b/Plugins/Samples/ServeFolders/Plugin.cpp
index 6772c83..6e8c64e 100644
--- a/Plugins/Samples/ServeFolders/Plugin.cpp
+++ b/Plugins/Samples/ServeFolders/Plugin.cpp
@@ -18,122 +18,81 @@
**/
-#include <orthanc/OrthancCPlugin.h>
+#include "../Common/OrthancPluginCppWrapper.h"
#include <json/reader.h>
#include <json/value.h>
#include <boost/filesystem.hpp>
+#include <boost/date_time/posix_time/posix_time.hpp>
+
+
+#if HAS_ORTHANC_EXCEPTION == 1
+# error The macro HAS_ORTHANC_EXCEPTION must be set to 0 to compile this plugin
+#endif
+
static OrthancPluginContext* context_ = NULL;
+static std::map<std::string, std::string> extensions_;
static std::map<std::string, std::string> folders_;
static const char* INDEX_URI = "/app/plugin-serve-folders.html";
+static bool allowCache_ = false;
+static bool generateETag_ = true;
-static const char* GetMimeType(const std::string& path)
+static void SetHttpHeaders(OrthancPluginRestOutput* output)
{
- size_t dot = path.find_last_of('.');
-
- std::string extension = (dot == std::string::npos) ? "" : path.substr(dot);
- std::transform(extension.begin(), extension.end(), extension.begin(), tolower);
-
- if (extension == ".html")
- {
- return "text/html";
- }
- else if (extension == ".css")
- {
- return "text/css";
- }
- else if (extension == ".js")
- {
- return "application/javascript";
- }
- else if (extension == ".gif")
- {
- return "image/gif";
- }
- else if (extension == ".svg")
- {
- return "image/svg+xml";
- }
- else if (extension == ".json")
- {
- return "application/json";
- }
- else if (extension == ".xml")
- {
- return "application/xml";
- }
- else if (extension == ".png")
- {
- return "image/png";
- }
- else if (extension == ".jpg" || extension == ".jpeg")
- {
- return "image/jpeg";
- }
- else if (extension == ".woff")
+ if (!allowCache_)
{
- return "application/x-font-woff";
- }
- else
- {
- std::string s = "Unknown MIME type for extension: " + extension;
- OrthancPluginLogWarning(context_, s.c_str());
- return "application/octet-stream";
+ // http://stackoverflow.com/a/2068407/881731
+ OrthancPluginSetHttpHeader(context_, output, "Cache-Control", "no-cache, no-store, must-revalidate");
+ OrthancPluginSetHttpHeader(context_, output, "Pragma", "no-cache");
+ OrthancPluginSetHttpHeader(context_, output, "Expires", "0");
}
}
-static bool ReadFile(std::string& target,
- const std::string& path)
+static void RegisterDefaultExtensions()
{
- OrthancPluginMemoryBuffer buffer;
- if (OrthancPluginReadFile(context_, &buffer, path.c_str()))
- {
- return false;
- }
- else
- {
- target.assign(reinterpret_cast<const char*>(buffer.data), buffer.size);
- OrthancPluginFreeMemoryBuffer(context_, &buffer);
- return true;
- }
+ extensions_["css"] = "text/css";
+ extensions_["gif"] = "image/gif";
+ extensions_["html"] = "text/html";
+ extensions_["jpeg"] = "image/jpeg";
+ extensions_["jpg"] = "image/jpeg";
+ extensions_["js"] = "application/javascript";
+ extensions_["json"] = "application/json";
+ extensions_["nexe"] = "application/x-nacl";
+ extensions_["nmf"] = "application/json";
+ extensions_["pexe"] = "application/x-pnacl";
+ extensions_["png"] = "image/png";
+ extensions_["svg"] = "image/svg+xml";
+ extensions_["woff"] = "application/x-font-woff";
+ extensions_["xml"] = "application/xml";
}
-static bool ReadConfiguration(Json::Value& configuration,
- OrthancPluginContext* context)
+static std::string GetMimeType(const std::string& path)
{
- std::string s;
+ size_t dot = path.find_last_of('.');
- {
- char* tmp = OrthancPluginGetConfiguration(context);
- if (tmp == NULL)
- {
- OrthancPluginLogError(context, "Error while retrieving the configuration from Orthanc");
- return false;
- }
+ std::string extension = (dot == std::string::npos) ? "" : path.substr(dot + 1);
+ std::transform(extension.begin(), extension.end(), extension.begin(), tolower);
- s.assign(tmp);
- OrthancPluginFreeString(context, tmp);
- }
+ std::map<std::string, std::string>::const_iterator found = extensions_.find(extension);
- Json::Reader reader;
- if (reader.parse(s, configuration))
+ if (found != extensions_.end() &&
+ !found->second.empty())
{
- return true;
+ return found->second;
}
else
{
- OrthancPluginLogError(context, "Unable to parse the configuration");
- return false;
+ OrthancPlugins::LogWarning(context_, "ServeFolders: Unknown MIME type for extension \"" + extension + "\"");
+ return "application/octet-stream";
}
}
-
static bool LookupFolder(std::string& folder,
OrthancPluginRestOutput* output,
const OrthancPluginHttpRequest* request)
@@ -143,8 +102,7 @@ static bool LookupFolder(std::string& folder,
std::map<std::string, std::string>::const_iterator found = folders_.find(uri);
if (found == folders_.end())
{
- std::string s = "Unknown URI in plugin server-folders: " + uri;
- OrthancPluginLogError(context_, s.c_str());
+ OrthancPlugins::LogError(context_, "Unknown URI in plugin server-folders: " + uri);
OrthancPluginSendHttpStatusCode(context_, output, 404);
return false;
}
@@ -156,16 +114,35 @@ static bool LookupFolder(std::string& folder,
}
-static OrthancPluginErrorCode FolderCallback(OrthancPluginRestOutput* output,
- const char* url,
- const OrthancPluginHttpRequest* request)
+static void Answer(OrthancPluginRestOutput* output,
+ const char* content,
+ size_t size,
+ const std::string& mime)
+{
+ if (generateETag_)
+ {
+ OrthancPlugins::OrthancString md5(context_);
+ md5.Assign(OrthancPluginComputeMd5(context_, content, size));
+
+ std::string etag = "\"" + std::string(md5.GetContent()) + "\"";
+ OrthancPluginSetHttpHeader(context_, output, "ETag", etag.c_str());
+ }
+
+ SetHttpHeaders(output);
+ OrthancPluginAnswerBuffer(context_, output, content, size, mime.c_str());
+}
+
+
+void ServeFolder(OrthancPluginRestOutput* output,
+ const char* url,
+ const OrthancPluginHttpRequest* request)
{
namespace fs = boost::filesystem;
if (request->method != OrthancPluginHttpMethod_Get)
{
OrthancPluginSendMethodNotAllowed(context_, output, "GET");
- return OrthancPluginErrorCode_Success;
+ return;
}
std::string folder;
@@ -212,40 +189,42 @@ static OrthancPluginErrorCode FolderCallback(OrthancPluginRestOutput* output,
s += " </body>\n";
s += "</html>\n";
- OrthancPluginAnswerBuffer(context_, output, s.c_str(), s.size(), "text/html");
+ Answer(output, s.c_str(), s.size(), "text/html");
}
else
{
std::string path = folder + "/" + item.string();
- const char* mime = GetMimeType(path);
+ std::string mime = GetMimeType(path);
- std::string s;
- if (ReadFile(s, path))
+ OrthancPlugins::MemoryBuffer content(context_);
+
+ try
{
- const char* resource = s.size() ? s.c_str() : NULL;
- OrthancPluginAnswerBuffer(context_, output, resource, s.size(), mime);
+ content.ReadFile(path);
}
- else
+ catch (...)
{
- std::string s = "Inexistent file in served folder: " + path;
- OrthancPluginLogError(context_, s.c_str());
- OrthancPluginSendHttpStatusCode(context_, output, 404);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InexistentFile);
}
+
+ boost::posix_time::ptime lastModification = boost::posix_time::from_time_t(fs::last_write_time(path));
+ std::string t = boost::posix_time::to_iso_string(lastModification);
+ OrthancPluginSetHttpHeader(context_, output, "Last-Modified", t.c_str());
+
+ Answer(output, content.GetData(), content.GetSize(), mime);
}
}
-
- return OrthancPluginErrorCode_Success;
}
-static OrthancPluginErrorCode ListServedFolders(OrthancPluginRestOutput* output,
- const char* url,
- const OrthancPluginHttpRequest* request)
+void ListServedFolders(OrthancPluginRestOutput* output,
+ const char* url,
+ const OrthancPluginHttpRequest* request)
{
if (request->method != OrthancPluginHttpMethod_Get)
{
OrthancPluginSendMethodNotAllowed(context_, output, "GET");
- return OrthancPluginErrorCode_Success;
+ return;
}
std::string s = "<html><body><h1>Additional folders served by Orthanc</h1>\n";
@@ -269,102 +248,197 @@ static OrthancPluginErrorCode ListServedFolders(OrthancPluginRestOutput* output,
s += "</body></html>\n";
- OrthancPluginAnswerBuffer(context_, output, s.c_str(), s.size(), "text/html");
+ Answer(output, s.c_str(), s.size(), "text/html");
+}
+
+
+static void ConfigureFolders(const Json::Value& folders)
+{
+ if (folders.type() != Json::objectValue)
+ {
+ OrthancPlugins::LogError(context_, "The list of folders to be served is badly formatted (must be a JSON object)");
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ Json::Value::Members members = folders.getMemberNames();
+
+ // Register the callback for each base URI
+ for (Json::Value::Members::const_iterator
+ it = members.begin(); it != members.end(); ++it)
+ {
+ if (folders[*it].type() != Json::stringValue)
+ {
+ OrthancPlugins::LogError(context_, "The folder to be served \"" + *it +
+ "\" must be associated with a string value (its mapped URI)");
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ std::string baseUri = *it;
+
+ // Remove the heading and trailing slashes in the root URI, if any
+ while (!baseUri.empty() &&
+ *baseUri.begin() == '/')
+ {
+ baseUri = baseUri.substr(1);
+ }
+
+ while (!baseUri.empty() &&
+ *baseUri.rbegin() == '/')
+ {
+ baseUri.resize(baseUri.size() - 1);
+ }
+
+ if (baseUri.empty())
+ {
+ OrthancPlugins::LogError(context_, "The URI of a folder to be served cannot be empty");
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
+
+ // Check whether the source folder exists and is indeed a directory
+ const std::string folder = folders[*it].asString();
+ if (!boost::filesystem::is_directory(folder))
+ {
+ OrthancPlugins::LogError(context_, "Trying and serve an inexistent folder: " + folder);
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_InexistentFile);
+ }
- return OrthancPluginErrorCode_Success;
+ folders_[baseUri] = folder;
+
+ // Register the callback to serve the folder
+ {
+ const std::string regex = "/(" + baseUri + ")/(.*)";
+ OrthancPlugins::RegisterRestCallback<ServeFolder>(context_, regex.c_str(), true);
+ }
+ }
}
-extern "C"
+static void ConfigureExtensions(const Json::Value& extensions)
{
- ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
+ if (extensions.type() != Json::objectValue)
{
- context_ = context;
+ OrthancPlugins::LogError(context_, "The list of extensions is badly formatted (must be a JSON object)");
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
+ }
- /* Check the version of the Orthanc core */
- if (OrthancPluginCheckVersion(context_) == 0)
+ Json::Value::Members members = extensions.getMemberNames();
+
+ for (Json::Value::Members::const_iterator
+ it = members.begin(); it != members.end(); ++it)
+ {
+ if (extensions[*it].type() != Json::stringValue)
{
- char info[1024];
- sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin",
- context_->orthancVersion,
- ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER,
- ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER,
- ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);
- OrthancPluginLogError(context_, info);
- return -1;
+ OrthancPlugins::LogError(context_, "The file extension \"" + *it +
+ "\" must be associated with a string value (its MIME type)");
+ ORTHANC_PLUGINS_THROW_EXCEPTION(OrthancPluginErrorCode_BadFileFormat);
}
- OrthancPluginSetDescription(context_, "Serve additional folders with the HTTP server of Orthanc.");
+ const std::string& mime = extensions[*it].asString();
+
+ std::string name = *it;
- Json::Value configuration;
- if (!ReadConfiguration(configuration, context_))
+ if (!name.empty() &&
+ name[0] == '.')
{
- return -1;
+ name = name.substr(1); // Remove the leading dot "."
}
- if (configuration.isMember("ServeFolders"))
+ extensions_[name] = mime;
+
+ if (mime.empty())
{
- if (configuration["ServeFolders"].type() != Json::objectValue)
- {
- OrthancPluginLogError(context_, "The \"ServeFolders\" configuration section is badly formatted (must be a JSON object)");
- return -1;
- }
+ OrthancPlugins::LogWarning(context_, "ServeFolders: Removing MIME type for file extension \"." + name + "\"");
}
else
{
- OrthancPluginLogWarning(context_, "No section \"ServeFolders\" in your configuration file: "
- "No additional folder will be served!");
- configuration["ServeFolders"] = Json::objectValue;
+ OrthancPlugins::LogWarning(context_, "ServeFolders: Associating file extension \"." + name +
+ "\" with MIME type \"" + mime + "\"");
}
+ }
+}
- Json::Value::Members members = configuration["ServeFolders"].getMemberNames();
+static void ReadConfiguration()
+{
+ OrthancPlugins::OrthancConfiguration configuration;
+
+ {
+ OrthancPlugins::OrthancConfiguration globalConfiguration(context_);
+ globalConfiguration.GetSection(configuration, "ServeFolders");
+ }
+
+ if (!configuration.IsSection("Folders"))
+ {
+ // This is a basic configuration
+ ConfigureFolders(configuration.GetJson());
+ }
+ else
+ {
+ // This is an advanced configuration
+ ConfigureFolders(configuration.GetJson()["Folders"]);
+
+ bool tmp;
- // Register the callback for each base URI
- for (Json::Value::Members::const_iterator
- it = members.begin(); it != members.end(); ++it)
+ if (configuration.LookupBooleanValue(tmp, "AllowCache"))
{
- std::string baseUri = *it;
+ allowCache_ = tmp;
+ OrthancPlugins::LogWarning(context_, "ServeFolders: Requesting the HTTP client to " +
+ std::string(tmp ? "enable" : "disable") +
+ " its caching mechanism");
+ }
- // Remove the heading and trailing slashes in the root URI, if any
- while (!baseUri.empty() &&
- *baseUri.begin() == '/')
- {
- baseUri = baseUri.substr(1);
- }
+ if (configuration.LookupBooleanValue(tmp, "GenerateETag"))
+ {
+ generateETag_ = tmp;
+ OrthancPlugins::LogWarning(context_, "ServeFolders: The computation of an ETag for the served resources is " +
+ std::string(tmp ? "enabled" : "disabled"));
+ }
- while (!baseUri.empty() &&
- *baseUri.rbegin() == '/')
- {
- baseUri.resize(baseUri.size() - 1);
- }
+ OrthancPlugins::OrthancConfiguration extensions;
+ configuration.GetSection(extensions, "Extensions");
+ ConfigureExtensions(extensions.GetJson());
+ }
- if (baseUri.empty())
- {
- OrthancPluginLogError(context_, "The URI of a folder to be served cannot be empty");
- return -1;
- }
+ if (folders_.empty())
+ {
+ OrthancPlugins::LogWarning(context_, "ServeFolders: Empty configuration file: No additional folder will be served!");
+ }
+}
- // Check whether the source folder exists and is indeed a directory
- const std::string folder = configuration["ServeFolders"][*it].asString();
- if (!boost::filesystem::is_directory(folder))
- {
- std::string msg = "Trying and serve an inexistent folder: " + folder;
- OrthancPluginLogError(context_, msg.c_str());
- return -1;
- }
- folders_[baseUri] = folder;
+extern "C"
+{
+ ORTHANC_PLUGINS_API int32_t OrthancPluginInitialize(OrthancPluginContext* context)
+ {
+ context_ = context;
- // Register the callback to serve the folder
- {
- const std::string regex = "/(" + baseUri + ")/(.*)";
- OrthancPluginRegisterRestCallback(context, regex.c_str(), FolderCallback);
- }
+ /* Check the version of the Orthanc core */
+ if (OrthancPluginCheckVersion(context_) == 0)
+ {
+ char info[1024];
+ sprintf(info, "Your version of Orthanc (%s) must be above %d.%d.%d to run this plugin",
+ context_->orthancVersion,
+ ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER,
+ ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER,
+ ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER);
+ OrthancPluginLogError(context_, info);
+ return -1;
}
- OrthancPluginRegisterRestCallback(context, INDEX_URI, ListServedFolders);
+ RegisterDefaultExtensions();
+ OrthancPluginSetDescription(context_, "Serve additional folders with the HTTP server of Orthanc.");
OrthancPluginSetRootUri(context, INDEX_URI);
+ OrthancPlugins::RegisterRestCallback<ListServedFolders>(context_, INDEX_URI, true);
+
+ try
+ {
+ ReadConfiguration();
+ }
+ catch (OrthancPlugins::PluginException& e)
+ {
+ OrthancPlugins::LogError(context_, "Error while initializing the ServeFolders plugin: " +
+ std::string(e.What(context_)));
+ }
return 0;
}
diff --git a/Plugins/Samples/ServeFolders/README b/Plugins/Samples/ServeFolders/README
index 3ba1f84..ed50f3f 100644
--- a/Plugins/Samples/ServeFolders/README
+++ b/Plugins/Samples/ServeFolders/README
@@ -1,52 +1,11 @@
-Introduction
-============
+ServeFolders plugin
+===================
This sample plugin enables Orthanc to serve additional folders using
its embedded Web server.
+The shared library containing the plugin is created as part of the
+build process of Orthanc.
-Compilation for Linux
-=====================
-
-# mkdir Build
-# cd Build
-# cmake ..
-# make
-
-
-Cross-compilation for Windows using MinGW
-=========================================
-
-# mkdir Build
-# cd Build
-# cmake .. -DCMAKE_TOOLCHAIN_FILE=../../../Resources/MinGWToolchain.cmake
-# make
-
-
-Configuration
-=============
-
-First, generate the default configuration of Orthanc:
-https://orthanc.chu.ulg.ac.be/book/users/configuration.html
-
-Then, modify the "Plugins" option to point to the folder containing
-the built plugins.
-
-Finally, create a section "ServeFolders" in the configuration file to
-specify which folder you want to serve, and at which URI. For
-instance, the following excerpt would load the plugins from the
-working directory, then would branch the content of the folder
-"/home/jodogne/WWW/fosdem" as the URI "http://localhost:8042/fosdem":
-
-{
- "Name" : "MyOrthanc",
- [...]
- "HttpPort" : 8042,
- [...]
- "Plugins" : [
- "."
- ],
- "ServeFolders" : {
- "/fosdem" : "/home/jodogne/WWW/fosdem"
- }
-}
+Documentation is available in the Orthanc Book:
+http://book.orthanc-server.com/plugins/serve-folders.html
diff --git a/README b/README
index 35859b2..38cc685 100644
--- a/README
+++ b/README
@@ -16,11 +16,11 @@ file.
Supported Platforms
-------------------
-Currently, the supported platforms are:
+Currently, the officially supported platforms are:
-* Linux 32bit.
-* Linux 64bit.
+* GNU/Linux (32bit and 64bit).
* Windows 32bit.
+* Apple OS X (32bit and 64bit).
Supported Toolchains
@@ -29,9 +29,9 @@ Supported Toolchains
Orthanc can currently be built using the following compiling
toolchains:
-* Native Linux compilation, with gcc.
+* Native GNU/Linux compilation, with gcc.
* Native Windows compilation, with Microsoft Visual Studio.
-* Cross-compilation for Windows under Linux, with MinGW.
+* Cross-compilation for Windows under GNU/Linux, with MinGW.
Licensing
diff --git a/Resources/CMake/BoostConfiguration.cmake b/Resources/CMake/BoostConfiguration.cmake
index 20c50df..fa54bf5 100644
--- a/Resources/CMake/BoostConfiguration.cmake
+++ b/Resources/CMake/BoostConfiguration.cmake
@@ -43,7 +43,7 @@ if (BOOST_STATIC)
set(BOOST_NAME boost_1_60_0)
set(BOOST_BCP_SUFFIX bcpdigest-1.0.1)
set(BOOST_MD5 "a789f8ec2056ad1c2d5f0cb64687cc7b")
- set(BOOST_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz")
+ set(BOOST_URL "http://www.orthanc-server.com/downloads/third-party/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz")
set(BOOST_FILESYSTEM_SOURCES_DIR "${BOOST_NAME}/libs/filesystem/src")
set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME})
@@ -54,8 +54,12 @@ if (BOOST_STATIC)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR
${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
- ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD")
+ ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
list(APPEND BOOST_SOURCES
+ ${BOOST_SOURCES_DIR}/libs/atomic/src/lockpool.cpp
${BOOST_SOURCES_DIR}/libs/thread/src/pthread/once.cpp
${BOOST_SOURCES_DIR}/libs/thread/src/pthread/thread.cpp
)
@@ -65,7 +69,10 @@ if (BOOST_STATIC)
-DBOOST_LOCALE_NO_STD_BACKEND=1
)
- if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase")
+ if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
add_definitions(-DBOOST_HAS_SCHED_YIELD=1)
endif()
@@ -107,19 +114,38 @@ if (BOOST_STATIC)
list(APPEND BOOST_SOURCES
${BOOST_REGEX_SOURCES}
${BOOST_SOURCES_DIR}/libs/date_time/src/gregorian/greg_month.cpp
- ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp
- ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp
- ${BOOST_FILESYSTEM_SOURCES_DIR}/path.cpp
- ${BOOST_FILESYSTEM_SOURCES_DIR}/path_traits.cpp
${BOOST_SOURCES_DIR}/libs/locale/src/encoding/codepage.cpp
${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp
)
+ if (${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
+ # boost::filesystem is not available on PNaCl
+ add_definitions(
+ -DBOOST_HAS_FILESYSTEM_V3=0
+ -D__INTEGRITY=1
+ )
+ else()
+ add_definitions(
+ -DBOOST_HAS_FILESYSTEM_V3=1
+ )
+ list(APPEND BOOST_SOURCES
+ ${BOOST_FILESYSTEM_SOURCES_DIR}/codecvt_error_category.cpp
+ ${BOOST_FILESYSTEM_SOURCES_DIR}/operations.cpp
+ ${BOOST_FILESYSTEM_SOURCES_DIR}/path.cpp
+ ${BOOST_FILESYSTEM_SOURCES_DIR}/path_traits.cpp
+ )
+ endif()
+
if (USE_BOOST_LOCALE_BACKENDS)
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR
${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD" OR
- ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD")
+ ${CMAKE_SYSTEM_NAME} STREQUAL "kFreeBSD" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "PNaCl" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl32" OR
+ ${CMAKE_SYSTEM_NAME} STREQUAL "NaCl64")
list(APPEND BOOST_SOURCES
${BOOST_SOURCES_DIR}/libs/locale/src/posix/codecvt.cpp
${BOOST_SOURCES_DIR}/libs/locale/src/posix/collate.cpp
@@ -175,7 +201,6 @@ if (BOOST_STATIC)
-DBOOST_SYSTEM_NO_LIB
-DBOOST_LOCALE_NO_LIB
-DBOOST_HAS_LOCALE=1
- -DBOOST_HAS_FILESYSTEM_V3=1
)
if (CMAKE_COMPILER_IS_GNUCXX)
@@ -186,7 +211,8 @@ if (BOOST_STATIC)
${BOOST_SOURCES_DIR}
)
- source_group(ThirdParty\\Boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*)
+ source_group(ThirdParty\\boost REGULAR_EXPRESSION ${BOOST_SOURCES_DIR}/.*)
+
else()
add_definitions(
-DBOOST_HAS_LOCALE=1
diff --git a/Resources/CMake/Compiler.cmake b/Resources/CMake/Compiler.cmake
index 52f4fab..fa7577d 100644
--- a/Resources/CMake/Compiler.cmake
+++ b/Resources/CMake/Compiler.cmake
@@ -41,7 +41,17 @@ elseif (MSVC)
-D_CRT_SECURE_NO_WARNINGS=1
-D_CRT_SECURE_NO_DEPRECATE=1
)
- include_directories(${ORTHANC_ROOT}/Resources/ThirdParty/VisualStudio)
+
+ if (MSVC_VERSION LESS 1600)
+ # Starting with Visual Studio >= 2010 (i.e. macro _MSC_VER >=
+ # 1600), Microsoft ships a standard-compliant <stdint.h>
+ # header. For earlier versions of Visual Studio, give access to a
+ # compatibility header.
+ # http://stackoverflow.com/a/70630/881731
+ # https://en.wikibooks.org/wiki/C_Programming/C_Reference/stdint.h#External_links
+ include_directories(${ORTHANC_ROOT}/Resources/ThirdParty/VisualStudio)
+ endif()
+
link_libraries(netapi32)
endif()
@@ -154,6 +164,23 @@ if (${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
endif()
+if (DEFINED ENABLE_PROFILING AND ENABLE_PROFILING)
+ if (NOT CMAKE_BUILD_TYPE STREQUAL "Debug")
+ message(WARNING "Enabling profiling on a non-debug build will not produce full information")
+ endif()
+
+ if (CMAKE_COMPILER_IS_GNUCXX)
+ set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -pg")
+ set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -pg")
+ set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -pg")
+ set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} -pg")
+ set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} -pg")
+ else()
+ message(FATAL_ERROR "Don't know how to enable profiling on your configuration")
+ endif()
+endif()
+
+
if (STATIC_BUILD)
add_definitions(-DORTHANC_STATIC=1)
else()
diff --git a/Resources/CMake/DcmtkConfiguration.cmake b/Resources/CMake/DcmtkConfiguration.cmake
index 0e22007..8534a93 100644
--- a/Resources/CMake/DcmtkConfiguration.cmake
+++ b/Resources/CMake/DcmtkConfiguration.cmake
@@ -7,7 +7,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
SET(DCMTK_VERSION_NUMBER 361)
SET(DCMTK_PACKAGE_VERSION "3.6.1")
SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.1_20160216)
- SET(DCMTK_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/dcmtk-3.6.1_20160216.tar.gz")
+ SET(DCMTK_URL "http://www.orthanc-server.com/downloads/third-party/dcmtk-3.6.1_20160216.tar.gz")
SET(DCMTK_MD5 "273c8a544b9fe09b8a4fb4eb51df8e52")
SET(DCMTK_PATCH_SPEED "${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.1-speed.patch")
@@ -21,7 +21,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
SET(DCMTK_VERSION_NUMBER 360)
SET(DCMTK_PACKAGE_VERSION "3.6.0")
SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.0)
- SET(DCMTK_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/dcmtk-3.6.0.zip")
+ SET(DCMTK_URL "http://www.orthanc-server.com/downloads/third-party/dcmtk-3.6.0.zip")
SET(DCMTK_MD5 "219ad631b82031806147e4abbfba4fa4")
SET(DCMTK_PATCH_SPEED "${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-speed.patch")
SET(DCMTK_PATCH_MINGW64 "${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-mingw64.patch")
@@ -35,6 +35,35 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
DownloadPackage(${DCMTK_MD5} ${DCMTK_URL} "${DCMTK_SOURCES_DIR}")
+
+ if (FirstRun AND
+ NOT USE_DCMTK_361)
+ if (USE_DCMTK_361_PRIVATE_DIC)
+ # If using DCMTK 3.6.0, backport the "private.dic" file from DCMTK
+ # 3.6.1 snapshot. This adds support for more private tags, and
+ # fixes some import problems with Philips MRI Achieva.
+ message("Using the dictionary of private tags from DCMTK 3.6.1")
+ configure_file(
+ ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.1-private.dic
+ ${DCMTK_SOURCES_DIR}/dcmdata/data/private.dic
+ COPYONLY)
+ else()
+ message("Using the dictionary of private tags from DCMTK 3.6.0")
+ endif()
+
+ # Patches specific to DCMTK 3.6.0
+ execute_process(
+ COMMAND ${PATCH_EXECUTABLE} -p0 -N -i ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch
+ WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
+ RESULT_VARIABLE Failure
+ )
+
+ if (Failure)
+ message(FATAL_ERROR "Error while patching a file")
+ endif()
+ endif()
+
+
IF (CMAKE_CROSSCOMPILING)
SET(C_CHAR_UNSIGNED 1 CACHE INTERNAL "Whether char is unsigned.")
ENDIF()
@@ -181,9 +210,15 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_DCMTK)
list(REMOVE_ITEM DCMTK_SOURCES
${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdictbi.cc
${DCMTK_SOURCES_DIR}/dcmdata/libsrc/mkdeftag.cc
- #${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdictbi.cc
)
+ if (NOT USE_DCMTK_361)
+ # Removing this file is required with DCMTK 3.6.0
+ list(REMOVE_ITEM DCMTK_SOURCES
+ ${DCMTK_SOURCES_DIR}/dcmdata/libsrc/dcdictbi.cc
+ )
+ endif()
+
#set_source_files_properties(${DCMTK_SOURCES}
# PROPERTIES COMPILE_DEFINITIONS
# "PACKAGE_VERSION=\"${DCMTK_PACKAGE_VERSION}\";PACKAGE_VERSION_NUMBER=\"${DCMTK_VERSION_NUMBER}\"")
@@ -271,6 +306,9 @@ if (NOT DCMTK_USE_EMBEDDED_DICTIONARIES)
/usr/share/libdcmtk4
/usr/share/libdcmtk5
/usr/share/libdcmtk6
+ /usr/share/libdcmtk7
+ /usr/share/libdcmtk8
+ /usr/share/libdcmtk9
/usr/local/share/dcmtk
)
diff --git a/Resources/CMake/DownloadPackage.cmake b/Resources/CMake/DownloadPackage.cmake
index 492a352..2a73cda 100644
--- a/Resources/CMake/DownloadPackage.cmake
+++ b/Resources/CMake/DownloadPackage.cmake
@@ -15,12 +15,18 @@ endmacro()
## Setup the patch command-line tool
##
-if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
- set(PATCH_EXECUTABLE ${CMAKE_SOURCE_DIR}/Resources/ThirdParty/patch/patch.exe)
-else ()
- find_program(PATCH_EXECUTABLE patch)
- if (${PATCH_EXECUTABLE} MATCHES "PATCH_EXECUTABLE-NOTFOUND")
- message(FATAL_ERROR "Please install the 'patch' standard command-line tool")
+if (NOT ORTHANC_DISABLE_PATCH)
+ if ("${CMAKE_HOST_SYSTEM_NAME}" STREQUAL "Windows")
+ set(PATCH_EXECUTABLE ${CMAKE_CURRENT_LIST_DIR}/../ThirdParty/patch/patch.exe)
+ if (NOT EXISTS ${PATCH_EXECUTABLE})
+ message(FATAL_ERROR "Unable to find the patch.exe tool that is shipped with Orthanc")
+ endif()
+
+ else ()
+ find_program(PATCH_EXECUTABLE patch)
+ if (${PATCH_EXECUTABLE} MATCHES "PATCH_EXECUTABLE-NOTFOUND")
+ message(FATAL_ERROR "Please install the 'patch' standard command-line tool")
+ endif()
endif()
endif()
@@ -70,7 +76,9 @@ macro(DownloadPackage MD5 Url TargetDirectory)
message(FATAL_ERROR "CMake is not allowed to download from Internet. Please set the ALLOW_DOWNLOADS option to ON")
endif()
- file(DOWNLOAD "${Url}" "${TMP_PATH}" SHOW_PROGRESS EXPECTED_MD5 "${MD5}")
+ file(DOWNLOAD "${Url}" "${TMP_PATH}"
+ SHOW_PROGRESS EXPECTED_MD5 "${MD5}"
+ TIMEOUT 60 INACTIVITY_TIMEOUT 60)
else()
message("Using local copy of ${Url}")
endif()
diff --git a/Resources/CMake/GoogleTestConfiguration.cmake b/Resources/CMake/GoogleTestConfiguration.cmake
index af6e67b..b9074b4 100644
--- a/Resources/CMake/GoogleTestConfiguration.cmake
+++ b/Resources/CMake/GoogleTestConfiguration.cmake
@@ -1,15 +1,32 @@
if (USE_GTEST_DEBIAN_SOURCE_PACKAGE)
- set(GTEST_SOURCES /usr/src/gtest/src/gtest-all.cc)
- include_directories(/usr/src/gtest)
+ find_path(GTEST_DEBIAN_SOURCES_DIR
+ NAMES src/gtest-all.cc
+ PATHS
+ /usr/src/gtest
+ /usr/src/googletest/googletest
+ PATH_SUFFIXES src
+ )
+
+ find_path(GTEST_DEBIAN_INCLUDE_DIR
+ NAMES gtest.h
+ PATHS
+ /usr/include/gtest
+ )
- if (NOT EXISTS /usr/include/gtest/gtest.h OR
- NOT EXISTS ${GTEST_SOURCES})
+ message("Path to the Debian Google Test sources: ${GTEST_DEBIAN_SOURCES_DIR}")
+ message("Path to the Debian Google Test includes: ${GTEST_DEBIAN_INCLUDE_DIR}")
+
+ set(GTEST_SOURCES ${GTEST_DEBIAN_SOURCES_DIR}/src/gtest-all.cc)
+ include_directories(${GTEST_DEBIAN_SOURCES_DIR})
+
+ if (NOT EXISTS ${GTEST_SOURCES} OR
+ NOT EXISTS ${GTEST_DEBIAN_INCLUDE_DIR}/gtest.h)
message(FATAL_ERROR "Please install the libgtest-dev package")
endif()
elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST)
set(GTEST_SOURCES_DIR ${CMAKE_BINARY_DIR}/gtest-1.7.0)
- set(GTEST_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/gtest-1.7.0.zip")
+ set(GTEST_URL "http://www.orthanc-server.com/downloads/third-party/gtest-1.7.0.zip")
set(GTEST_MD5 "2d6ec8ccdf5c46b05ba54a9fd1d130d7")
DownloadPackage(${GTEST_MD5} ${GTEST_URL} "${GTEST_SOURCES_DIR}")
@@ -28,6 +45,8 @@ elseif (STATIC_BUILD OR NOT USE_SYSTEM_GOOGLE_TEST)
add_definitions(/D _VARIADIC_MAX=10)
endif()
+ source_group(ThirdParty\\GoogleTest REGULAR_EXPRESSION ${GTEST_SOURCES_DIR}/.*)
+
else()
include(FindGTest)
if (NOT GTEST_FOUND)
diff --git a/Resources/CMake/JsonCppConfiguration.cmake b/Resources/CMake/JsonCppConfiguration.cmake
index bad61b8..1532a81 100644
--- a/Resources/CMake/JsonCppConfiguration.cmake
+++ b/Resources/CMake/JsonCppConfiguration.cmake
@@ -1,6 +1,6 @@
if (STATIC_BUILD OR NOT USE_SYSTEM_JSONCPP)
set(JSONCPP_SOURCES_DIR ${CMAKE_BINARY_DIR}/jsoncpp-0.10.5)
- set(JSONCPP_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/jsoncpp-0.10.5.tar.gz")
+ set(JSONCPP_URL "http://www.orthanc-server.com/downloads/third-party/jsoncpp-0.10.5.tar.gz")
set(JSONCPP_MD5 "db146bac5a126ded9bd728ab7b61ed6b")
DownloadPackage(${JSONCPP_MD5} ${JSONCPP_URL} "${JSONCPP_SOURCES_DIR}")
diff --git a/Resources/CMake/LibCurlConfiguration.cmake b/Resources/CMake/LibCurlConfiguration.cmake
index d10912a..390a1a7 100644
--- a/Resources/CMake/LibCurlConfiguration.cmake
+++ b/Resources/CMake/LibCurlConfiguration.cmake
@@ -1,7 +1,7 @@
if (STATIC_BUILD OR NOT USE_SYSTEM_CURL)
- SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-7.44.0)
- SET(CURL_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/curl-7.44.0.tar.gz")
- SET(CURL_MD5 "cf46112b5151e2f1a3fd38439bdade23")
+ SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-7.50.3)
+ SET(CURL_URL "http://www.orthanc-server.com/downloads/third-party/curl-7.50.3.tar.gz")
+ SET(CURL_MD5 "870e16fd88a88b52e26a4f04dfc161db")
DownloadPackage(${CURL_MD5} ${CURL_URL} "${CURL_SOURCES_DIR}")
@@ -10,6 +10,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_CURL)
)
AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib CURL_SOURCES)
+ AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vauth CURL_SOURCES)
AUX_SOURCE_DIRECTORY(${CURL_SOURCES_DIR}/lib/vtls CURL_SOURCES)
source_group(ThirdParty\\LibCurl REGULAR_EXPRESSION ${CURL_SOURCES_DIR}/.*)
@@ -40,13 +41,21 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_CURL)
)
endif()
- file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "")
+ if (NOT EXISTS "${CURL_SOURCES_DIR}/lib/curl_config.h")
+ file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "")
- file(GLOB CURL_LIBS_HEADERS ${CURL_SOURCES_DIR}/lib/*.h)
- foreach (header IN LISTS CURL_LIBS_HEADERS)
- get_filename_component(filename ${header} NAME)
- file(WRITE ${CURL_SOURCES_DIR}/lib/vtls/${filename} "#include \"../${filename}\"\n")
- endforeach()
+ file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/vauth.h "#include \"../vauth.h\"\n")
+ file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/digest.h "#include \"../digest.h\"\n")
+ file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vauth/ntlm.h "#include \"../ntlm.h\"\n")
+ file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/vtls/vtls.h "#include \"../../vtls/vtls.h\"\n")
+
+ file(GLOB CURL_LIBS_HEADERS ${CURL_SOURCES_DIR}/lib/*.h)
+ foreach (header IN LISTS CURL_LIBS_HEADERS)
+ get_filename_component(filename ${header} NAME)
+ file(WRITE ${CURL_SOURCES_DIR}/lib/vauth/${filename} "#include \"../${filename}\"\n")
+ file(WRITE ${CURL_SOURCES_DIR}/lib/vtls/${filename} "#include \"../${filename}\"\n")
+ endforeach()
+ endif()
if (${CMAKE_SYSTEM_NAME} STREQUAL "Linux" OR
${CMAKE_SYSTEM_NAME} STREQUAL "Darwin" OR
diff --git a/Resources/CMake/LibIconvConfiguration.cmake b/Resources/CMake/LibIconvConfiguration.cmake
index be7cd75..d381798 100644
--- a/Resources/CMake/LibIconvConfiguration.cmake
+++ b/Resources/CMake/LibIconvConfiguration.cmake
@@ -1,5 +1,5 @@
set(LIBICONV_SOURCES_DIR ${CMAKE_BINARY_DIR}/libiconv-1.14)
-set(LIBICONV_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/libiconv-1.14.tar.gz")
+set(LIBICONV_URL "http://www.orthanc-server.com/downloads/third-party/libiconv-1.14.tar.gz")
set(LIBICONV_MD5 "e34509b1623cec449dfeb73d7ce9c6c6")
DownloadPackage(${LIBICONV_MD5} ${LIBICONV_URL} "${LIBICONV_SOURCES_DIR}")
@@ -48,3 +48,5 @@ list(APPEND BOOST_SOURCES
${LIBICONV_SOURCES_DIR}/libcharset/lib/localcharset.c
${LIBICONV_SOURCES_DIR}/libcharset/lib/relocatable.c
)
+
+source_group(ThirdParty\\libiconv REGULAR_EXPRESSION ${LIBICONV_SOURCES_DIR}/.*)
diff --git a/Resources/CMake/LibJpegConfiguration.cmake b/Resources/CMake/LibJpegConfiguration.cmake
index d0ecdd1..dcc4149 100644
--- a/Resources/CMake/LibJpegConfiguration.cmake
+++ b/Resources/CMake/LibJpegConfiguration.cmake
@@ -2,7 +2,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBJPEG)
set(LIBJPEG_SOURCES_DIR ${CMAKE_BINARY_DIR}/jpeg-9a)
DownloadPackage(
"3353992aecaee1805ef4109aadd433e7"
- "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/jpegsrc.v9a.tar.gz"
+ "http://www.orthanc-server.com/downloads/third-party/jpegsrc.v9a.tar.gz"
"${LIBJPEG_SOURCES_DIR}")
include_directories(
@@ -81,6 +81,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBJPEG)
${LIBJPEG_SOURCES_DIR}/jconfig.h COPYONLY
)
+ source_group(ThirdParty\\libjpeg REGULAR_EXPRESSION ${LIBJPEG_SOURCES_DIR}/.*)
+
else()
include(FindJPEG)
diff --git a/Resources/CMake/LibP11Configuration.cmake b/Resources/CMake/LibP11Configuration.cmake
index 509bee6..21ab70d 100644
--- a/Resources/CMake/LibP11Configuration.cmake
+++ b/Resources/CMake/LibP11Configuration.cmake
@@ -1,6 +1,6 @@
if (STATIC_BUILD OR NOT USE_SYSTEM_LIBP11)
SET(LIBP11_SOURCES_DIR ${CMAKE_BINARY_DIR}/libp11-0.4.0)
- SET(LIBP11_URL "www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/beid/libp11-0.4.0.tar.gz")
+ SET(LIBP11_URL "http://www.orthanc-server.com/downloads/third-party/beid/libp11-0.4.0.tar.gz")
SET(LIBP11_MD5 "00b3e41db5be840d822bda12f3ab2ca7")
if (IS_DIRECTORY "${LIBP11_SOURCES_DIR}")
@@ -54,6 +54,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBP11)
)
endif()
+ source_group(ThirdParty\\libp11 REGULAR_EXPRESSION ${LIBP11_SOURCES_DIR}/.*)
+
else()
check_include_file_cxx(libp11.h HAVE_LIBP11_H)
if (NOT HAVE_LIBP11_H)
diff --git a/Resources/CMake/LibPngConfiguration.cmake b/Resources/CMake/LibPngConfiguration.cmake
index 903079f..bf9820c 100644
--- a/Resources/CMake/LibPngConfiguration.cmake
+++ b/Resources/CMake/LibPngConfiguration.cmake
@@ -1,6 +1,6 @@
if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPNG)
SET(LIBPNG_SOURCES_DIR ${CMAKE_BINARY_DIR}/libpng-1.5.12)
- SET(LIBPNG_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/libpng-1.5.12.tar.gz")
+ SET(LIBPNG_URL "http://www.orthanc-server.com/downloads/third-party/libpng-1.5.12.tar.gz")
SET(LIBPNG_MD5 "8ea7f60347a306c5faf70b977fa80e28")
DownloadPackage(${LIBPNG_MD5} ${LIBPNG_URL} "${LIBPNG_SOURCES_DIR}")
@@ -46,7 +46,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_LIBPNG)
-DPNG_IMPEXP=
)
- source_group(ThirdParty\\Libpng REGULAR_EXPRESSION ${LIBPNG_SOURCES_DIR}/.*)
+ source_group(ThirdParty\\libpng REGULAR_EXPRESSION ${LIBPNG_SOURCES_DIR}/.*)
else()
include(FindPNG)
diff --git a/Resources/CMake/LuaConfiguration.cmake b/Resources/CMake/LuaConfiguration.cmake
index 40bda1e..b88a3f1 100644
--- a/Resources/CMake/LuaConfiguration.cmake
+++ b/Resources/CMake/LuaConfiguration.cmake
@@ -1,7 +1,7 @@
if (STATIC_BUILD OR NOT USE_SYSTEM_LUA)
SET(LUA_SOURCES_DIR ${CMAKE_BINARY_DIR}/lua-5.1.5)
SET(LUA_MD5 "2e115fe26e435e33b0d5c022e4490567")
- SET(LUA_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/lua-5.1.5.tar.gz")
+ SET(LUA_URL "http://www.orthanc-server.com/downloads/third-party/lua-5.1.5.tar.gz")
DownloadPackage(${LUA_MD5} ${LUA_URL} "${LUA_SOURCES_DIR}")
diff --git a/Resources/CMake/MongooseConfiguration.cmake b/Resources/CMake/MongooseConfiguration.cmake
index c451981..4ef44f2 100644
--- a/Resources/CMake/MongooseConfiguration.cmake
+++ b/Resources/CMake/MongooseConfiguration.cmake
@@ -11,7 +11,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_MONGOOSE)
# Use Mongoose 3.1
DownloadPackage(
"e718fc287b4eb1bd523be3fa00942bb0"
- "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/mongoose-3.1.tgz"
+ "http://www.orthanc-server.com/downloads/third-party/mongoose-3.1.tgz"
"${MONGOOSE_SOURCES_DIR}")
add_definitions(-DMONGOOSE_USE_CALLBACKS=0)
@@ -21,7 +21,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_MONGOOSE)
# Use Mongoose 3.8
DownloadPackage(
"7e3296295072792cdc3c633f9404e0c3"
- "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/mongoose-3.8.tgz"
+ "http://www.orthanc-server.com/downloads/third-party/mongoose-3.8.tgz"
"${MONGOOSE_SOURCES_DIR}")
add_definitions(-DMONGOOSE_USE_CALLBACKS=1)
diff --git a/Resources/CMake/OpenSslConfiguration.cmake b/Resources/CMake/OpenSslConfiguration.cmake
index 6e7a995..5652e59 100644
--- a/Resources/CMake/OpenSslConfiguration.cmake
+++ b/Resources/CMake/OpenSslConfiguration.cmake
@@ -4,7 +4,7 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL)
# not always properly handled when uncompressing on Windows.
SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-1.0.2d)
- SET(OPENSSL_URL "www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/openssl-1.0.2d.zip")
+ SET(OPENSSL_URL "http://www.orthanc-server.com/downloads/third-party/openssl-1.0.2d.zip")
SET(OPENSSL_MD5 "4b2ac15fc6db17f3dadc54482d3eee85")
if (IS_DIRECTORY "${OPENSSL_SOURCES_DIR}")
@@ -191,9 +191,10 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL)
${OPENSSL_SOURCES_DIR}/crypto/x509/verify_extra_test.c
${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3prin.c
${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3nametest.c
- ${OPENSSL_SOURCES_DIR}/crypto/ssl/heartbeat_test.c
${OPENSSL_SOURCES_DIR}/crypto/constant_time_test.c
${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256_table.c
+
+ ${OPENSSL_SOURCES_DIR}/ssl/heartbeat_test.c
)
@@ -215,6 +216,8 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL)
endif()
endif()
+ source_group(ThirdParty\\OpenSSL REGULAR_EXPRESSION ${OPENSSL_SOURCES_DIR}/.*)
+
else()
include(FindOpenSSL)
diff --git a/Resources/CMake/PugixmlConfiguration.cmake b/Resources/CMake/PugixmlConfiguration.cmake
index 4094fa3..4d57b12 100644
--- a/Resources/CMake/PugixmlConfiguration.cmake
+++ b/Resources/CMake/PugixmlConfiguration.cmake
@@ -1,10 +1,10 @@
if (USE_PUGIXML)
- add_definitions(-DORTHANC_PUGIXML_ENABLED=1)
+ add_definitions(-DORTHANC_ENABLE_PUGIXML=1)
if (STATIC_BUILD OR NOT USE_SYSTEM_PUGIXML)
set(PUGIXML_SOURCES_DIR ${CMAKE_BINARY_DIR}/pugixml-1.4)
set(PUGIXML_MD5 "7c56c91cfe3ecdee248a8e4892ef5781")
- set(PUGIXML_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/pugixml-1.4.tar.gz")
+ set(PUGIXML_URL "http://www.orthanc-server.com/downloads/third-party/pugixml-1.4.tar.gz")
DownloadPackage(${PUGIXML_MD5} ${PUGIXML_URL} "${PUGIXML_SOURCES_DIR}")
@@ -26,6 +26,8 @@ if (USE_PUGIXML)
link_libraries(pugixml)
endif()
+ source_group(ThirdParty\\pugixml REGULAR_EXPRESSION ${PUGIXML_SOURCES_DIR}/.*)
+
else()
- add_definitions(-DORTHANC_PUGIXML_ENABLED=0)
+ add_definitions(-DORTHANC_ENABLE_PUGIXML=0)
endif()
diff --git a/Resources/CMake/SQLiteConfiguration.cmake b/Resources/CMake/SQLiteConfiguration.cmake
index c6b446a..e15a6e0 100644
--- a/Resources/CMake/SQLiteConfiguration.cmake
+++ b/Resources/CMake/SQLiteConfiguration.cmake
@@ -17,7 +17,7 @@ endif()
if (SQLITE_STATIC)
SET(SQLITE_SOURCES_DIR ${CMAKE_BINARY_DIR}/sqlite-amalgamation-3071300)
SET(SQLITE_MD5 "5fbeff9645ab035a1f580e90b279a16d")
- SET(SQLITE_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/sqlite-amalgamation-3071300.zip")
+ SET(SQLITE_URL "http://www.orthanc-server.com/downloads/third-party/sqlite-amalgamation-3071300.zip")
DownloadPackage(${SQLITE_MD5} ${SQLITE_URL} "${SQLITE_SOURCES_DIR}")
diff --git a/Resources/CMake/ZlibConfiguration.cmake b/Resources/CMake/ZlibConfiguration.cmake
index e1940c7..4487c1e 100644
--- a/Resources/CMake/ZlibConfiguration.cmake
+++ b/Resources/CMake/ZlibConfiguration.cmake
@@ -1,6 +1,6 @@
if (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB)
SET(ZLIB_SOURCES_DIR ${CMAKE_BINARY_DIR}/zlib-1.2.7)
- SET(ZLIB_URL "http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/zlib-1.2.7.tar.gz")
+ SET(ZLIB_URL "http://www.orthanc-server.com/downloads/third-party/zlib-1.2.7.tar.gz")
SET(ZLIB_MD5 "60df6a37c56e7c1366cca812414f7b85")
DownloadPackage(${ZLIB_MD5} ${ZLIB_URL} "${ZLIB_SOURCES_DIR}")
@@ -27,10 +27,10 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_ZLIB)
${ZLIB_SOURCES_DIR}/zutil.c
)
+ source_group(ThirdParty\\zlib REGULAR_EXPRESSION ${ZLIB_SOURCES_DIR}/.*)
+
else()
include(FindZLIB)
include_directories(${ZLIB_INCLUDE_DIRS})
link_libraries(${ZLIB_LIBRARIES})
endif()
-
-source_group(ThirdParty\\ZLib REGULAR_EXPRESSION ${ZLIB_SOURCES_DIR}/.*)
diff --git a/Resources/Configuration.json b/Resources/Configuration.json
index 6ba93c6..43975bf 100644
--- a/Resources/Configuration.json
+++ b/Resources/Configuration.json
@@ -87,10 +87,11 @@
"DicomPort" : 4242,
// The default encoding that is assumed for DICOM files without
- // "SpecificCharacterSet" DICOM tag. The allowed values are "Ascii",
- // "Utf8", "Latin1", "Latin2", "Latin3", "Latin4", "Latin5",
- // "Cyrillic", "Windows1251", "Arabic", "Greek", "Hebrew", "Thai",
- // "Japanese", and "Chinese".
+ // "SpecificCharacterSet" DICOM tag, and that is used when answering
+ // C-Find requests (including worklists). The allowed values are
+ // "Ascii", "Utf8", "Latin1", "Latin2", "Latin3", "Latin4",
+ // "Latin5", "Cyrillic", "Windows1251", "Arabic", "Greek", "Hebrew",
+ // "Thai", "Japanese", and "Chinese".
"DefaultEncoding" : "Latin1",
// The transfer syntaxes that are accepted by Orthanc C-Store SCP
@@ -106,6 +107,11 @@
// SOP classes (aka. "promiscuous mode")
"UnknownSopClassAccepted" : false,
+ // Set the timeout (in seconds) after which the DICOM associations
+ // are closed by the Orthanc SCP (server) if no further DIMSE
+ // command is received from the SCU (client).
+ "DicomScpTimeout" : 30,
+
/**
@@ -158,6 +164,11 @@
// "clearcanvas" : [ "CLEARCANVAS", "192.168.1.1", 104, "ClearCanvas" ]
},
+ // The timeout (in seconds) after which the DICOM associations are
+ // considered as closed by the Orthanc SCU (client) if the remote
+ // DICOM SCP (server) does not answer.
+ "DicomScuTimeout" : 10,
+
// The list of the known Orthanc peers
"OrthancPeers" : {
/**
@@ -216,7 +227,8 @@
// Dictionary of symbolic names for the user-defined metadata. Each
// entry must map an unique string to an unique number between 1024
- // and 65535.
+ // and 65535. Reserved values:
+ // - The Orthanc whole-slide imaging plugin uses metadata 4200
"UserMetadata" : {
// "Sample" : 1024
},
@@ -302,18 +314,33 @@
}
**/
- // If set to "true", Orthanc will handle "SOP Classes in Study"
- // (0008,0062) in C-FIND requests. This option is turned off by
- // default, as it requires intensive accesses to the hard drive.
+ // If set to "true", Orthanc will still handle "SOP Classes in
+ // Study" (0008,0062) in C-FIND requests, even if the "SOP Class
+ // UID" metadata is not available in the database (which is the case
+ // if the DB was previously used by Orthanc <= 1.1.0). This option
+ // is turned off by default, as it requires intensive accesses to
+ // the hard drive.
"AllowFindSopClassesInStudy" : false,
+ // If set to "false", Orthanc will not load its default dictionary
+ // of private tags. This might be necessary if you cannot import a
+ // DICOM file encoded using the Implicit VR Endian transfer syntax,
+ // and containing private tags: Such an import error might stem from
+ // a bad dictionary. You can still list your private tags of
+ // interest in the "Dictionary" configuration option below.
+ "LoadPrivateDictionary" : true,
+
// Register a new tag in the dictionary of DICOM tags that are known
// to Orthanc. Each line must contain the tag (formatted as 2
// hexadecimal numbers), the value representation (2 upcase
// characters), a nickname for the tag, possibly the minimum
- // multiplicity (> 0 with defaults to 1), and possibly the maximum
- // multiplicity (0 means arbitrary multiplicity, defaults to 1).
+ // multiplicity (> 0 with defaults to 1), possibly the maximum
+ // multiplicity (0 means arbitrary multiplicity, defaults to 1), and
+ // possibly the Private Creator (for private tags).
"Dictionary" : {
// "0014,1020" : [ "DA", "ValidationExpiryDate", 1, 1 ]
+ // "00e1,10c2" : [ "UI", "PET-CT Multi Modality Name", 1, 1, "ELSCINT1" ]
+ // "7053,1003" : [ "ST", "Original Image Filename", 1, 1, "Philips PET Private Group" ]
+ // "2001,5f" : [ "SQ", "StackSequence", 1, 1, "Philips Imaging DD 001" ]
}
}
diff --git a/Resources/DicomConformanceStatement.txt b/Resources/DicomConformanceStatement.txt
index af8c95d..939e9f5 100644
--- a/Resources/DicomConformanceStatement.txt
+++ b/Resources/DicomConformanceStatement.txt
@@ -203,7 +203,7 @@ Orthanc supports the following SOP Classes as an SCU for C-Move:
Transfer Syntaxes
-----------------
-Orthanc will accept and negociate presentation contexts for all of the
+Orthanc will accept and negotiate presentation contexts for all of the
abovementioned supported SOP Classes using any of the following
transfer syntaxes:
diff --git a/Resources/EmbedResources.py b/Resources/EmbedResources.py
index d914d15..ad5cf61 100755
--- a/Resources/EmbedResources.py
+++ b/Resources/EmbedResources.py
@@ -159,6 +159,10 @@ header.write("""
#include <string>
#include <list>
+#if defined(_MSC_VER)
+# pragma warning(disable: 4065) // "Switch statement contains 'default' but no 'case' labels"
+#endif
+
namespace %s
{
namespace EmbeddedResources
diff --git a/Resources/ErrorCodes.json b/Resources/ErrorCodes.json
index f6ac2a7..083df34 100644
--- a/Resources/ErrorCodes.json
+++ b/Resources/ErrorCodes.json
@@ -32,7 +32,7 @@
{
"Code": 4,
"Name": "NotEnoughMemory",
- "Description": "Not enough memory"
+ "Description": "The server hosting Orthanc is running out of memory"
},
{
"Code": 5,
@@ -195,6 +195,11 @@
"HttpStatus": 406,
"Name": "NotAcceptable",
"Description": "Cannot send a response which is acceptable according to the Accept HTTP header"
+ },
+ {
+ "Code": 35,
+ "Name": "NullPointer",
+ "Description": "Cannot handle a NULL pointer"
},
diff --git a/Resources/Orthanc.doxygen b/Resources/Orthanc.doxygen
index 9e2fd0e..b99ccb9 100644
--- a/Resources/Orthanc.doxygen
+++ b/Resources/Orthanc.doxygen
@@ -1,110 +1,129 @@
-# Doxyfile 1.8.1.2
+# Doxyfile 1.8.7
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
-# All text after a hash (#) is considered a comment and will be ignored.
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ").
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
-# The PROJECT_NAME tag is a single word (or sequence of words) that should
-# identify the project. Note that if you do not use Doxywizard you need
-# to put quotes around the project name if it contains spaces.
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
PROJECT_NAME = Orthanc
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
PROJECT_NUMBER =
# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer
-# a quick idea about the purpose of the project. Keep the description short.
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Internal documentation of Orthanc"
-# With the PROJECT_LOGO tag one can specify an logo or icon that is
-# included in the documentation. The maximum height of the logo should not
-# exceed 55 pixels and the maximum width should not exceed 200 pixels.
-# Doxygen will copy the logo to the output directory.
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
PROJECT_LOGO = @CMAKE_SOURCE_DIR@/Resources/OrthancLogoDocumentation.png
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
OUTPUT_DIRECTORY = OrthancInternalDocumentation
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
CREATE_SUBDIRS = NO
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
OUTPUT_LANGUAGE = English
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
BRIEF_MEMBER_DESC = YES
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
+# The default value is: YES.
REPEAT_BRIEF = YES
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
ABBREVIATE_BRIEF =
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
+# doxygen will generate a detailed section even if there is only a brief
# description.
+# The default value is: NO.
ALWAYS_DETAILED_SEC = NO
@@ -112,169 +131,207 @@ ALWAYS_DETAILED_SEC = NO
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
+# The default value is: NO.
INLINE_INHERITED_MEMB = NO
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
FULL_PATH_NAMES = NO
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
STRIP_FROM_PATH =
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
STRIP_FROM_INC_PATH =
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
SHORT_NAMES = NO
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
JAVADOC_AUTOBRIEF = NO
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
QT_AUTOBRIEF = NO
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
MULTILINE_CPP_IS_BRIEF = NO
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
INHERIT_DOCS = YES
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
SEPARATE_MEMBER_PAGES = NO
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
TAB_SIZE = 8
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding
-# "class=itcl::class" will allow you to use the command class in the
-# itcl::class meaning.
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
OPTIMIZE_OUTPUT_FOR_C = NO
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
OPTIMIZE_FOR_FORTRAN = NO
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
EXTENSION_MAPPING =
-# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
-# comments according to the Markdown format, which allows for more readable
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you
-# can mix doxygen, HTML, and XML commands with Markdown formatting.
-# Disable only in case of backward compatibilities issues.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
MARKDOWN_SUPPORT = YES
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
BUILTIN_STL_SUPPORT = YES
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
+# The default value is: NO.
CPP_CLI_SUPPORT = NO
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
SIP_SUPPORT = NO
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
IDL_PROPERTY_SUPPORT = YES
@@ -282,67 +339,61 @@ IDL_PROPERTY_SUPPORT = YES
# tag is set to YES, then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
+# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
SUBGROUPING = YES
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
-# unions are shown inside the group in which they are included (e.g. using
-# @ingroup) instead of on a separate page (for HTML and Man pages) or
-# section (for LaTeX and RTF).
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
INLINE_GROUPED_CLASSES = NO
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
-# unions with only public data fields will be shown inline in the documentation
-# of the scope in which they are defined (i.e. file, namespace, or group
-# documentation), provided this scope is documented. If set to NO (the default),
-# structs, classes, and unions are shown on a separate page (for HTML and Man
-# pages) or section (for LaTeX and RTF).
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
INLINE_SIMPLE_STRUCTS = NO
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
TYPEDEF_HIDES_STRUCT = NO
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
-
-SYMBOL_CACHE_SIZE = 0
-
-# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
-# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
-# their name and scope. Since this can be an expensive process and often the
-# same symbol appear multiple times in the code, doxygen keeps a cache of
-# pre-resolved symbols. If the cache is too small doxygen will become slower.
-# If the cache is too large, memory is wasted. The cache size is given by this
-# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
LOOKUP_CACHE_SIZE = 0
@@ -351,340 +402,391 @@ LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
EXTRACT_ALL = YES
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
EXTRACT_PRIVATE = NO
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
EXTRACT_PACKAGE = NO
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
EXTRACT_STATIC = NO
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
EXTRACT_LOCAL_CLASSES = YES
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
EXTRACT_LOCAL_METHODS = NO
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespaces are hidden.
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
EXTRACT_ANON_NSPACES = NO
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
HIDE_UNDOC_MEMBERS = NO
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = NO
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
HIDE_IN_BODY_DOCS = NO
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
INTERNAL_DOCS = NO
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
CASE_SENSE_NAMES = YES
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
HIDE_SCOPE_NAMES = NO
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
SHOW_INCLUDE_FILES = YES
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
FORCE_LOCAL_INCLUDES = NO
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
INLINE_INFO = YES
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
SORT_MEMBER_DOCS = YES
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
SORT_BRIEF_DOCS = NO
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
SORT_MEMBERS_CTORS_1ST = NO
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
SORT_GROUP_NAMES = NO
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
SORT_BY_SCOPE_NAME = NO
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
-# do proper type resolution of all parameters of a function it will reject a
-# match between the prototype and the implementation of a member function even
-# if there is only one candidate or it is obvious which candidate to choose
-# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
-# will still accept a match between prototype and implementation in such cases.
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
STRICT_PROTO_MATCHING = NO
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
GENERATE_TODOLIST = YES
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
GENERATE_TESTLIST = YES
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
GENERATE_BUGLIST = YES
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
GENERATE_DEPRECATEDLIST= YES
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
ENABLED_SECTIONS =
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
MAX_INITIALIZER_LINES = 30
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
SHOW_USED_FILES = YES
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
SHOW_FILES = YES
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page.
-# This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
LAYOUT_FILE =
-# The CITE_BIB_FILES tag can be used to specify one or more bib files
-# containing the references data. This must be a list of .bib files. The
-# .bib extension is automatically appended if omitted. Using this command
-# requires the bibtex tool to be installed. See also
-# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
-# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
-# feature you need bibtex and perl available in the search path.
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
CITE_BIB_FILES =
#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
WARNINGS = YES
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
WARN_IF_UNDOCUMENTED = YES
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
WARN_IF_DOC_ERROR = YES
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
WARN_NO_PARAMDOC = NO
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
WARN_LOGFILE =
#---------------------------------------------------------------------------
-# configuration options related to the input files
+# Configuration options related to the input files
#---------------------------------------------------------------------------
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
INPUT = @CMAKE_SOURCE_DIR@/Core \
@CMAKE_SOURCE_DIR@/OrthancServer
# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
FILE_PATTERNS = *.h
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
# Note that relative paths are relative to the directory from which doxygen is
# run.
@@ -693,14 +795,16 @@ EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
+# The default value is: NO.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS =
@@ -709,755 +813,1076 @@ EXCLUDE_PATTERNS =
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
EXCLUDE_SYMBOLS = Orthanc::Internals
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
EXAMPLE_PATTERNS =
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
EXAMPLE_RECURSIVE = NO
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be
-# ignored.
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.
-# Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.
-# The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
FILTER_SOURCE_FILES = NO
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
-# and it is also possible to disable source filtering for a specific pattern
-# using *.ext= (so without naming a filter). This option only has effect when
-# FILTER_SOURCE_FILES is enabled.
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
FILTER_SOURCE_PATTERNS =
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
#---------------------------------------------------------------------------
-# configuration options related to source browsing
+# Configuration options related to source browsing
#---------------------------------------------------------------------------
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
SOURCE_BROWSER = NO
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
INLINE_SOURCES = NO
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C, C++ and Fortran comments will always remain visible.
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
STRIP_CODE_COMMENTS = YES
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
REFERENCED_BY_RELATION = NO
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
REFERENCES_RELATION = NO
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
REFERENCES_LINK_SOURCE = YES
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
USE_HTAGS = NO
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
+# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
ALPHABETICAL_INDEX = YES
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
-# configuration options related to the HTML output
+# Configuration options related to the HTML output
#---------------------------------------------------------------------------
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
GENERATE_HTML = YES
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = doc
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FILE_EXTENSION = .html
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-# for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is advised to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
-# changing the value of configuration settings such as GENERATE_TREEVIEW!
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_HEADER =
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FOOTER =
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# style sheet in the HTML output directory as well, or it will be erased!
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_STYLESHEET =
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
-# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that
-# the files will be copied as-is; there are no commands or markers available.
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES =
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the style sheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_HUE = 220
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_SAT = 100
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_DYNAMIC_SECTIONS = NO
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
-# entries shown in the various tree structured indices initially; the user
-# can expand and collapse entries dynamically later on. Doxygen will expand
-# the tree to such a level that at most the specified number of entries are
-# visible (unless a fully collapsed tree already exceeds this amount).
-# So setting the number of entries 1 will produce a full collapsed tree by
-# default. 0 is a special value representing an infinite number of entries
-# and will result in a full expanded tree by default.
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_INDEX_NUM_ENTRIES = 100
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_DOCSET = NO
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_FEEDNAME = "Doxygen generated docs"
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_BUNDLE_ID = org.doxygen.Project
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_NAME = Publisher
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_HTMLHELP = NO
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_FILE =
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
BINARY_TOC = NO
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_QHP = NO
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QCH_FILE =
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_NAMESPACE = org.doxygen.Project
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_VIRTUAL_FOLDER = doc
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-# will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_ECLIPSEHELP = NO
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
ECLIPSE_DOC_ID = org.doxygen.Project
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
-# at top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it. Since the tabs have the same information as the
-# navigation tree you can set this option to NO if you already set
-# GENERATE_TREEVIEW to YES.
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-# Since the tree basically has the same information as the tab index you
-# could consider to set DISABLE_INDEX to NO when enabling this option.
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML
-# documentation. Note that a value of 0 will completely suppress the enum
-# values from appearing in the overview section.
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
ENUM_VALUES_PER_LINE = 1
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
TREEVIEW_WIDTH = 250
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
EXT_LINKS_IN_WINDOW = NO
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you may also need to install MathJax separately and
-# configure the path to it using the MATHJAX_RELPATH option.
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
USE_MATHJAX = NO
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to
-# the MathJax Content Delivery Network so you can quickly see the result without
-# installing MathJax.
-# However, it is strongly recommended to install a local
-# copy of MathJax from http://www.mathjax.org before deployment.
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
-# names that should be enabled during MathJax rendering.
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_EXTENSIONS =
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
SEARCHENGINE = YES
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
SERVER_BASED_SEARCH = NO
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
+# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
GENERATE_LATEX = NO
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
COMPACT_LATEX = NO
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4wide will be used.
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
PAPER_TYPE = a4
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
EXTRA_PACKAGES =
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
-# the generated latex document. The footer should contain everything after
-# the last chapter. If it is left blank doxygen will generate a
-# standard footer. Notice: only use this tag if you know what you are doing!
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
PDF_HYPERLINKS = YES
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
USE_PDFLATEX = YES
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BATCHMODE = NO
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HIDE_INDICES = NO
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
-# http://en.wikipedia.org/wiki/BibTeX for more info.
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BIB_STYLE = plain
#---------------------------------------------------------------------------
-# configuration options related to the RTF output
+# Configuration options related to the RTF output
#---------------------------------------------------------------------------
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
GENERATE_RTF = NO
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_OUTPUT = rtf
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
COMPACT_RTF = NO
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_HYPERLINKS = NO
-# Load style sheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_STYLESHEET_FILE =
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
-# configuration options related to the man page output
+# Configuration options related to the man page output
#---------------------------------------------------------------------------
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
GENERATE_MAN = NO
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_OUTPUT = man
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_EXTENSION = .3
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_LINKS = NO
#---------------------------------------------------------------------------
-# configuration options related to the XML output
+# Configuration options related to the XML output
#---------------------------------------------------------------------------
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
GENERATE_XML = NO
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
XML_OUTPUT = xml
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
-XML_SCHEMA =
+XML_PROGRAMLISTING = YES
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
-XML_DTD =
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
+GENERATE_DOCBOOK = NO
-XML_PROGRAMLISTING = YES
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
+# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
+# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
GENERATE_PERLMOD = NO
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_LATEX = NO
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.
-# This is useful
-# if you want to understand what is going on.
-# On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_PRETTY = YES
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_MAKEVAR_PREFIX =
@@ -1465,106 +1890,128 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
ENABLE_PREPROCESSING = YES
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = NO
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_ONLY_PREDEF = NO
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# pointed to by INCLUDE_PATH will be searched when a #include is found.
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
INCLUDE_FILE_PATTERNS =
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED =
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition that
-# overrules the definition found in the source code.
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_AS_DEFINED =
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all references to function-like macros
-# that are alone on a line, have an all uppercase name, and do not end with a
-# semicolon, because these will confuse the parser if not removed.
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
-# Configuration::additions related to external references
+# Configuration options related to external references
#---------------------------------------------------------------------------
-# The TAGFILES option can be used to specify one or more tagfiles. For each
-# tag file the location of the external documentation should be added. The
-# format of a tag file without this location is as follows:
-#
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
-#
# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths
-# or URLs. Note that each tag file must have a unique name (where the name does
-# NOT include the path). If a tag file is not located in the directory in which
-# doxygen is run, you must also specify the path to the tagfile here.
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
TAGFILES =
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
GENERATE_TAGFILE =
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
ALLEXTERNALS = NO
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
EXTERNAL_GROUPS = YES
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
@@ -1572,222 +2019,295 @@ PERL_PATH = /usr/bin/perl
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
HAVE_DOT = NO
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_NUM_THREADS = 0
-# By default doxygen will use the Helvetica font for all dot files that
-# doxygen generates. When you want a differently looking font you can specify
-# the font name using DOT_FONTNAME. You need to make sure dot is able to find
-# the font, which can be done by putting it in a standard location or by setting
-# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
-# directory containing the font.
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
-# By default doxygen will tell dot to use the Helvetica font.
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
-# set the path where dot can find it.
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# CLASS_DIAGRAMS tag to NO.
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
COLLABORATION_GRAPH = YES
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
GROUP_GRAPHS = YES
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
UML_LOOK = NO
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside
-# the class node. If there are many fields or methods and many nodes the
-# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
-# threshold limits the number of items for each type to make the size more
-# managable. Set this to 0 for no limit. Note that the threshold may be
-# exceeded by 50% before the limit is enforced.
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
UML_LIMIT_NUM_FIELDS = 10
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
TEMPLATE_RELATIONS = NO
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
INCLUDE_GRAPH = YES
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
INCLUDED_BY_GRAPH = YES
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
CALL_GRAPH = NO
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
CALLER_GRAPH = NO
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
GRAPHICAL_HIERARCHY = YES
-# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used. If you choose svg you need to set
-# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible in IE 9+ (other browsers do not have this requirement).
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_IMAGE_FORMAT = png
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
# enable generation of interactive SVG images that allow zooming and panning.
-# Note that this requires a modern browser other than Internet Explorer.
-# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
-# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible. Older versions of IE do not have SVG support.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
INTERACTIVE_SVG = NO
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_PATH =
# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
-# \mscfile command).
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
MSCFILE_DIRS =
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_GRAPH_MAX_NODES = 50
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_MULTI_TARGETS = YES
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
GENERATE_LEGEND = YES
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES
diff --git a/Resources/OrthancPlugin.doxygen b/Resources/OrthancPlugin.doxygen
index 0b68168..7a943b9 100644
--- a/Resources/OrthancPlugin.doxygen
+++ b/Resources/OrthancPlugin.doxygen
@@ -1,110 +1,129 @@
-# Doxyfile 1.8.1.2
+# Doxyfile 1.8.7
# This file describes the settings to be used by the documentation system
# doxygen (www.doxygen.org) for a project.
#
-# All text after a hash (#) is considered a comment and will be ignored.
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
# The format is:
-# TAG = value [value, ...]
-# For lists items can also be appended using:
-# TAG += value [value, ...]
-# Values that contain spaces should be placed between quotes (" ").
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
#---------------------------------------------------------------------------
# Project related configuration options
#---------------------------------------------------------------------------
# This tag specifies the encoding used for all characters in the config file
-# that follow. The default is UTF-8 which is also the encoding used for all
-# text before the first occurrence of this tag. Doxygen uses libiconv (or the
-# iconv built into libc) for the transcoding. See
-# http://www.gnu.org/software/libiconv for the list of possible encodings.
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
DOXYFILE_ENCODING = UTF-8
-# The PROJECT_NAME tag is a single word (or sequence of words) that should
-# identify the project. Note that if you do not use Doxywizard you need
-# to put quotes around the project name if it contains spaces.
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
PROJECT_NAME = "Orthanc Plugin SDK"
-# The PROJECT_NUMBER tag can be used to enter a project or revision number.
-# This could be handy for archiving the generated documentation or
-# if some version control system is used.
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
-PROJECT_NUMBER =
+PROJECT_NUMBER = @ORTHANC_VERSION@
# Using the PROJECT_BRIEF tag one can provide an optional one line description
-# for a project that appears at the top of each page and should give viewer
-# a quick idea about the purpose of the project. Keep the description short.
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
PROJECT_BRIEF = "Documentation of the plugin interface of Orthanc"
-# With the PROJECT_LOGO tag one can specify an logo or icon that is
-# included in the documentation. The maximum height of the logo should not
-# exceed 55 pixels and the maximum width should not exceed 200 pixels.
-# Doxygen will copy the logo to the output directory.
+# With the PROJECT_LOGO tag one can specify an logo or icon that is included in
+# the documentation. The maximum height of the logo should not exceed 55 pixels
+# and the maximum width should not exceed 200 pixels. Doxygen will copy the logo
+# to the output directory.
PROJECT_LOGO = @CMAKE_SOURCE_DIR@/Resources/OrthancLogoDocumentation.png
-# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
-# base path where the generated documentation will be put.
-# If a relative path is entered, it will be relative to the location
-# where doxygen was started. If left blank the current directory will be used.
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
OUTPUT_DIRECTORY = OrthancPluginDocumentation
-# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
-# 4096 sub-directories (in 2 levels) under the output directory of each output
-# format and will distribute the generated files over these directories.
-# Enabling this option can be useful when feeding doxygen a huge amount of
-# source files, where putting all generated files in the same directory would
-# otherwise cause performance problems for the file system.
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
CREATE_SUBDIRS = NO
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
# The OUTPUT_LANGUAGE tag is used to specify the language in which all
# documentation generated by doxygen is written. Doxygen will use this
# information to generate all constant output in the proper language.
-# The default language is English, other supported languages are:
-# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
-# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
-# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
-# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
-# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrillic, Slovak,
-# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
OUTPUT_LANGUAGE = English
-# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
-# include brief member descriptions after the members that are listed in
-# the file and class documentation (similar to JavaDoc).
-# Set to NO to disable this.
+# If the BRIEF_MEMBER_DESC tag is set to YES doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
BRIEF_MEMBER_DESC = YES
-# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
-# the brief description of a member or function before the detailed description.
-# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# If the REPEAT_BRIEF tag is set to YES doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
# brief descriptions will be completely suppressed.
+# The default value is: YES.
REPEAT_BRIEF = NO
-# This tag implements a quasi-intelligent brief description abbreviator
-# that is used to form the text in various listings. Each string
-# in this list, if found as the leading text of the brief description, will be
-# stripped from the text and the result after processing the whole list, is
-# used as the annotated text. Otherwise, the brief description is used as-is.
-# If left blank, the following values are used ("$name" is automatically
-# replaced with the name of the entity): "The $name class" "The $name widget"
-# "The $name file" "is" "provides" "specifies" "contains"
-# "represents" "a" "an" "the"
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
ABBREVIATE_BRIEF =
# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
-# Doxygen will generate a detailed section even if there is only a brief
+# doxygen will generate a detailed section even if there is only a brief
# description.
+# The default value is: NO.
ALWAYS_DETAILED_SEC = NO
@@ -112,169 +131,207 @@ ALWAYS_DETAILED_SEC = NO
# inherited members of a class in the documentation of that class as if those
# members were ordinary class members. Constructors, destructors and assignment
# operators of the base classes will not be shown.
+# The default value is: NO.
INLINE_INHERITED_MEMB = NO
-# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
-# path before files name in the file list and in the header files. If set
-# to NO the shortest path that makes the file name unique will be used.
+# If the FULL_PATH_NAMES tag is set to YES doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
FULL_PATH_NAMES = NO
-# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
-# can be used to strip a user-defined part of the path. Stripping is
-# only done if one of the specified strings matches the left-hand part of
-# the path. The tag can be used to show relative paths in the file list.
-# If left blank the directory from which doxygen is run is used as the
-# path to strip.
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
STRIP_FROM_PATH =
-# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
-# the path mentioned in the documentation of a class, which tells
-# the reader which header file to include in order to use a class.
-# If left blank only the name of the header file containing the class
-# definition is used. Otherwise one should specify the include paths that
-# are normally passed to the compiler using the -I flag.
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
STRIP_FROM_INC_PATH =
-# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
-# (but less readable) file names. This can be useful if your file system
-# doesn't support long names like on DOS, Mac, or CD-ROM.
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
SHORT_NAMES = NO
-# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
-# will interpret the first line (until the first dot) of a JavaDoc-style
-# comment as the brief description. If set to NO, the JavaDoc
-# comments will behave just like regular Qt-style comments
-# (thus requiring an explicit @brief command for a brief description.)
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
JAVADOC_AUTOBRIEF = NO
-# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
-# interpret the first line (until the first dot) of a Qt-style
-# comment as the brief description. If set to NO, the comments
-# will behave just like regular Qt-style comments (thus requiring
-# an explicit \brief command for a brief description.)
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
QT_AUTOBRIEF = NO
-# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
-# treat a multi-line C++ special comment block (i.e. a block of //! or ///
-# comments) as a brief description. This used to be the default behaviour.
-# The new default is to treat a multi-line C++ comment block as a detailed
-# description. Set this tag to YES if you prefer the old behaviour instead.
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
MULTILINE_CPP_IS_BRIEF = NO
-# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
-# member inherits the documentation from any documented member that it
-# re-implements.
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
INHERIT_DOCS = YES
-# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
-# a new page for each member. If set to NO, the documentation of a member will
-# be part of the file/class/namespace that contains it.
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce a
+# new page for each member. If set to NO, the documentation of a member will be
+# part of the file/class/namespace that contains it.
+# The default value is: NO.
SEPARATE_MEMBER_PAGES = NO
-# The TAB_SIZE tag can be used to set the number of spaces in a tab.
-# Doxygen uses this value to replace tabs by spaces in code fragments.
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
TAB_SIZE = 8
-# This tag can be used to specify a number of aliases that acts
-# as commands in the documentation. An alias has the form "name=value".
-# For example adding "sideeffect=\par Side Effects:\n" will allow you to
-# put the command \sideeffect (or @sideeffect) in the documentation, which
-# will result in a user-defined paragraph with heading "Side Effects:".
-# You can put \n's in the value part of an alias to insert newlines.
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
ALIASES =
# This tag can be used to specify a number of word-keyword mappings (TCL only).
-# A mapping has the form "name=value". For example adding
-# "class=itcl::class" will allow you to use the command class in the
-# itcl::class meaning.
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
TCL_SUBST =
-# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
-# sources only. Doxygen will then generate output that is more tailored for C.
-# For instance, some of the names that are used will be different. The list
-# of all members will be omitted, etc.
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
OPTIMIZE_OUTPUT_FOR_C = NO
-# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
-# sources only. Doxygen will then generate output that is more tailored for
-# Java. For instance, namespaces will be presented as packages, qualified
-# scopes will look different, etc.
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
OPTIMIZE_OUTPUT_JAVA = NO
# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
-# sources only. Doxygen will then generate output that is more tailored for
-# Fortran.
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
OPTIMIZE_FOR_FORTRAN = NO
# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
-# sources. Doxygen will then generate output that is tailored for
-# VHDL.
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
OPTIMIZE_OUTPUT_VHDL = NO
# Doxygen selects the parser to use depending on the extension of the files it
-# parses. With this tag you can assign which parser to use for a given extension.
-# Doxygen has a built-in mapping, but you can override or extend it using this
-# tag. The format is ext=language, where ext is a file extension, and language
-# is one of the parsers supported by doxygen: IDL, Java, Javascript, CSharp, C,
-# C++, D, PHP, Objective-C, Python, Fortran, VHDL, C, C++. For instance to make
-# doxygen treat .inc files as Fortran files (default is PHP), and .f files as C
-# (default is Fortran), use: inc=Fortran f=C. Note that for custom extensions
-# you also need to set FILE_PATTERNS otherwise the files are not read by doxygen.
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
EXTENSION_MAPPING =
-# If MARKDOWN_SUPPORT is enabled (the default) then doxygen pre-processes all
-# comments according to the Markdown format, which allows for more readable
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
# documentation. See http://daringfireball.net/projects/markdown/ for details.
-# The output of markdown processing is further processed by doxygen, so you
-# can mix doxygen, HTML, and XML commands with Markdown formatting.
-# Disable only in case of backward compatibilities issues.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
MARKDOWN_SUPPORT = YES
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by by putting a % sign in front of the word
+# or globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
-# to include (a tag file for) the STL sources as input, then you should
-# set this tag to YES in order to let doxygen match functions declarations and
-# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
-# func(std::string) {}). This also makes the inheritance and collaboration
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
BUILTIN_STL_SUPPORT = YES
# If you use Microsoft's C++/CLI language, you should set this option to YES to
# enable parsing support.
+# The default value is: NO.
CPP_CLI_SUPPORT = NO
-# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
-# Doxygen will parse them like normal C++ but will assume all classes use public
-# instead of private inheritance when no explicit protection keyword is present.
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
SIP_SUPPORT = NO
-# For Microsoft's IDL there are propget and propput attributes to indicate getter
-# and setter methods for a property. Setting this option to YES (the default)
-# will make doxygen replace the get and set methods by a property in the
-# documentation. This will only work if the methods are indeed getting or
-# setting a simple type. If this is not the case, or you want to show the
-# methods anyway, you should set this option to NO.
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
IDL_PROPERTY_SUPPORT = YES
@@ -282,67 +339,61 @@ IDL_PROPERTY_SUPPORT = YES
# tag is set to YES, then doxygen will reuse the documentation of the first
# member in the group (if any) for the other members of the group. By default
# all members of a group must be documented explicitly.
+# The default value is: NO.
DISTRIBUTE_GROUP_DOC = NO
-# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
-# the same type (for instance a group of public functions) to be put as a
-# subgroup of that type (e.g. under the Public Functions section). Set it to
-# NO to prevent subgrouping. Alternatively, this can be done per class using
-# the \nosubgrouping command.
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
SUBGROUPING = YES
-# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and
-# unions are shown inside the group in which they are included (e.g. using
-# @ingroup) instead of on a separate page (for HTML and Man pages) or
-# section (for LaTeX and RTF).
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
INLINE_GROUPED_CLASSES = NO
-# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and
-# unions with only public data fields will be shown inline in the documentation
-# of the scope in which they are defined (i.e. file, namespace, or group
-# documentation), provided this scope is documented. If set to NO (the default),
-# structs, classes, and unions are shown on a separate page (for HTML and Man
-# pages) or section (for LaTeX and RTF).
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
INLINE_SIMPLE_STRUCTS = NO
-# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
-# is documented as struct, union, or enum with the name of the typedef. So
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
# with name TypeT. When disabled the typedef will appear as a member of a file,
-# namespace, or class. And the struct will be named TypeS. This can typically
-# be useful for C code in case the coding convention dictates that all compound
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
TYPEDEF_HIDES_STRUCT = NO
-# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
-# determine which symbols to keep in memory and which to flush to disk.
-# When the cache is full, less often used symbols will be written to disk.
-# For small to medium size projects (<1000 input files) the default value is
-# probably good enough. For larger projects a too small cache size can cause
-# doxygen to be busy swapping symbols to and from disk most of the time
-# causing a significant performance penalty.
-# If the system has enough physical memory increasing the cache will improve the
-# performance by keeping more symbols in memory. Note that the value works on
-# a logarithmic scale so increasing the size by one will roughly double the
-# memory usage. The cache size is given by this formula:
-# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
-
-SYMBOL_CACHE_SIZE = 0
-
-# Similar to the SYMBOL_CACHE_SIZE the size of the symbol lookup cache can be
-# set using LOOKUP_CACHE_SIZE. This cache is used to resolve symbols given
-# their name and scope. Since this can be an expensive process and often the
-# same symbol appear multiple times in the code, doxygen keeps a cache of
-# pre-resolved symbols. If the cache is too small doxygen will become slower.
-# If the cache is too large, memory is wasted. The cache size is given by this
-# formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range is 0..9, the default is 0,
-# corresponding to a cache size of 2^16 = 65536 symbols.
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
LOOKUP_CACHE_SIZE = 0
@@ -351,341 +402,392 @@ LOOKUP_CACHE_SIZE = 0
#---------------------------------------------------------------------------
# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
-# documentation are documented, even if no documentation was available.
-# Private class members and static file members will be hidden unless
-# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
EXTRACT_ALL = NO
-# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
-# will be included in the documentation.
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
EXTRACT_PRIVATE = NO
-# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal scope will be included in the documentation.
+# If the EXTRACT_PACKAGE tag is set to YES all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
EXTRACT_PACKAGE = NO
-# If the EXTRACT_STATIC tag is set to YES all static members of a file
-# will be included in the documentation.
+# If the EXTRACT_STATIC tag is set to YES all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
EXTRACT_STATIC = NO
-# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
-# defined locally in source files will be included in the documentation.
-# If set to NO only classes defined in header files are included.
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
EXTRACT_LOCAL_CLASSES = YES
-# This flag is only useful for Objective-C code. When set to YES local
-# methods, which are defined in the implementation section but not in
-# the interface are included in the documentation.
-# If set to NO (the default) only methods in the interface are included.
+# This flag is only useful for Objective-C code. When set to YES local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO only methods in the interface are
+# included.
+# The default value is: NO.
EXTRACT_LOCAL_METHODS = NO
# If this flag is set to YES, the members of anonymous namespaces will be
# extracted and appear in the documentation as a namespace called
-# 'anonymous_namespace{file}', where file will be replaced with the base
-# name of the file that contains the anonymous namespace. By default
-# anonymous namespaces are hidden.
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
EXTRACT_ANON_NSPACES = NO
-# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
-# undocumented members of documented classes, files or namespaces.
-# If set to NO (the default) these members will be included in the
-# various overviews, but no documentation section is generated.
-# This option has no effect if EXTRACT_ALL is enabled.
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
HIDE_UNDOC_MEMBERS = NO
-# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
-# undocumented classes that are normally visible in the class hierarchy.
-# If set to NO (the default) these classes will be included in the various
-# overviews. This option has no effect if EXTRACT_ALL is enabled.
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO these classes will be included in the various overviews. This option has
+# no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
HIDE_UNDOC_CLASSES = NO
-# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
-# friend (class|struct|union) declarations.
-# If set to NO (the default) these declarations will be included in the
-# documentation.
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO these declarations will be
+# included in the documentation.
+# The default value is: NO.
HIDE_FRIEND_COMPOUNDS = YES
-# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
-# documentation blocks found inside the body of a function.
-# If set to NO (the default) these blocks will be appended to the
-# function's detailed documentation block.
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
HIDE_IN_BODY_DOCS = NO
-# The INTERNAL_DOCS tag determines if documentation
-# that is typed after a \internal command is included. If the tag is set
-# to NO (the default) then the documentation will be excluded.
-# Set it to YES to include the internal documentation.
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
INTERNAL_DOCS = NO
-# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
-# file names in lower-case letters. If set to YES upper-case letters are also
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES upper-case letters are also
# allowed. This is useful if you have classes or files whose names only differ
# in case and if your file system supports case sensitive file names. Windows
# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
CASE_SENSE_NAMES = YES
-# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
-# will show members with their full class and namespace scopes in the
-# documentation. If set to YES the scope will be hidden.
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES the
+# scope will be hidden.
+# The default value is: NO.
HIDE_SCOPE_NAMES = NO
-# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
-# will put a list of the files that are included by a file in the documentation
-# of that file.
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
SHOW_INCLUDE_FILES = YES
-# If the FORCE_LOCAL_INCLUDES tag is set to YES then Doxygen
-# will list include files with double quotes in the documentation
-# rather than with sharp brackets.
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
FORCE_LOCAL_INCLUDES = NO
-# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
-# is inserted in the documentation for inline members.
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
INLINE_INFO = YES
-# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
-# will sort the (detailed) documentation of file and class members
-# alphabetically by member name. If set to NO the members will appear in
-# declaration order.
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order.
+# The default value is: YES.
SORT_MEMBER_DOCS = YES
-# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
-# brief documentation of file, namespace and class members alphabetically
-# by member name. If set to NO (the default) the members will appear in
-# declaration order.
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
SORT_BRIEF_DOCS = NO
-# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
-# will sort the (brief and detailed) documentation of class members so that
-# constructors and destructors are listed first. If set to NO (the default)
-# the constructors will appear in the respective orders defined by
-# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
-# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
-# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
SORT_MEMBERS_CTORS_1ST = NO
-# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
-# hierarchy of group names into alphabetical order. If set to NO (the default)
-# the group names will appear in their defined order.
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
SORT_GROUP_NAMES = NO
-# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
-# sorted by fully-qualified names, including namespaces. If set to
-# NO (the default), the class list will be sorted only by class name,
-# not including the namespace part.
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
-# Note: This option applies only to the class list, not to the
-# alphabetical list.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
SORT_BY_SCOPE_NAME = NO
-# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to
-# do proper type resolution of all parameters of a function it will reject a
-# match between the prototype and the implementation of a member function even
-# if there is only one candidate or it is obvious which candidate to choose
-# by doing a simple string match. By disabling STRICT_PROTO_MATCHING doxygen
-# will still accept a match between prototype and implementation in such cases.
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
STRICT_PROTO_MATCHING = NO
-# The GENERATE_TODOLIST tag can be used to enable (YES) or
-# disable (NO) the todo list. This list is created by putting \todo
-# commands in the documentation.
+# The GENERATE_TODOLIST tag can be used to enable ( YES) or disable ( NO) the
+# todo list. This list is created by putting \todo commands in the
+# documentation.
+# The default value is: YES.
GENERATE_TODOLIST = YES
-# The GENERATE_TESTLIST tag can be used to enable (YES) or
-# disable (NO) the test list. This list is created by putting \test
-# commands in the documentation.
+# The GENERATE_TESTLIST tag can be used to enable ( YES) or disable ( NO) the
+# test list. This list is created by putting \test commands in the
+# documentation.
+# The default value is: YES.
GENERATE_TESTLIST = YES
-# The GENERATE_BUGLIST tag can be used to enable (YES) or
-# disable (NO) the bug list. This list is created by putting \bug
-# commands in the documentation.
+# The GENERATE_BUGLIST tag can be used to enable ( YES) or disable ( NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
GENERATE_BUGLIST = YES
-# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
-# disable (NO) the deprecated list. This list is created by putting
-# \deprecated commands in the documentation.
+# The GENERATE_DEPRECATEDLIST tag can be used to enable ( YES) or disable ( NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
GENERATE_DEPRECATEDLIST= YES
-# The ENABLED_SECTIONS tag can be used to enable conditional
-# documentation sections, marked by \if sectionname ... \endif.
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
ENABLED_SECTIONS =
-# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
-# the initial value of a variable or macro consists of for it to appear in
-# the documentation. If the initializer consists of more lines than specified
-# here it will be hidden. Use a value of 0 to hide initializers completely.
-# The appearance of the initializer of individual variables and macros in the
-# documentation can be controlled using \showinitializer or \hideinitializer
-# command in the documentation regardless of this setting.
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
MAX_INITIALIZER_LINES = 0
-# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
-# at the bottom of the documentation of classes and structs. If set to YES the
-# list will mention the files that were used to generate the documentation.
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES the list
+# will mention the files that were used to generate the documentation.
+# The default value is: YES.
SHOW_USED_FILES = YES
-# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
-# This will remove the Files entry from the Quick Index and from the
-# Folder Tree View (if specified). The default is YES.
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
SHOW_FILES = YES
-# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
-# Namespaces page.
-# This will remove the Namespaces entry from the Quick Index
-# and from the Folder Tree View (if specified). The default is YES.
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
SHOW_NAMESPACES = YES
# The FILE_VERSION_FILTER tag can be used to specify a program or script that
# doxygen should invoke to get the current version for each file (typically from
# the version control system). Doxygen will invoke the program by executing (via
-# popen()) the command <command> <input-file>, where <command> is the value of
-# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
-# provided by doxygen. Whatever the program writes to standard output
-# is used as the file version. See the manual for examples.
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
FILE_VERSION_FILTER =
# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
# by doxygen. The layout file controls the global structure of the generated
# output files in an output format independent way. To create the layout file
-# that represents doxygen's defaults, run doxygen with the -l option.
-# You can optionally specify a file name after the option, if omitted
-# DoxygenLayout.xml will be used as the name of the layout file.
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
LAYOUT_FILE =
-# The CITE_BIB_FILES tag can be used to specify one or more bib files
-# containing the references data. This must be a list of .bib files. The
-# .bib extension is automatically appended if omitted. Using this command
-# requires the bibtex tool to be installed. See also
-# http://en.wikipedia.org/wiki/BibTeX for more info. For LaTeX the style
-# of the bibliography can be controlled using LATEX_BIB_STYLE. To use this
-# feature you need bibtex and perl available in the search path.
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. Do not use file names with spaces, bibtex cannot handle them. See
+# also \cite for info how to create references.
CITE_BIB_FILES =
#---------------------------------------------------------------------------
-# configuration options related to warning and progress messages
+# Configuration options related to warning and progress messages
#---------------------------------------------------------------------------
-# The QUIET tag can be used to turn on/off the messages that are generated
-# by doxygen. Possible values are YES and NO. If left blank NO is used.
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
QUIET = NO
# The WARNINGS tag can be used to turn on/off the warning messages that are
-# generated by doxygen. Possible values are YES and NO. If left blank
-# NO is used.
+# generated to standard error ( stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
WARNINGS = YES
-# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
-# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
-# automatically be disabled.
+# If the WARN_IF_UNDOCUMENTED tag is set to YES, then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
WARN_IF_UNDOCUMENTED = YES
-# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
-# potential errors in the documentation, such as not documenting some
-# parameters in a documented function, or documenting parameters that
-# don't exist or using markup commands wrongly.
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
WARN_IF_DOC_ERROR = YES
-# The WARN_NO_PARAMDOC option can be enabled to get warnings for
-# functions that are documented, but have no documentation for their parameters
-# or return value. If set to NO (the default) doxygen will only warn about
-# wrong or incomplete parameter documentation, but not about the absence of
-# documentation.
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO doxygen will only warn about wrong or incomplete parameter
+# documentation, but not about the absence of documentation.
+# The default value is: NO.
WARN_NO_PARAMDOC = YES
-# The WARN_FORMAT tag determines the format of the warning messages that
-# doxygen can produce. The string should contain the $file, $line, and $text
-# tags, which will be replaced by the file and line number from which the
-# warning originated and the warning text. Optionally the format may contain
-# $version, which will be replaced by the version of the file (if it could
-# be obtained via FILE_VERSION_FILTER)
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
WARN_FORMAT = "$file:$line: $text"
-# The WARN_LOGFILE tag can be used to specify a file to which warning
-# and error messages should be written. If left blank the output is written
-# to stderr.
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
WARN_LOGFILE =
#---------------------------------------------------------------------------
-# configuration options related to the input files
+# Configuration options related to the input files
#---------------------------------------------------------------------------
-# The INPUT tag can be used to specify the files and/or directories that contain
-# documented source files. You may enter file names like "myfile.cpp" or
-# directories like "/usr/src/myproject". Separate the files or directories
-# with spaces.
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces.
+# Note: If this tag is empty the current directory is searched.
INPUT = @CMAKE_SOURCE_DIR@/Plugins/Include/orthanc/OrthancCPlugin.h \
@CMAKE_SOURCE_DIR@/Plugins/Include/orthanc/OrthancCDatabasePlugin.h \
@CMAKE_SOURCE_DIR@/Plugins/Include/orthanc/OrthancCppDatabasePlugin.h
# This tag can be used to specify the character encoding of the source files
-# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
-# also the default input encoding. Doxygen uses libiconv (or the iconv built
-# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
-# the list of possible encodings.
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
INPUT_ENCODING = UTF-8
# If the value of the INPUT tag contains directories, you can use the
-# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank the following patterns are tested:
-# *.c *.cc *.cxx *.cpp *.c++ *.d *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh
-# *.hxx *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.dox *.py
-# *.f90 *.f *.for *.vhd *.vhdl
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank the
+# following patterns are tested:*.c, *.cc, *.cxx, *.cpp, *.c++, *.java, *.ii,
+# *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h, *.hh, *.hxx, *.hpp,
+# *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc, *.m, *.markdown,
+# *.md, *.mm, *.dox, *.py, *.f90, *.f, *.for, *.tcl, *.vhd, *.vhdl, *.ucf,
+# *.qsf, *.as and *.js.
FILE_PATTERNS = *.h
-# The RECURSIVE tag can be used to turn specify whether or not subdirectories
-# should be searched for input files as well. Possible values are YES and NO.
-# If left blank NO is used.
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
RECURSIVE = YES
# The EXCLUDE tag can be used to specify files and/or directories that should be
# excluded from the INPUT source files. This way you can easily exclude a
# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
# Note that relative paths are relative to the directory from which doxygen is
# run.
@@ -694,14 +796,16 @@ EXCLUDE =
# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
# directories that are symbolic links (a Unix file system feature) are excluded
# from the input.
+# The default value is: NO.
EXCLUDE_SYMLINKS = NO
# If the value of the INPUT tag contains directories, you can use the
# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
-# certain files from those directories. Note that the wildcards are matched
-# against the file with absolute path, so to exclude all test directories
-# for example use the pattern */test/*
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
EXCLUDE_PATTERNS =
@@ -710,755 +814,1077 @@ EXCLUDE_PATTERNS =
# output. The symbol name can be a fully qualified name, a word, or if the
# wildcard * is used, a substring. Examples: ANamespace, AClass,
# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
-EXCLUDE_SYMBOLS = _OrthancPlugin* OrthancPluginGetName
+EXCLUDE_SYMBOLS = _OrthancPlugin* \
+ OrthancPluginGetName
-# The EXAMPLE_PATH tag can be used to specify one or more files or
-# directories that contain example code fragments that are included (see
-# the \include command).
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
EXAMPLE_PATH =
# If the value of the EXAMPLE_PATH tag contains directories, you can use the
-# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
-# and *.h) to filter out the source-files in the directories. If left
-# blank all files are included.
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
EXAMPLE_PATTERNS =
# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
-# searched for input files to be used with the \include or \dontinclude
-# commands irrespective of the value of the RECURSIVE tag.
-# Possible values are YES and NO. If left blank NO is used.
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
EXAMPLE_RECURSIVE = NO
-# The IMAGE_PATH tag can be used to specify one or more files or
-# directories that contain image that are included in the documentation (see
-# the \image command).
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
IMAGE_PATH =
# The INPUT_FILTER tag can be used to specify a program that doxygen should
# invoke to filter for each input file. Doxygen will invoke the filter program
-# by executing (via popen()) the command <filter> <input-file>, where <filter>
-# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
-# input file. Doxygen will then use the output that the filter program writes
-# to standard output.
-# If FILTER_PATTERNS is specified, this tag will be
-# ignored.
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
INPUT_FILTER =
# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
-# basis.
-# Doxygen will compare the file name with each pattern and apply the
-# filter if there is a match.
-# The filters are a list of the form:
-# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
-# info on how filters are used. If FILTER_PATTERNS is empty or if
-# non of the patterns match the file name, INPUT_FILTER is applied.
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
FILTER_PATTERNS =
# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
-# INPUT_FILTER) will be used to filter the input files when producing source
-# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# INPUT_FILTER ) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
FILTER_SOURCE_FILES = NO
# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
-# pattern. A pattern will override the setting for FILTER_PATTERN (if any)
-# and it is also possible to disable source filtering for a specific pattern
-# using *.ext= (so without naming a filter). This option only has effect when
-# FILTER_SOURCE_FILES is enabled.
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
FILTER_SOURCE_PATTERNS =
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
#---------------------------------------------------------------------------
-# configuration options related to source browsing
+# Configuration options related to source browsing
#---------------------------------------------------------------------------
-# If the SOURCE_BROWSER tag is set to YES then a list of source files will
-# be generated. Documented entities will be cross-referenced with these sources.
-# Note: To get rid of all source code in the generated output, make sure also
-# VERBATIM_HEADERS is set to NO.
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
SOURCE_BROWSER = NO
-# Setting the INLINE_SOURCES tag to YES will include the body
-# of functions and classes directly in the documentation.
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
INLINE_SOURCES = NO
-# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
-# doxygen to hide any special comment blocks from generated source code
-# fragments. Normal C, C++ and Fortran comments will always remain visible.
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
STRIP_CODE_COMMENTS = YES
-# If the REFERENCED_BY_RELATION tag is set to YES
-# then for each documented function all documented
-# functions referencing it will be listed.
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
REFERENCED_BY_RELATION = NO
-# If the REFERENCES_RELATION tag is set to YES
-# then for each documented function all documented entities
-# called/used by that function will be listed.
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
REFERENCES_RELATION = NO
-# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
-# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
-# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
-# link to the source code.
-# Otherwise they will link to the documentation.
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES, then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
REFERENCES_LINK_SOURCE = YES
-# If the USE_HTAGS tag is set to YES then the references to source code
-# will point to the HTML generated by the htags(1) tool instead of doxygen
-# built-in source browser. The htags tool is part of GNU's global source
-# tagging system (see http://www.gnu.org/software/global/global.html). You
-# will need version 4.8.6 or higher.
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
USE_HTAGS = NO
-# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
-# will generate a verbatim copy of the header file for each class for
-# which an include is specified. Set to NO to disable this.
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
VERBATIM_HEADERS = YES
#---------------------------------------------------------------------------
-# configuration options related to the alphabetical class index
+# Configuration options related to the alphabetical class index
#---------------------------------------------------------------------------
-# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
-# of all compounds will be generated. Enable this if the project
-# contains a lot of classes, structs, unions or interfaces.
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
ALPHABETICAL_INDEX = YES
-# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
-# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
-# in which this list will be split (can be a number in the range [1..20])
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
COLS_IN_ALPHA_INDEX = 5
-# In case all classes in a project start with a common prefix, all
-# classes will be put under the same header in the alphabetical index.
-# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
-# should be ignored while generating the index headers.
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
IGNORE_PREFIX =
#---------------------------------------------------------------------------
-# configuration options related to the HTML output
+# Configuration options related to the HTML output
#---------------------------------------------------------------------------
-# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
-# generate HTML output.
+# If the GENERATE_HTML tag is set to YES doxygen will generate HTML output
+# The default value is: YES.
GENERATE_HTML = YES
-# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `html' will be used as the default path.
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_OUTPUT = doc
-# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
-# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
-# doxygen will generate files with .html extension.
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FILE_EXTENSION = .html
-# The HTML_HEADER tag can be used to specify a personal HTML header for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard header. Note that when using a custom header you are responsible
-# for the proper inclusion of any scripts and style sheets that doxygen
-# needs, which is dependent on the configuration options used.
-# It is advised to generate a default header using "doxygen -w html
-# header.html footer.html stylesheet.css YourConfigFile" and then modify
-# that header. Note that the header is subject to change so you typically
-# have to redo this when upgrading to a newer version of doxygen or when
-# changing the value of configuration settings such as GENERATE_TREEVIEW!
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_HEADER =
-# The HTML_FOOTER tag can be used to specify a personal HTML footer for
-# each generated HTML page. If it is left blank doxygen will generate a
-# standard footer.
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_FOOTER =
-# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
-# style sheet that is used by each HTML page. It can be used to
-# fine-tune the look of the HTML output. If the tag is left blank doxygen
-# will generate a default style sheet. Note that doxygen will try to copy
-# the style sheet file to the HTML output directory, so don't put your own
-# style sheet in the HTML output directory as well, or it will be erased!
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_STYLESHEET =
+# The HTML_EXTRA_STYLESHEET tag can be used to specify an additional user-
+# defined cascading style sheet that is included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefor more robust against future updates.
+# Doxygen will copy the style sheet file to the output directory. For an example
+# see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
# other source files which should be copied to the HTML output directory. Note
# that these files will be copied to the base HTML output directory. Use the
-# $relpath$ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
-# files. In the HTML_STYLESHEET file, use the file name only. Also note that
-# the files will be copied as-is; there are no commands or markers available.
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_EXTRA_FILES =
-# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output.
-# Doxygen will adjust the colors in the style sheet and background images
-# according to this color. Hue is specified as an angle on a colorwheel,
-# see http://en.wikipedia.org/wiki/Hue for more information.
-# For instance the value 0 represents red, 60 is yellow, 120 is green,
-# 180 is cyan, 240 is blue, 300 purple, and 360 is red again.
-# The allowed range is 0 to 359.
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the stylesheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_HUE = 220
-# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of
-# the colors in the HTML output. For a value of 0 the output will use
-# grayscales only. A value of 255 will produce the most vivid colors.
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_SAT = 100
-# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to
-# the luminance component of the colors in the HTML output. Values below
-# 100 gradually make the output lighter, whereas values above 100 make
-# the output darker. The value divided by 100 is the actual gamma applied,
-# so 80 represents a gamma of 0.8, The value 220 represents a gamma of 2.2,
-# and 100 does not change the gamma.
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_COLORSTYLE_GAMMA = 80
# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
-# page will contain the date and time when the page was generated. Setting
-# this to NO can help when comparing the output of multiple runs.
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_TIMESTAMP = NO
# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
# documentation will contain sections that can be hidden and shown after the
# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_DYNAMIC_SECTIONS = NO
-# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of
-# entries shown in the various tree structured indices initially; the user
-# can expand and collapse entries dynamically later on. Doxygen will expand
-# the tree to such a level that at most the specified number of entries are
-# visible (unless a fully collapsed tree already exceeds this amount).
-# So setting the number of entries 1 will produce a full collapsed tree by
-# default. 0 is a special value representing an infinite number of entries
-# and will result in a full expanded tree by default.
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
HTML_INDEX_NUM_ENTRIES = 100
-# If the GENERATE_DOCSET tag is set to YES, additional index files
-# will be generated that can be used as input for Apple's Xcode 3
-# integrated development environment, introduced with OSX 10.5 (Leopard).
-# To create a documentation set, doxygen will generate a Makefile in the
-# HTML output directory. Running make will produce the docset in that
-# directory and running "make install" will install the docset in
-# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
-# it at startup.
-# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_DOCSET = NO
-# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
-# feed. A documentation feed provides an umbrella under which multiple
-# documentation sets from a single provider (such as a company or product suite)
-# can be grouped.
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_FEEDNAME = "Doxygen generated docs"
-# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
-# should uniquely identify the documentation set bundle. This should be a
-# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
-# will append .docset to the name.
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_BUNDLE_ID = org.doxygen.Project
-# When GENERATE_PUBLISHER_ID tag specifies a string that should uniquely identify
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
# the documentation publisher. This should be a reverse domain-name style
# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_ID = org.doxygen.Publisher
-# The GENERATE_PUBLISHER_NAME tag identifies the documentation publisher.
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
DOCSET_PUBLISHER_NAME = Publisher
-# If the GENERATE_HTMLHELP tag is set to YES, additional index files
-# will be generated that can be used as input for tools like the
-# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
-# of the generated HTML documentation.
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_HTMLHELP = NO
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
-# be used to specify the file name of the resulting .chm file. You
-# can add a path in front of the file if the result should not be
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_FILE =
-# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
-# be used to specify the location (absolute path including file name) of
-# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
-# the HTML help compiler on the generated index.hhp.
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler ( hhc.exe). If non-empty
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
HHC_LOCATION =
-# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
-# controls if a separate .chi index file is generated (YES) or that
-# it should be included in the master .chm file (NO).
+# The GENERATE_CHI flag controls if a separate .chi index file is generated (
+# YES) or that it should be included in the master .chm file ( NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
GENERATE_CHI = NO
-# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
-# is used to encode HtmlHelp index (hhk), content (hhc) and project file
-# content.
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index ( hhk), content ( hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
CHM_INDEX_ENCODING =
-# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
-# controls whether a binary table of contents is generated (YES) or a
-# normal table of contents (NO) in the .chm file.
+# The BINARY_TOC flag controls whether a binary table of contents is generated (
+# YES) or a normal table of contents ( NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
BINARY_TOC = NO
-# The TOC_EXPAND flag can be set to YES to add extra items for group members
-# to the contents of the HTML help documentation and to the tree view.
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
TOC_EXPAND = NO
# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
-# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated
-# that can be used as input for Qt's qhelpgenerator to generate a
-# Qt Compressed Help (.qch) of the generated HTML documentation.
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_QHP = NO
-# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
-# be used to specify the file name of the resulting .qch file.
-# The path specified is relative to the HTML output folder.
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QCH_FILE =
-# The QHP_NAMESPACE tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#namespace
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_NAMESPACE = org.doxygen.Project
-# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
-# Qt Help Project output. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_VIRTUAL_FOLDER = doc
-# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to
-# add. For more information please see
-# http://doc.trolltech.com/qthelpproject.html#custom-filters
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_NAME =
-# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the
-# custom filter to add. For more information please see
-# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">
-# Qt Help Project / Custom Filters</a>.
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_CUST_FILTER_ATTRS =
# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
-# project's
-# filter section matches.
-# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">
-# Qt Help Project / Filter Attributes</a>.
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHP_SECT_FILTER_ATTRS =
-# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
-# be used to specify the location of Qt's qhelpgenerator.
-# If non-empty doxygen will try to run qhelpgenerator on the generated
-# .qhp file.
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
QHG_LOCATION =
-# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files
-# will be generated, which together with the HTML files, form an Eclipse help
-# plugin. To install this plugin and make it available under the help contents
-# menu in Eclipse, the contents of the directory containing the HTML and XML
-# files needs to be copied into the plugins directory of eclipse. The name of
-# the directory within the plugins directory should be the same as
-# the ECLIPSE_DOC_ID value. After copying Eclipse needs to be restarted before
-# the help appears.
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_ECLIPSEHELP = NO
-# A unique identifier for the eclipse help plugin. When installing the plugin
-# the directory name containing the HTML and XML files should also have
-# this name.
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
ECLIPSE_DOC_ID = org.doxygen.Project
-# The DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs)
-# at top of each HTML page. The value NO (the default) enables the index and
-# the value YES disables it. Since the tabs have the same information as the
-# navigation tree you can set this option to NO if you already set
-# GENERATE_TREEVIEW to YES.
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
DISABLE_INDEX = NO
# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
-# structure should be generated to display hierarchical information.
-# If the tag value is set to YES, a side panel will be generated
-# containing a tree-like index structure (just like the one that
-# is generated for HTML Help). For this to work a browser that supports
-# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
-# Windows users are probably better off using the HTML help feature.
-# Since the tree basically has the same information as the tab index you
-# could consider to set DISABLE_INDEX to NO when enabling this option.
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom stylesheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
GENERATE_TREEVIEW = NO
-# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values
-# (range [0,1..20]) that doxygen will group on one line in the generated HTML
-# documentation. Note that a value of 0 will completely suppress the enum
-# values from appearing in the overview section.
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
ENUM_VALUES_PER_LINE = 1
-# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
-# used to set the initial width (in pixels) of the frame in which the tree
-# is shown.
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
TREEVIEW_WIDTH = 250
-# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open
-# links to external symbols imported via tag files in a separate window.
+# When the EXT_LINKS_IN_WINDOW option is set to YES doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
EXT_LINKS_IN_WINDOW = NO
-# Use this tag to change the font size of Latex formulas included
-# as images in the HTML documentation. The default is 10. Note that
-# when you change the font size after a successful doxygen run you need
-# to manually remove any form_*.png images from the HTML output directory
-# to force them to be regenerated.
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_FONTSIZE = 10
# Use the FORMULA_TRANPARENT tag to determine whether or not the images
-# generated for formulas are transparent PNGs. Transparent PNGs are
-# not supported properly for IE 6.0, but are supported on all modern browsers.
-# Note that when changing this option you need to delete any form_*.png files
-# in the HTML output before the changes have effect.
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
FORMULA_TRANSPARENT = YES
-# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax
-# (see http://www.mathjax.org) which uses client side Javascript for the
-# rendering instead of using prerendered bitmaps. Use this if you do not
-# have LaTeX installed or if you want to formulas look prettier in the HTML
-# output. When enabled you may also need to install MathJax separately and
-# configure the path to it using the MATHJAX_RELPATH option.
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using prerendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
USE_MATHJAX = NO
-# When MathJax is enabled you need to specify the location relative to the
-# HTML output directory using the MATHJAX_RELPATH option. The destination
-# directory should contain the MathJax.js script. For instance, if the mathjax
-# directory is located at the same level as the HTML output directory, then
-# MATHJAX_RELPATH should be ../mathjax. The default value points to
-# the MathJax Content Delivery Network so you can quickly see the result without
-# installing MathJax.
-# However, it is strongly recommended to install a local
-# copy of MathJax from http://www.mathjax.org before deployment.
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_RELPATH = http://www.mathjax.org/mathjax
-# The MATHJAX_EXTENSIONS tag can be used to specify one or MathJax extension
-# names that should be enabled during MathJax rendering.
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
MATHJAX_EXTENSIONS =
-# When the SEARCHENGINE tag is enabled doxygen will generate a search box
-# for the HTML output. The underlying search engine uses javascript
-# and DHTML and should work on any modern browser. Note that when using
-# HTML help (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets
-# (GENERATE_DOCSET) there is already a search function so this one should
-# typically be disabled. For large projects the javascript based search engine
-# can be slow, then enabling SERVER_BASED_SEARCH may provide a better solution.
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
SEARCHENGINE = NO
# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
-# implemented using a PHP enabled web server instead of at the web client
-# using Javascript. Doxygen will generate the search PHP script and index
-# file to put on the web server. The advantage of the server
-# based approach is that it scales better to large projects and allows
-# full text search. The disadvantages are that it is more difficult to setup
-# and does not have live searching capabilities.
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
SERVER_BASED_SEARCH = NO
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer ( doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
#---------------------------------------------------------------------------
-# configuration options related to the LaTeX output
+# Configuration options related to the LaTeX output
#---------------------------------------------------------------------------
-# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
-# generate Latex output.
+# If the GENERATE_LATEX tag is set to YES doxygen will generate LaTeX output.
+# The default value is: YES.
GENERATE_LATEX = NO
-# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `latex' will be used as the default path.
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_OUTPUT = latex
# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
-# invoked. If left blank `latex' will be used as the default command name.
-# Note that when enabling USE_PDFLATEX this option is only used for
-# generating bitmaps for formulas in the HTML output, but not in the
-# Makefile that is written to the output directory.
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_CMD_NAME = latex
-# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
-# generate index for LaTeX. If left blank `makeindex' will be used as the
-# default command name.
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
MAKEINDEX_CMD_NAME = makeindex
-# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
-# LaTeX documents. This may be useful for small projects and may help to
-# save some trees in general.
+# If the COMPACT_LATEX tag is set to YES doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
COMPACT_LATEX = NO
-# The PAPER_TYPE tag can be used to set the paper type that is used
-# by the printer. Possible values are: a4, letter, legal and
-# executive. If left blank a4wide will be used.
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
PAPER_TYPE = a4
-# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
-# packages that should be included in the LaTeX output.
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. To get the times font for
+# instance you can specify
+# EXTRA_PACKAGES=times
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
EXTRA_PACKAGES =
-# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
-# the generated latex document. The header should contain everything until
-# the first chapter. If it is left blank doxygen will generate a
-# standard header. Notice: only use this tag if you know what you are doing!
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber. Doxygen will
+# replace them by respectively the title of the page, the current date and time,
+# only the current date, the version number of doxygen, the project name (see
+# PROJECT_NAME), or the project number (see PROJECT_NUMBER).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HEADER =
-# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for
-# the generated latex document. The footer should contain everything after
-# the last chapter. If it is left blank doxygen will generate a
-# standard footer. Notice: only use this tag if you know what you are doing!
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_FOOTER =
-# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
-# is prepared for conversion to pdf (using ps2pdf). The pdf file will
-# contain links (just like the HTML output) instead of page references
-# This makes the output suitable for online browsing using a pdf viewer.
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
PDF_HYPERLINKS = YES
-# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
-# plain latex in the generated Makefile. Set this option to YES to get a
+# If the LATEX_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES to get a
# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
USE_PDFLATEX = YES
-# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
-# command to the generated LaTeX files. This will instruct LaTeX to keep
-# running if errors occur, instead of asking the user for help.
-# This option is also used when generating formulas in HTML.
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BATCHMODE = NO
-# If LATEX_HIDE_INDICES is set to YES then doxygen will not
-# include the index chapters (such as File Index, Compound Index, etc.)
-# in the output.
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_HIDE_INDICES = NO
-# If LATEX_SOURCE_CODE is set to YES then doxygen will include
-# source code with syntax highlighting in the LaTeX output.
-# Note that which sources are shown also depends on other settings
-# such as SOURCE_BROWSER.
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_SOURCE_CODE = NO
# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
-# bibliography, e.g. plainnat, or ieeetr. The default style is "plain". See
-# http://en.wikipedia.org/wiki/BibTeX for more info.
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
LATEX_BIB_STYLE = plain
#---------------------------------------------------------------------------
-# configuration options related to the RTF output
+# Configuration options related to the RTF output
#---------------------------------------------------------------------------
-# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
-# The RTF output is optimized for Word 97 and may not look very pretty with
-# other RTF readers or editors.
+# If the GENERATE_RTF tag is set to YES doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
GENERATE_RTF = NO
-# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `rtf' will be used as the default path.
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_OUTPUT = rtf
-# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
-# RTF documents. This may be useful for small projects and may help to
-# save some trees in general.
+# If the COMPACT_RTF tag is set to YES doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
COMPACT_RTF = NO
-# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
-# will contain hyperlink fields. The RTF file will
-# contain links (just like the HTML output) instead of page references.
-# This makes the output suitable for online browsing using WORD or other
-# programs which support those fields.
-# Note: wordpad (write) and others do not support links.
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_HYPERLINKS = NO
-# Load style sheet definitions from file. Syntax is similar to doxygen's
-# config file, i.e. a series of assignments. You only have to provide
-# replacements, missing definitions are set to their default value.
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_STYLESHEET_FILE =
-# Set optional variables used in the generation of an rtf document.
-# Syntax is similar to doxygen's config file.
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
RTF_EXTENSIONS_FILE =
#---------------------------------------------------------------------------
-# configuration options related to the man page output
+# Configuration options related to the man page output
#---------------------------------------------------------------------------
-# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
-# generate man pages
+# If the GENERATE_MAN tag is set to YES doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
GENERATE_MAN = NO
-# The MAN_OUTPUT tag is used to specify where the man pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `man' will be used as the default path.
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_OUTPUT = man
-# The MAN_EXTENSION tag determines the extension that is added to
-# the generated man pages (default is the subroutine's section .3)
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_EXTENSION = .3
-# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
-# then it will generate one additional man file for each entity
-# documented in the real man page(s). These additional files
-# only source the real man page, but without them the man command
-# would be unable to find the correct page. The default is NO.
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
MAN_LINKS = NO
#---------------------------------------------------------------------------
-# configuration options related to the XML output
+# Configuration options related to the XML output
#---------------------------------------------------------------------------
-# If the GENERATE_XML tag is set to YES Doxygen will
-# generate an XML file that captures the structure of
-# the code including all documentation.
+# If the GENERATE_XML tag is set to YES doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
GENERATE_XML = NO
-# The XML_OUTPUT tag is used to specify where the XML pages will be put.
-# If a relative path is entered the value of OUTPUT_DIRECTORY will be
-# put in front of it. If left blank `xml' will be used as the default path.
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
XML_OUTPUT = xml
-# The XML_SCHEMA tag can be used to specify an XML schema,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+# If the XML_PROGRAMLISTING tag is set to YES doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
-XML_SCHEMA =
+XML_PROGRAMLISTING = YES
-# The XML_DTD tag can be used to specify an XML DTD,
-# which can be used by a validating XML parser to check the
-# syntax of the XML files.
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
-XML_DTD =
+# If the GENERATE_DOCBOOK tag is set to YES doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
-# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
-# dump the program listings (including syntax highlighting
-# and cross-referencing information) to the XML output. Note that
-# enabling this will significantly increase the size of the XML output.
+GENERATE_DOCBOOK = NO
-XML_PROGRAMLISTING = YES
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
#---------------------------------------------------------------------------
-# configuration options for the AutoGen Definitions output
+# Configuration options for the AutoGen Definitions output
#---------------------------------------------------------------------------
-# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
-# generate an AutoGen Definitions (see autogen.sf.net) file
-# that captures the structure of the code including all
-# documentation. Note that this feature is still experimental
-# and incomplete at the moment.
+# If the GENERATE_AUTOGEN_DEF tag is set to YES doxygen will generate an AutoGen
+# Definitions (see http://autogen.sf.net) file that captures the structure of
+# the code including all documentation. Note that this feature is still
+# experimental and incomplete at the moment.
+# The default value is: NO.
GENERATE_AUTOGEN_DEF = NO
#---------------------------------------------------------------------------
-# configuration options related to the Perl module output
+# Configuration options related to the Perl module output
#---------------------------------------------------------------------------
-# If the GENERATE_PERLMOD tag is set to YES Doxygen will
-# generate a Perl module file that captures the structure of
-# the code including all documentation. Note that this
-# feature is still experimental and incomplete at the
-# moment.
+# If the GENERATE_PERLMOD tag is set to YES doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
GENERATE_PERLMOD = NO
-# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
-# the necessary Makefile rules, Perl scripts and LaTeX code to be able
-# to generate PDF and DVI output from the Perl module output.
+# If the PERLMOD_LATEX tag is set to YES doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_LATEX = NO
-# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
-# nicely formatted so it can be parsed by a human reader.
-# This is useful
-# if you want to understand what is going on.
-# On the other hand, if this
-# tag is set to NO the size of the Perl module output will be much smaller
-# and Perl will parse it just the same.
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_PRETTY = YES
-# The names of the make variables in the generated doxyrules.make file
-# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
-# This is useful so different doxyrules.make files included by the same
-# Makefile don't overwrite each other's variables.
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
PERLMOD_MAKEVAR_PREFIX =
@@ -1466,106 +1892,128 @@ PERLMOD_MAKEVAR_PREFIX =
# Configuration options related to the preprocessor
#---------------------------------------------------------------------------
-# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
-# evaluate all C-preprocessor directives found in the sources and include
-# files.
+# If the ENABLE_PREPROCESSING tag is set to YES doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
ENABLE_PREPROCESSING = YES
-# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
-# names in the source code. If set to NO (the default) only conditional
-# compilation will be performed. Macro expansion can be done in a controlled
-# way by setting EXPAND_ONLY_PREDEF to YES.
+# If the MACRO_EXPANSION tag is set to YES doxygen will expand all macro names
+# in the source code. If set to NO only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
MACRO_EXPANSION = YES
-# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
-# then the macro expansion is limited to the macros specified with the
-# PREDEFINED and EXPAND_AS_DEFINED tags.
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_ONLY_PREDEF = YES
-# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
-# pointed to by INCLUDE_PATH will be searched when a #include is found.
+# If the SEARCH_INCLUDES tag is set to YES the includes files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
SEARCH_INCLUDES = YES
# The INCLUDE_PATH tag can be used to specify one or more directories that
-# contain include files that are not input files but should be processed by
-# the preprocessor.
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
INCLUDE_PATH =
# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
# patterns (like *.h and *.hpp) to filter out the header-files in the
-# directories. If left blank, the patterns specified with FILE_PATTERNS will
-# be used.
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
INCLUDE_FILE_PATTERNS =
-# The PREDEFINED tag can be used to specify one or more macro names that
-# are defined before the preprocessor is started (similar to the -D option of
-# gcc). The argument of the tag is a list of macros of the form: name
-# or name=definition (no spaces). If the definition and the = are
-# omitted =1 is assumed. To prevent a macro definition from being
-# undefined via #undef or recursively expanded use the := operator
-# instead of the = operator.
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
PREDEFINED = ORTHANC_PLUGIN_INLINE=
-# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
-# this tag can be used to specify a list of macro names that should be expanded.
-# The macro definition that is found in the sources will be used.
-# Use the PREDEFINED tag if you want to use a different macro definition that
-# overrules the definition found in the source code.
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
EXPAND_AS_DEFINED =
-# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
-# doxygen's preprocessor will remove all references to function-like macros
-# that are alone on a line, have an all uppercase name, and do not end with a
-# semicolon, because these will confuse the parser if not removed.
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
SKIP_FUNCTION_MACROS = YES
#---------------------------------------------------------------------------
-# Configuration::additions related to external references
+# Configuration options related to external references
#---------------------------------------------------------------------------
-# The TAGFILES option can be used to specify one or more tagfiles. For each
-# tag file the location of the external documentation should be added. The
-# format of a tag file without this location is as follows:
-#
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
# TAGFILES = file1 file2 ...
# Adding location for the tag files is done as follows:
-#
# TAGFILES = file1=loc1 "file2 = loc2" ...
-# where "loc1" and "loc2" can be relative or absolute paths
-# or URLs. Note that each tag file must have a unique name (where the name does
-# NOT include the path). If a tag file is not located in the directory in which
-# doxygen is run, you must also specify the path to the tagfile here.
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
TAGFILES =
-# When a file name is specified after GENERATE_TAGFILE, doxygen will create
-# a tag file that is based on the input files it reads.
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
GENERATE_TAGFILE =
-# If the ALLEXTERNALS tag is set to YES all external classes will be listed
-# in the class index. If set to NO only the inherited external classes
-# will be listed.
+# If the ALLEXTERNALS tag is set to YES all external class will be listed in the
+# class index. If set to NO only the inherited external classes will be listed.
+# The default value is: NO.
ALLEXTERNALS = NO
-# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
-# in the modules index. If set to NO, only the current project's groups will
-# be listed.
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed in
+# the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
EXTERNAL_GROUPS = YES
+# If the EXTERNAL_PAGES tag is set to YES all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
# The PERL_PATH should be the absolute path and name of the perl script
-# interpreter (i.e. the result of `which perl').
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
PERL_PATH = /usr/bin/perl
@@ -1573,222 +2021,295 @@ PERL_PATH = /usr/bin/perl
# Configuration options related to the dot tool
#---------------------------------------------------------------------------
-# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
-# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
-# or super classes. Setting the tag to NO turns the diagrams off. Note that
-# this option also works with HAVE_DOT disabled, but it is recommended to
-# install and use dot, since it yields more powerful graphs.
+# If the CLASS_DIAGRAMS tag is set to YES doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
CLASS_DIAGRAMS = YES
# You can define message sequence charts within doxygen comments using the \msc
-# command. Doxygen will then run the mscgen tool (see
-# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
# documentation. The MSCGEN_PATH tag allows you to specify the directory where
# the mscgen tool resides. If left empty the tool is assumed to be found in the
# default search path.
MSCGEN_PATH =
-# If set to YES, the inheritance and collaboration graphs will hide
-# inheritance and usage relations if the target is undocumented
-# or is not a class.
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
HIDE_UNDOC_RELATIONS = YES
# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
-# available from the path. This tool is part of Graphviz, a graph visualization
-# toolkit from AT&T and Lucent Bell Labs. The other options in this section
-# have no effect if this option is set to NO (the default)
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
HAVE_DOT = NO
-# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is
-# allowed to run in parallel. When set to 0 (the default) doxygen will
-# base this on the number of processors available in the system. You can set it
-# explicitly to a value larger than 0 to get control over the balance
-# between CPU load and processing speed.
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_NUM_THREADS = 0
-# By default doxygen will use the Helvetica font for all dot files that
-# doxygen generates. When you want a differently looking font you can specify
-# the font name using DOT_FONTNAME. You need to make sure dot is able to find
-# the font, which can be done by putting it in a standard location or by setting
-# the DOTFONTPATH environment variable or by setting DOT_FONTPATH to the
-# directory containing the font.
+# When you want a differently looking font n the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTNAME = Helvetica
-# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
-# The default size is 10pt.
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTSIZE = 10
-# By default doxygen will tell dot to use the Helvetica font.
-# If you specify a different font using DOT_FONTNAME you can use DOT_FONTPATH to
-# set the path where dot can find it.
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_FONTPATH =
-# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect inheritance relations. Setting this tag to YES will force the
-# CLASS_DIAGRAMS tag to NO.
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
CLASS_GRAPH = YES
-# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for each documented class showing the direct and
-# indirect implementation dependencies (inheritance, containment, and
-# class references variables) of the class with other documented classes.
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
COLLABORATION_GRAPH = YES
-# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
-# will generate a graph for groups, showing the direct groups dependencies
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
GROUP_GRAPHS = YES
# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
# collaboration diagrams in a style similar to the OMG's Unified Modeling
# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
UML_LOOK = NO
-# If the UML_LOOK tag is enabled, the fields and methods are shown inside
-# the class node. If there are many fields or methods and many nodes the
-# graph may become too big to be useful. The UML_LIMIT_NUM_FIELDS
-# threshold limits the number of items for each type to make the size more
-# managable. Set this to 0 for no limit. Note that the threshold may be
-# exceeded by 50% before the limit is enforced.
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
UML_LIMIT_NUM_FIELDS = 10
-# If set to YES, the inheritance and collaboration graphs will show the
-# relations between templates and their instances.
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
TEMPLATE_RELATIONS = NO
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
-# tags are set to YES then doxygen will generate a graph for each documented
-# file showing the direct and indirect include dependencies of the file with
-# other documented files.
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
INCLUDE_GRAPH = YES
-# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
-# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
-# documented header file showing the documented files that directly or
-# indirectly include this file.
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
INCLUDED_BY_GRAPH = YES
-# If the CALL_GRAPH and HAVE_DOT options are set to YES then
-# doxygen will generate a call dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable call graphs
-# for selected functions only using the \callgraph command.
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
CALL_GRAPH = NO
-# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
-# doxygen will generate a caller dependency graph for every global function
-# or class method. Note that enabling this option will significantly increase
-# the time of a run. So in most cases it will be better to enable caller
-# graphs for selected functions only using the \callergraph command.
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
CALLER_GRAPH = NO
-# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
-# will generate a graphical hierarchy of all classes instead of a textual one.
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
GRAPHICAL_HIERARCHY = YES
-# If the DIRECTORY_GRAPH and HAVE_DOT tags are set to YES
-# then doxygen will show the dependencies a directory has on other directories
-# in a graphical way. The dependency relations are determined by the #include
-# relations between the files in the directories.
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
DIRECTORY_GRAPH = YES
# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
-# generated by dot. Possible values are svg, png, jpg, or gif.
-# If left blank png will be used. If you choose svg you need to set
-# HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible in IE 9+ (other browsers do not have this requirement).
+# generated by dot.
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd and svg.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_IMAGE_FORMAT = png
# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
# enable generation of interactive SVG images that allow zooming and panning.
-# Note that this requires a modern browser other than Internet Explorer.
-# Tested and working are Firefox, Chrome, Safari, and Opera. For IE 9+ you
-# need to set HTML_FILE_EXTENSION to xhtml in order to make the SVG files
-# visible. Older versions of IE do not have SVG support.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
INTERACTIVE_SVG = NO
-# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_PATH =
# The DOTFILE_DIRS tag can be used to specify one or more directories that
-# contain dot files that are included in the documentation (see the
-# \dotfile command).
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
DOTFILE_DIRS =
# The MSCFILE_DIRS tag can be used to specify one or more directories that
-# contain msc files that are included in the documentation (see the
-# \mscfile command).
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
MSCFILE_DIRS =
-# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
-# nodes that will be shown in the graph. If the number of nodes in a graph
-# becomes larger than this value, doxygen will truncate the graph, which is
-# visualized by representing a node as a red box. Note that doxygen if the
-# number of direct children of the root node in a graph is already larger than
-# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
-# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_GRAPH_MAX_NODES = 50
-# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
-# graphs generated by dot. A depth value of 3 means that only nodes reachable
-# from the root by following a path via at most 3 edges will be shown. Nodes
-# that lay further from the root node will be omitted. Note that setting this
-# option to 1 or 2 may greatly reduce the computation time needed for large
-# code bases. Also note that the size of a graph can be further restricted by
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
MAX_DOT_GRAPH_DEPTH = 0
# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
-# background. This is disabled by default, because dot on Windows does not
-# seem to support this out of the box. Warning: Depending on the platform used,
-# enabling this option may lead to badly anti-aliased labels on the edges of
-# a graph (i.e. they become hard to read).
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_TRANSPARENT = NO
# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
# files in one run (i.e. multiple -o and -T options on the command line). This
-# makes dot run faster, but since only newer versions of dot (>1.8.10)
-# support this, this feature is disabled by default.
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_MULTI_TARGETS = YES
-# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
-# generate a legend page explaining the meaning of the various boxes and
-# arrows in the dot generated graphs.
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
GENERATE_LEGEND = YES
-# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
-# remove the intermediate dot files that are used to generate
-# the various graphs.
+# If the DOT_CLEANUP tag is set to YES doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
DOT_CLEANUP = YES
diff --git a/Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch b/Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch
new file mode 100644
index 0000000..321f810
--- /dev/null
+++ b/Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch
@@ -0,0 +1,29 @@
+diff -urEb dcmtk-3.6.0.orig/dcmnet/libsrc/dulparse.cc dcmtk-3.6.0/dcmnet/libsrc/dulparse.cc
+--- dcmtk-3.6.0.orig/dcmnet/libsrc/dulparse.cc 2010-12-01 09:26:36.000000000 +0100
++++ dcmtk-3.6.0/dcmnet/libsrc/dulparse.cc 2016-12-02 15:58:49.930540033 +0100
+@@ -393,6 +393,8 @@
+ return cond;
+
+ buf += length;
++ if (presentationLength < length)
++ return EC_MemoryExhausted;
+ presentationLength -= length;
+ DCMNET_TRACE("Successfully parsed Abstract Syntax");
+ break;
+@@ -404,12 +406,16 @@
+ cond = LST_Enqueue(&context->transferSyntaxList, (LST_NODE*)subItem);
+ if (cond.bad()) return cond;
+ buf += length;
++ if (presentationLength < length)
++ return EC_MemoryExhausted;
+ presentationLength -= length;
+ DCMNET_TRACE("Successfully parsed Transfer Syntax");
+ break;
+ default:
+ cond = parseDummy(buf, &length, presentationLength);
+ buf += length;
++ if (presentationLength < length)
++ return EC_MemoryExhausted;
+ presentationLength -= length;
+ break;
+ }
diff --git a/Resources/Patches/dcmtk-3.6.1-private.dic b/Resources/Patches/dcmtk-3.6.1-private.dic
new file mode 100644
index 0000000..880753f
--- /dev/null
+++ b/Resources/Patches/dcmtk-3.6.1-private.dic
@@ -0,0 +1,3040 @@
+#
+# Copyright (C) 1994-2013, OFFIS e.V.
+# All rights reserved. See COPYRIGHT file for details.
+#
+# This software and supporting documentation were developed by
+#
+# OFFIS e.V.
+# R&D Division Health
+# Escherweg 2
+# D-26121 Oldenburg, Germany
+#
+#
+# Module: dcmdata
+#
+# Author: Andrew Hewett, Marco Eichelberg, Joerg Riesmeier
+#
+# Purpose:
+# This is the private tag DICOM data dictionary for the dcmtk class library.
+#
+#
+# Dictionary of Private Tags
+#
+# This dictionary contains the private tags defined in the following
+# reference documents (in alphabetical order):
+# - AGFA IMPAX 6.5.x Solution conformance statement
+# - Circle Cardiovascular Imaging cmr42 3.0 conformance statement
+# - David Clunie's dicom3tools package, 2002-04-20 snapshot
+# - Fuji CR console, 3rd release
+# - Intelerad Medical Systems Inc., Image Server
+# - OCULUS Pentacam 1.17 conformance statement
+# - Philips Digital Diagnost 1.3 conformance statement
+# - Philips Integris H, catheterization laboratory, RIS-interface
+# - Philips Intera Achieva conformance statement
+# - Philips MR Achieva conformance statement
+# - Siemens Somatom syngo VA40B conformance statement
+# - Siemens AXIOM Artis VB30 conformance statement
+# - SonoWand Invite 2.1.1 conformance statement
+# - Swissvision TR4000 conformance statement
+# - private tags for DCMTK anonymizer tool
+#
+# Each line represents an entry in the data dictionary. Each line
+# has 5 fields (Tag, VR, Name, VM, Version). Entries need not be
+# in ascending tag order.
+#
+# Entries may override existing entries.
+#
+# Each field must be separated by a single tab.
+# The tag value may take one of two forms:
+# (gggg,"CREATOR",ee)
+# (gggg,"CREATOR",eeee) [eeee >= 1000]
+# The first form describes a private tag that may be used with different
+# element numbers as reserved by the private creator element.
+# The second form describes a private tag that may only occur with a
+# certain fixed element number.
+# In both cases, the tag values must be in hexadecimal.
+# Repeating groups are represented by indicating the range
+# (gggg-o-gggg,"CREATOR",ee) or (gggg-o-gggg,"CREATOR",eeee)
+# where "-o-" indicates that only odd group numbers match the definition.
+# The element part of the tag can also be a range.
+#
+# Comments have a '#' at the beginning of the line.
+#
+# Tag VR Name VM Version / Description
+#
+(0019,"1.2.840.113681",10) ST CRImageParamsCommon 1 PrivateTag
+(0019,"1.2.840.113681",11) ST CRImageIPParamsSingle 1 PrivateTag
+(0019,"1.2.840.113681",12) ST CRImageIPParamsLeft 1 PrivateTag
+(0019,"1.2.840.113681",13) ST CRImageIPParamsRight 1 PrivateTag
+
+(0087,"1.2.840.113708.794.1.1.2.0",10) CS MediaType 1 PrivateTag
+(0087,"1.2.840.113708.794.1.1.2.0",20) CS MediaLocation 1 PrivateTag
+(0087,"1.2.840.113708.794.1.1.2.0",50) IS EstimatedRetrieveTime 1 PrivateTag
+
+(0009,"ACUSON",00) IS Unknown 1 PrivateTag
+(0009,"ACUSON",01) IS Unknown 1 PrivateTag
+(0009,"ACUSON",02) UN Unknown 1 PrivateTag
+(0009,"ACUSON",03) UN Unknown 1 PrivateTag
+(0009,"ACUSON",04) UN Unknown 1 PrivateTag
+(0009,"ACUSON",05) UN Unknown 1 PrivateTag
+(0009,"ACUSON",06) UN Unknown 1 PrivateTag
+(0009,"ACUSON",07) UN Unknown 1 PrivateTag
+(0009,"ACUSON",08) LT Unknown 1 PrivateTag
+(0009,"ACUSON",09) LT Unknown 1 PrivateTag
+(0009,"ACUSON",0a) IS Unknown 1 PrivateTag
+(0009,"ACUSON",0b) IS Unknown 1 PrivateTag
+(0009,"ACUSON",0c) IS Unknown 1 PrivateTag
+(0009,"ACUSON",0d) IS Unknown 1 PrivateTag
+(0009,"ACUSON",0e) IS Unknown 1 PrivateTag
+(0009,"ACUSON",0f) UN Unknown 1 PrivateTag
+(0009,"ACUSON",10) IS Unknown 1 PrivateTag
+(0009,"ACUSON",11) UN Unknown 1 PrivateTag
+(0009,"ACUSON",12) IS Unknown 1 PrivateTag
+(0009,"ACUSON",13) IS Unknown 1 PrivateTag
+(0009,"ACUSON",14) LT Unknown 1 PrivateTag
+(0009,"ACUSON",15) UN Unknown 1 PrivateTag
+
+(0003,"AEGIS_DICOM_2.00",00) US Unknown 1-n PrivateTag
+(0005,"AEGIS_DICOM_2.00",00) US Unknown 1-n PrivateTag
+(0009,"AEGIS_DICOM_2.00",00) US Unknown 1-n PrivateTag
+(0019,"AEGIS_DICOM_2.00",00) US Unknown 1-n PrivateTag
+(0029,"AEGIS_DICOM_2.00",00) US Unknown 1-n PrivateTag
+(1369,"AEGIS_DICOM_2.00",00) US Unknown 1-n PrivateTag
+
+(0009,"AGFA",10) LO Unknown 1 PrivateTag
+(0009,"AGFA",11) LO Unknown 1 PrivateTag
+(0009,"AGFA",13) LO Unknown 1 PrivateTag
+(0009,"AGFA",14) LO Unknown 1 PrivateTag
+(0009,"AGFA",15) LO Unknown 1 PrivateTag
+
+(0031,"AGFA PACS Archive Mirroring 1.0",00) CS StudyStatus 1 PrivateTag
+(0031,"AGFA PACS Archive Mirroring 1.0",01) UL DateTimeVerified 1 PrivateTag
+
+(0029,"CAMTRONICS IP",10) LT Unknown 1 PrivateTag
+(0029,"CAMTRONICS IP",20) UN Unknown 1 PrivateTag
+(0029,"CAMTRONICS IP",30) UN Unknown 1 PrivateTag
+(0029,"CAMTRONICS IP",40) UN Unknown 1 PrivateTag
+
+(0029,"CAMTRONICS",10) LT Commentline 1 PrivateTag
+(0029,"CAMTRONICS",20) DS EdgeEnhancementCoefficient 1 PrivateTag
+(0029,"CAMTRONICS",50) LT SceneText 1 PrivateTag
+(0029,"CAMTRONICS",60) LT ImageText 1 PrivateTag
+(0029,"CAMTRONICS",70) IS PixelShiftHorizontal 1 PrivateTag
+(0029,"CAMTRONICS",80) IS PixelShiftVertical 1 PrivateTag
+(0029,"CAMTRONICS",90) IS Unknown 1 PrivateTag
+
+(0009,"CARDIO-D.R. 1.0",00) UL FileLocation 1 PrivateTag
+(0009,"CARDIO-D.R. 1.0",01) UL FileSize 1 PrivateTag
+(0009,"CARDIO-D.R. 1.0",40) SQ AlternateImageSequence 1 PrivateTag
+(0019,"CARDIO-D.R. 1.0",00) CS ImageBlankingShape 1 PrivateTag
+(0019,"CARDIO-D.R. 1.0",02) IS ImageBlankingLeftVerticalEdge 1 PrivateTag
+(0019,"CARDIO-D.R. 1.0",04) IS ImageBlankingRightVerticalEdge 1 PrivateTag
+(0019,"CARDIO-D.R. 1.0",06) IS ImageBlankingUpperHorizontalEdge 1 PrivateTag
+(0019,"CARDIO-D.R. 1.0",08) IS ImageBlankingLowerHorizontalEdge 1 PrivateTag
+(0019,"CARDIO-D.R. 1.0",10) IS CenterOfCircularImageBlanking 1 PrivateTag
+(0019,"CARDIO-D.R. 1.0",12) IS RadiusOfCircularImageBlanking 1 PrivateTag
+(0019,"CARDIO-D.R. 1.0",30) UL MaximumImageFrameSize 1 PrivateTag
+(0021,"CARDIO-D.R. 1.0",13) IS ImageSequenceNumber 1 PrivateTag
+(0029,"CARDIO-D.R. 1.0",00) SQ EdgeEnhancementSequence 1 PrivateTag
+(0029,"CARDIO-D.R. 1.0",01) US ConvolutionKernelSize 2 PrivateTag
+(0029,"CARDIO-D.R. 1.0",02) DS ConvolutionKernelCoefficients 1-n PrivateTag
+(0029,"CARDIO-D.R. 1.0",03) DS EdgeEnhancementGain 1 PrivateTag
+
+(0025,"CMR42 CIRCLECVI",1010) LO WorkspaceID 1 PrivateTag
+(0025,"CMR42 CIRCLECVI",1020) LO WorkspaceTimeString 1 PrivateTag
+(0025,"CMR42 CIRCLECVI",1030) OB WorkspaceStream 1 PrivateTag
+
+(0009,"DCMTK_ANONYMIZER",00) SQ AnonymizerUIDMap 1 PrivateTag
+(0009,"DCMTK_ANONYMIZER",10) UI AnonymizerUIDKey 1 PrivateTag
+(0009,"DCMTK_ANONYMIZER",20) UI AnonymizerUIDValue 1 PrivateTag
+(0009,"DCMTK_ANONYMIZER",30) SQ AnonymizerPatientIDMap 1 PrivateTag
+(0009,"DCMTK_ANONYMIZER",40) LO AnonymizerPatientIDKey 1 PrivateTag
+(0009,"DCMTK_ANONYMIZER",50) LO AnonymizerPatientIDValue 1 PrivateTag
+
+(0019,"DIDI TO PCR 1.1",22) UN RouteAET 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",23) DS PCRPrintScale 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",24) UN PCRPrintJobEnd 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",25) IS PCRNoFilmCopies 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",26) IS PCRFilmLayoutPosition 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",27) UN PCRPrintReportName 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",70) UN RADProtocolPrinter 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",71) UN RADProtocolMedium 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",90) LO UnprocessedFlag 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",91) UN KeyValues 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",92) UN DestinationPostprocessingFunction 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A0) UN Version 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A1) UN RangingMode 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A2) UN AbdomenBrightness 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A3) UN FixedBrightness 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A4) UN DetailContrast 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A5) UN ContrastBalance 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A6) UN StructureBoost 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A7) UN StructurePreference 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A8) UN NoiseRobustness 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",A9) UN NoiseDoseLimit 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",AA) UN NoiseDoseStep 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",AB) UN NoiseFrequencyLimit 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",AC) UN WeakContrastLimit 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",AD) UN StrongContrastLimit 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",AE) UN StructureBoostOffset 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",AF) UN SmoothGain 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",B0) UN MeasureField1 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",B1) UN MeasureField2 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",B2) UN KeyPercentile1 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",B3) UN KeyPercentile2 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",B4) UN DensityLUT 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",B5) UN Brightness 1 PrivateTag
+(0019,"DIDI TO PCR 1.1",B6) UN Gamma 1 PrivateTag
+(0089,"DIDI TO PCR 1.1",10) SQ Unknown 1 PrivateTag
+
+(0029,"DIGISCAN IMAGE",31) US Unknown 1-n PrivateTag
+(0029,"DIGISCAN IMAGE",32) US Unknown 1-n PrivateTag
+(0029,"DIGISCAN IMAGE",33) LT Unknown 1 PrivateTag
+(0029,"DIGISCAN IMAGE",34) LT Unknown 1 PrivateTag
+
+(7001-o-70ff,"DLX_ANNOT_01",04) ST TextAnnotation 1 PrivateTag
+(7001-o-70ff,"DLX_ANNOT_01",05) IS Box 2 PrivateTag
+(7001-o-70ff,"DLX_ANNOT_01",07) IS ArrowEnd 2 PrivateTag
+
+(0015,"DLX_EXAMS_01",01) DS StenosisCalibrationRatio 1 PrivateTag
+(0015,"DLX_EXAMS_01",02) DS StenosisMagnification 1 PrivateTag
+(0015,"DLX_EXAMS_01",03) DS CardiacCalibrationRatio 1 PrivateTag
+
+(6001-o-60ff,"DLX_LKUP_01",01) US GrayPaletteColorLookupTableDescriptor 3 PrivateTag
+(6001-o-60ff,"DLX_LKUP_01",02) US GrayPaletteColorLookupTableData 1 PrivateTag
+
+(0011,"DLX_PATNT_01",01) LT PatientDOB 1 PrivateTag
+
+(0019,"DLX_SERIE_01",01) DS AngleValueLArm 1 PrivateTag
+(0019,"DLX_SERIE_01",02) DS AngleValuePArm 1 PrivateTag
+(0019,"DLX_SERIE_01",03) DS AngleValueCArm 1 PrivateTag
+(0019,"DLX_SERIE_01",04) CS AngleLabelLArm 1 PrivateTag
+(0019,"DLX_SERIE_01",05) CS AngleLabelPArm 1 PrivateTag
+(0019,"DLX_SERIE_01",06) CS AngleLabelCArm 1 PrivateTag
+(0019,"DLX_SERIE_01",07) ST ProcedureName 1 PrivateTag
+(0019,"DLX_SERIE_01",08) ST ExamName 1 PrivateTag
+(0019,"DLX_SERIE_01",09) SH PatientSize 1 PrivateTag
+(0019,"DLX_SERIE_01",0a) IS RecordView 1 PrivateTag
+(0019,"DLX_SERIE_01",10) DS InjectorDelay 1 PrivateTag
+(0019,"DLX_SERIE_01",11) CS AutoInject 1 PrivateTag
+(0019,"DLX_SERIE_01",14) IS AcquisitionMode 1 PrivateTag
+(0019,"DLX_SERIE_01",15) CS CameraRotationEnabled 1 PrivateTag
+(0019,"DLX_SERIE_01",16) CS ReverseSweep 1 PrivateTag
+(0019,"DLX_SERIE_01",17) IS SpatialFilterStrength 1 PrivateTag
+(0019,"DLX_SERIE_01",18) IS ZoomFactor 1 PrivateTag
+(0019,"DLX_SERIE_01",19) IS XZoomCenter 1 PrivateTag
+(0019,"DLX_SERIE_01",1a) IS YZoomCenter 1 PrivateTag
+(0019,"DLX_SERIE_01",1b) DS Focus 1 PrivateTag
+(0019,"DLX_SERIE_01",1c) CS Dose 1 PrivateTag
+(0019,"DLX_SERIE_01",1d) IS SideMark 1 PrivateTag
+(0019,"DLX_SERIE_01",1e) IS PercentageLandscape 1 PrivateTag
+(0019,"DLX_SERIE_01",1f) DS ExposureDuration 1 PrivateTag
+
+(00E1,"ELSCINT1",01) US DataDictionaryVersion 1 PrivateTag
+(00E1,"ELSCINT1",14) LT Unknown 1 PrivateTag
+(00E1,"ELSCINT1",22) DS Unknown 2 PrivateTag
+(00E1,"ELSCINT1",23) DS Unknown 2 PrivateTag
+(00E1,"ELSCINT1",24) LT Unknown 1 PrivateTag
+(00E1,"ELSCINT1",25) LT Unknown 1 PrivateTag
+(00E1,"ELSCINT1",40) SH OffsetFromCTMRImages 1 PrivateTag
+(0601,"ELSCINT1",00) SH ImplementationVersion 1 PrivateTag
+(0601,"ELSCINT1",20) DS RelativeTablePosition 1 PrivateTag
+(0601,"ELSCINT1",21) DS RelativeTableHeight 1 PrivateTag
+(0601,"ELSCINT1",30) SH SurviewDirection 1 PrivateTag
+(0601,"ELSCINT1",31) DS SurviewLength 1 PrivateTag
+(0601,"ELSCINT1",50) SH ImageViewType 1 PrivateTag
+(0601,"ELSCINT1",70) DS BatchNumber 1 PrivateTag
+(0601,"ELSCINT1",71) DS BatchSize 1 PrivateTag
+(0601,"ELSCINT1",72) DS BatchSliceNumber 1 PrivateTag
+
+(0009,"FDMS 1.0",04) SH ImageControlUnit 1 PrivateTag
+(0009,"FDMS 1.0",05) OW ImageUID 1 PrivateTag
+(0009,"FDMS 1.0",06) OW RouteImageUID 1 PrivateTag
+(0009,"FDMS 1.0",08) UL ImageDisplayInformationVersionNo 1 PrivateTag
+(0009,"FDMS 1.0",09) UL PatientInformationVersionNo 1 PrivateTag
+(0009,"FDMS 1.0",0C) OW FilmUID 1 PrivateTag
+(0009,"FDMS 1.0",10) CS ExposureUnitTypeCode 1 PrivateTag
+(0009,"FDMS 1.0",80) LO KanjiHospitalName 1 PrivateTag
+(0009,"FDMS 1.0",90) ST DistributionCode 1 PrivateTag
+(0009,"FDMS 1.0",92) SH KanjiDepartmentName 1 PrivateTag
+(0009,"FDMS 1.0",F0) CS BlackeningProcessFlag 1 PrivateTag
+(0019,"FDMS 1.0",15) LO KanjiBodyPartForExposure 1 PrivateTag
+(0019,"FDMS 1.0",32) LO KanjiMenuName 1 PrivateTag
+(0019,"FDMS 1.0",40) CS ImageProcessingType 1 PrivateTag
+(0019,"FDMS 1.0",50) CS EDRMode 1 PrivateTag
+(0019,"FDMS 1.0",60) SH RadiographersCode 1 PrivateTag
+(0019,"FDMS 1.0",70) IS SplitExposureFormat 1 PrivateTag
+(0019,"FDMS 1.0",71) IS NoOfSplitExposureFrames 1 PrivateTag
+(0019,"FDMS 1.0",80) IS ReadingPositionSpecification 1 PrivateTag
+(0019,"FDMS 1.0",81) IS ReadingSensitivityCenter 1 PrivateTag
+(0019,"FDMS 1.0",90) SH FilmAnnotationCharacterString1 1 PrivateTag
+(0019,"FDMS 1.0",91) SH FilmAnnotationCharacterString2 1 PrivateTag
+(0021,"FDMS 1.0",10) CS FCRImageID 1 PrivateTag
+(0021,"FDMS 1.0",30) CS SetNo 1 PrivateTag
+(0021,"FDMS 1.0",40) IS ImageNoInTheSet 1 PrivateTag
+(0021,"FDMS 1.0",50) CS PairProcessingInformation 1 PrivateTag
+(0021,"FDMS 1.0",80) OB EquipmentTypeSpecificInformation 1 PrivateTag
+(0023,"FDMS 1.0",10) SQ Unknown 1 PrivateTag
+(0023,"FDMS 1.0",20) SQ Unknown 1 PrivateTag
+(0023,"FDMS 1.0",30) SQ Unknown 1 PrivateTag
+(0025,"FDMS 1.0",10) US RelativeLightEmissionAmountSk 1 PrivateTag
+(0025,"FDMS 1.0",11) US TermOfCorrectionForEachIPTypeSt 1 PrivateTag
+(0025,"FDMS 1.0",12) US ReadingGainGp 1 PrivateTag
+(0025,"FDMS 1.0",13) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",15) CS Unknown 1 PrivateTag
+(0025,"FDMS 1.0",20) US Unknown 2 PrivateTag
+(0025,"FDMS 1.0",21) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",30) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",31) SS Unknown 1 PrivateTag
+(0025,"FDMS 1.0",32) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",33) SS Unknown 1 PrivateTag
+(0025,"FDMS 1.0",34) SS Unknown 1 PrivateTag
+(0025,"FDMS 1.0",40) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",41) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",42) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",43) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",50) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",51) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",52) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",53) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",60) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",61) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",62) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",63) CS Unknown 1 PrivateTag
+(0025,"FDMS 1.0",70) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",71) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",72) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",73) US Unknown 1-n PrivateTag
+(0025,"FDMS 1.0",74) US Unknown 1-n PrivateTag
+(0025,"FDMS 1.0",80) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",81) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",82) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",83) US Unknown 1-n PrivateTag
+(0025,"FDMS 1.0",84) US Unknown 1-n PrivateTag
+(0025,"FDMS 1.0",90) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",91) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",92) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",93) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",94) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",95) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",96) CS Unknown 1 PrivateTag
+(0025,"FDMS 1.0",a0) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",a1) SS Unknown 1 PrivateTag
+(0025,"FDMS 1.0",a2) US Unknown 1 PrivateTag
+(0025,"FDMS 1.0",a3) SS Unknown 1 PrivateTag
+(0027,"FDMS 1.0",10) SQ Unknown 1 PrivateTag
+(0027,"FDMS 1.0",20) SQ Unknown 1 PrivateTag
+(0027,"FDMS 1.0",30) SQ Unknown 1 PrivateTag
+(0027,"FDMS 1.0",40) SQ Unknown 1 PrivateTag
+(0027,"FDMS 1.0",50) SQ Unknown 1 PrivateTag
+(0027,"FDMS 1.0",60) SQ Unknown 1 PrivateTag
+(0027,"FDMS 1.0",70) SQ Unknown 1 PrivateTag
+(0027,"FDMS 1.0",80) SQ Unknown 1 PrivateTag
+(0027,"FDMS 1.0",a0) IS Unknown 1 PrivateTag
+(0027,"FDMS 1.0",a1) CS Unknown 2 PrivateTag
+(0027,"FDMS 1.0",a2) CS Unknown 2 PrivateTag
+(0027,"FDMS 1.0",a3) SS Unknown 1-n PrivateTag
+(0029,"FDMS 1.0",20) CS ImageScanningDirection 1 PrivateTag
+(0029,"FDMS 1.0",30) CS ExtendedReadingSizeValue 1 PrivateTag
+(0029,"FDMS 1.0",34) US MagnificationReductionRatio 1 PrivateTag
+(0029,"FDMS 1.0",44) CS LineDensityCode 1 PrivateTag
+(0029,"FDMS 1.0",50) CS DataCompressionCode 1 PrivateTag
+(2011,"FDMS 1.0",11) CS ImagePosition SpecifyingFlag 1 PrivateTag
+(50F1,"FDMS 1.0",06) CS EnergySubtractionParam 1 PrivateTag
+(50F1,"FDMS 1.0",07) CS SubtractionRegistrationResult 1 PrivateTag
+(50F1,"FDMS 1.0",08) CS EnergySubtractionParam2 1 PrivateTag
+(50F1,"FDMS 1.0",09) SL AfinConversionCoefficient 1 PrivateTag
+(50F1,"FDMS 1.0",10) CS FilmOutputFormat 1 PrivateTag
+(50F1,"FDMS 1.0",20) CS ImageProcessingModificationFlag 1 PrivateTag
+
+(0009,"FFP DATA",01) UN CRHeaderInformation 1 PrivateTag
+
+(0019,"GE ??? From Adantage Review CS",30) LO CREDRMode 1 PrivateTag
+(0019,"GE ??? From Adantage Review CS",40) LO CRLatitude 1 PrivateTag
+(0019,"GE ??? From Adantage Review CS",50) LO CRGroupNumber 1 PrivateTag
+(0019,"GE ??? From Adantage Review CS",70) LO CRImageSerialNumber 1 PrivateTag
+(0019,"GE ??? From Adantage Review CS",80) LO CRBarCodeNumber 1 PrivateTag
+(0019,"GE ??? From Adantage Review CS",90) LO CRFilmOutputExposures 1 PrivateTag
+
+(0009,"GEMS_ACQU_01",24) DS Unknown 1 PrivateTag
+(0009,"GEMS_ACQU_01",25) US Unknown 1 PrivateTag
+(0009,"GEMS_ACQU_01",3e) US Unknown 1 PrivateTag
+(0009,"GEMS_ACQU_01",3f) US Unknown 1 PrivateTag
+(0009,"GEMS_ACQU_01",42) US Unknown 1 PrivateTag
+(0009,"GEMS_ACQU_01",43) US Unknown 1 PrivateTag
+(0009,"GEMS_ACQU_01",f8) US Unknown 1 PrivateTag
+(0009,"GEMS_ACQU_01",fb) IS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",01) LT Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",02) SL NumberOfCellsInDetector 1 PrivateTag
+(0019,"GEMS_ACQU_01",03) DS CellNumberAtTheta 1 PrivateTag
+(0019,"GEMS_ACQU_01",04) DS CellSpacing 1 PrivateTag
+(0019,"GEMS_ACQU_01",05) LT Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",06) UN Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",0e) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",0f) DS HorizontalFrameOfReference 1 PrivateTag
+(0019,"GEMS_ACQU_01",11) SS SeriesContrast 1 PrivateTag
+(0019,"GEMS_ACQU_01",12) SS LastPseq 1 PrivateTag
+(0019,"GEMS_ACQU_01",13) SS StartNumberForBaseline 1 PrivateTag
+(0019,"GEMS_ACQU_01",14) SS End NumberForBaseline 1 PrivateTag
+(0019,"GEMS_ACQU_01",15) SS StartNumberForEnhancedScans 1 PrivateTag
+(0019,"GEMS_ACQU_01",16) SS EndNumberForEnhancedScans 1 PrivateTag
+(0019,"GEMS_ACQU_01",17) SS SeriesPlane 1 PrivateTag
+(0019,"GEMS_ACQU_01",18) LO FirstScanRAS 1 PrivateTag
+(0019,"GEMS_ACQU_01",19) DS FirstScanLocation 1 PrivateTag
+(0019,"GEMS_ACQU_01",1a) LO LastScanRAS 1 PrivateTag
+(0019,"GEMS_ACQU_01",1b) DS LastScanLocation 1 PrivateTag
+(0019,"GEMS_ACQU_01",1e) DS DisplayFieldOfView 1 PrivateTag
+(0019,"GEMS_ACQU_01",20) DS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",22) DS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",23) DS TableSpeed 1 PrivateTag
+(0019,"GEMS_ACQU_01",24) DS MidScanTime 1 PrivateTag
+(0019,"GEMS_ACQU_01",25) SS MidScanFlag 1 PrivateTag
+(0019,"GEMS_ACQU_01",26) SL DegreesOfAzimuth 1 PrivateTag
+(0019,"GEMS_ACQU_01",27) DS GantryPeriod 1 PrivateTag
+(0019,"GEMS_ACQU_01",2a) DS XrayOnPosition 1 PrivateTag
+(0019,"GEMS_ACQU_01",2b) DS XrayOffPosition 1 PrivateTag
+(0019,"GEMS_ACQU_01",2c) SL NumberOfTriggers 1 PrivateTag
+(0019,"GEMS_ACQU_01",2d) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",2e) DS AngleOfFirstView 1 PrivateTag
+(0019,"GEMS_ACQU_01",2f) DS TriggerFrequency 1 PrivateTag
+(0019,"GEMS_ACQU_01",39) SS ScanFOVType 1 PrivateTag
+(0019,"GEMS_ACQU_01",3a) IS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",3b) LT Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",3c) UN Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",3e) UN Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",3f) UN Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",40) SS StatReconFlag 1 PrivateTag
+(0019,"GEMS_ACQU_01",41) SS ComputeType 1 PrivateTag
+(0019,"GEMS_ACQU_01",42) SS SegmentNumber 1 PrivateTag
+(0019,"GEMS_ACQU_01",43) SS TotalSegmentsRequested 1 PrivateTag
+(0019,"GEMS_ACQU_01",44) DS InterscanDelay 1 PrivateTag
+(0019,"GEMS_ACQU_01",47) SS ViewCompressionFactor 1 PrivateTag
+(0019,"GEMS_ACQU_01",48) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",49) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",4a) SS TotalNumberOfRefChannels 1 PrivateTag
+(0019,"GEMS_ACQU_01",4b) SL DataSizeForScanData 1 PrivateTag
+(0019,"GEMS_ACQU_01",52) SS ReconPostProcessingFlag 1 PrivateTag
+(0019,"GEMS_ACQU_01",54) UN Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",57) SS CTWaterNumber 1 PrivateTag
+(0019,"GEMS_ACQU_01",58) SS CTBoneNumber 1 PrivateTag
+(0019,"GEMS_ACQU_01",5a) FL AcquisitionDuration 1 PrivateTag
+(0019,"GEMS_ACQU_01",5d) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",5e) SL NumberOfChannels1To512 1 PrivateTag
+(0019,"GEMS_ACQU_01",5f) SL IncrementBetweenChannels 1 PrivateTag
+(0019,"GEMS_ACQU_01",60) SL StartingView 1 PrivateTag
+(0019,"GEMS_ACQU_01",61) SL NumberOfViews 1 PrivateTag
+(0019,"GEMS_ACQU_01",62) SL IncrementBetweenViews 1 PrivateTag
+(0019,"GEMS_ACQU_01",6a) SS DependantOnNumberOfViewsProcessed 1 PrivateTag
+(0019,"GEMS_ACQU_01",6b) SS FieldOfViewInDetectorCells 1 PrivateTag
+(0019,"GEMS_ACQU_01",70) SS ValueOfBackProjectionButton 1 PrivateTag
+(0019,"GEMS_ACQU_01",71) SS SetIfFatqEstimatesWereUsed 1 PrivateTag
+(0019,"GEMS_ACQU_01",72) DS ZChannelAvgOverViews 1 PrivateTag
+(0019,"GEMS_ACQU_01",73) DS AvgOfLeftRefChannelsOverViews 1 PrivateTag
+(0019,"GEMS_ACQU_01",74) DS MaxLeftChannelOverViews 1 PrivateTag
+(0019,"GEMS_ACQU_01",75) DS AvgOfRightRefChannelsOverViews 1 PrivateTag
+(0019,"GEMS_ACQU_01",76) DS MaxRightChannelOverViews 1 PrivateTag
+(0019,"GEMS_ACQU_01",7d) DS SecondEcho 1 PrivateTag
+(0019,"GEMS_ACQU_01",7e) SS NumberOfEchos 1 PrivateTag
+(0019,"GEMS_ACQU_01",7f) DS TableDelta 1 PrivateTag
+(0019,"GEMS_ACQU_01",81) SS Contiguous 1 PrivateTag
+(0019,"GEMS_ACQU_01",82) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",83) DS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",84) DS PeakSAR 1 PrivateTag
+(0019,"GEMS_ACQU_01",85) SS MonitorSAR 1 PrivateTag
+(0019,"GEMS_ACQU_01",86) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",87) DS CardiacRepetition Time 1 PrivateTag
+(0019,"GEMS_ACQU_01",88) SS ImagesPerCardiacCycle 1 PrivateTag
+(0019,"GEMS_ACQU_01",8a) SS ActualReceiveGainAnalog 1 PrivateTag
+(0019,"GEMS_ACQU_01",8b) SS ActualReceiveGainDigital 1 PrivateTag
+(0019,"GEMS_ACQU_01",8d) DS DelayAfterTrigger 1 PrivateTag
+(0019,"GEMS_ACQU_01",8f) SS SwapPhaseFrequency 1 PrivateTag
+(0019,"GEMS_ACQU_01",90) SS PauseInterval 1 PrivateTag
+(0019,"GEMS_ACQU_01",91) DS PulseTime 1 PrivateTag
+(0019,"GEMS_ACQU_01",92) SL SliceOffsetOnFrequencyAxis 1 PrivateTag
+(0019,"GEMS_ACQU_01",93) DS CenterFrequency 1 PrivateTag
+(0019,"GEMS_ACQU_01",94) SS TransmitGain 1 PrivateTag
+(0019,"GEMS_ACQU_01",95) SS AnalogReceiverGain 1 PrivateTag
+(0019,"GEMS_ACQU_01",96) SS DigitalReceiverGain 1 PrivateTag
+(0019,"GEMS_ACQU_01",97) SL BitmapDefiningCVs 1 PrivateTag
+(0019,"GEMS_ACQU_01",98) SS CenterFrequencyMethod 1 PrivateTag
+(0019,"GEMS_ACQU_01",99) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",9b) SS PulseSequenceMode 1 PrivateTag
+(0019,"GEMS_ACQU_01",9c) LO PulseSequenceName 1 PrivateTag
+(0019,"GEMS_ACQU_01",9d) DT PulseSequenceDate 1 PrivateTag
+(0019,"GEMS_ACQU_01",9e) LO InternalPulseSequenceName 1 PrivateTag
+(0019,"GEMS_ACQU_01",9f) SS TransmittingCoil 1 PrivateTag
+(0019,"GEMS_ACQU_01",a0) SS SurfaceCoilType 1 PrivateTag
+(0019,"GEMS_ACQU_01",a1) SS ExtremityCoilFlag 1 PrivateTag
+(0019,"GEMS_ACQU_01",a2) SL RawDataRunNumber 1 PrivateTag
+(0019,"GEMS_ACQU_01",a3) UL CalibratedFieldStrength 1 PrivateTag
+(0019,"GEMS_ACQU_01",a4) SS SATFatWaterBone 1 PrivateTag
+(0019,"GEMS_ACQU_01",a5) DS ReceiveBandwidth 1 PrivateTag
+(0019,"GEMS_ACQU_01",a7) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",a8) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",a9) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",aa) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",ab) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",ac) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",ad) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",ae) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",af) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b0) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b1) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b2) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b3) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b4) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b5) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b6) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b7) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b8) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",b9) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",ba) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",bb) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",bc) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",bd) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",be) DS ProjectionAngle 1 PrivateTag
+(0019,"GEMS_ACQU_01",c0) SS SaturationPlanes 1 PrivateTag
+(0019,"GEMS_ACQU_01",c1) SS SurfaceCoilIntensityCorrectionFlag 1 PrivateTag
+(0019,"GEMS_ACQU_01",c2) SS SATLocationR 1 PrivateTag
+(0019,"GEMS_ACQU_01",c3) SS SATLocationL 1 PrivateTag
+(0019,"GEMS_ACQU_01",c4) SS SATLocationA 1 PrivateTag
+(0019,"GEMS_ACQU_01",c5) SS SATLocationP 1 PrivateTag
+(0019,"GEMS_ACQU_01",c6) SS SATLocationH 1 PrivateTag
+(0019,"GEMS_ACQU_01",c7) SS SATLocationF 1 PrivateTag
+(0019,"GEMS_ACQU_01",c8) SS SATThicknessRL 1 PrivateTag
+(0019,"GEMS_ACQU_01",c9) SS SATThicknessAP 1 PrivateTag
+(0019,"GEMS_ACQU_01",ca) SS SATThicknessHF 1 PrivateTag
+(0019,"GEMS_ACQU_01",cb) SS PrescribedFlowAxis 1 PrivateTag
+(0019,"GEMS_ACQU_01",cc) SS VelocityEncoding 1 PrivateTag
+(0019,"GEMS_ACQU_01",cd) SS ThicknessDisclaimer 1 PrivateTag
+(0019,"GEMS_ACQU_01",ce) SS PrescanType 1 PrivateTag
+(0019,"GEMS_ACQU_01",cf) SS PrescanStatus 1 PrivateTag
+(0019,"GEMS_ACQU_01",d0) SH RawDataType 1 PrivateTag
+(0019,"GEMS_ACQU_01",d2) SS ProjectionAlgorithm 1 PrivateTag
+(0019,"GEMS_ACQU_01",d3) SH ProjectionAlgorithm 1 PrivateTag
+(0019,"GEMS_ACQU_01",d4) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",d5) SS FractionalEcho 1 PrivateTag
+(0019,"GEMS_ACQU_01",d6) SS PrepPulse 1 PrivateTag
+(0019,"GEMS_ACQU_01",d7) SS CardiacPhases 1 PrivateTag
+(0019,"GEMS_ACQU_01",d8) SS VariableEchoFlag 1 PrivateTag
+(0019,"GEMS_ACQU_01",d9) DS ConcatenatedSAT 1 PrivateTag
+(0019,"GEMS_ACQU_01",da) SS ReferenceChannelUsed 1 PrivateTag
+(0019,"GEMS_ACQU_01",db) DS BackProjectorCoefficient 1 PrivateTag
+(0019,"GEMS_ACQU_01",dc) SS PrimarySpeedCorrectionUsed 1 PrivateTag
+(0019,"GEMS_ACQU_01",dd) SS OverrangeCorrectionUsed 1 PrivateTag
+(0019,"GEMS_ACQU_01",de) DS DynamicZAlphaValue 1 PrivateTag
+(0019,"GEMS_ACQU_01",df) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",e0) DS UserData 1 PrivateTag
+(0019,"GEMS_ACQU_01",e1) DS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",e2) DS VelocityEncodeScale 1 PrivateTag
+(0019,"GEMS_ACQU_01",e3) LT Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",e4) LT Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",e5) IS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",e6) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",e8) DS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",e9) DS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",eb) DS Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",ec) US Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",f0) UN Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",f1) LT Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",f2) SS FastPhases 1 PrivateTag
+(0019,"GEMS_ACQU_01",f3) LT Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",f4) LT Unknown 1 PrivateTag
+(0019,"GEMS_ACQU_01",f9) DS TransmitGain 1 PrivateTag
+
+(0023,"GEMS_ACRQA_1.0 BLOCK1",00) LO CRExposureMenuCode 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",10) LO CRExposureMenuString 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",20) LO CREDRMode 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",30) LO CRLatitude 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",40) LO CRGroupNumber 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",50) US CRImageSerialNumber 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",60) LO CRBarCodeNumber 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",70) LO CRFilmOutputExposure 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",80) LO CRFilmFormat 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK1",90) LO CRSShiftString 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",00) US CRSShift 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",10) DS CRCShift 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",20) DS CRGT 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",30) DS CRGA 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",40) DS CRGC 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",50) DS CRGS 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",60) DS CRRT 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",70) DS CRRE 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",80) US CRRN 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK2",90) DS CRDRT 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",00) DS CRDRE 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",10) US CRDRN 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",20) DS CRORE 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",30) US CRORN 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",40) US CRORD 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",50) LO CRCassetteSize 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",60) LO CRMachineID 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",70) LO CRMachineType 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",80) LO CRTechnicianCode 1 PrivateTag
+(0023,"GEMS_ACRQA_1.0 BLOCK3",90) LO CREnergySubtractionParameters 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",00) LO CRExposureMenuCode 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",10) LO CRExposureMenuString 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",20) LO CREDRMode 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",30) LO CRLatitude 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",40) LO CRGroupNumber 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",50) US CRImageSerialNumber 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",60) LO CRBarCodeNumber 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",70) LO CRFilmOutputExposure 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",80) LO CRFilmFormat 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK1",90) LO CRSShiftString 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",00) US CRSShift 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",10) LO CRCShift 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",20) LO CRGT 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",30) DS CRGA 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",40) DS CRGC 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",50) DS CRGS 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",60) LO CRRT 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",70) DS CRRE 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",80) US CRRN 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK2",90) DS CRDRT 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",00) DS CRDRE 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",10) US CRDRN 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",20) DS CRORE 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",30) US CRORN 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",40) US CRORD 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",50) LO CRCassetteSize 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",60) LO CRMachineID 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",70) LO CRMachineType 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",80) LO CRTechnicianCode 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",90) LO CREnergySubtractionParameters 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",f0) LO CRDistributionCode 1 PrivateTag
+(0023,"GEMS_ACRQA_2.0 BLOCK3",ff) US CRShuttersApplied 1 PrivateTag
+
+(0047,"GEMS_ADWSoft_3D1",01) SQ Reconstruction Parameters Sequence 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",50) UL VolumeVoxelCount 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",51) UL VolumeSegmentCount 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",53) US VolumeSliceSize 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",54) US VolumeSliceCount 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",55) SL VolumeThresholdValue 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",57) DS VolumeVoxelRatio 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",58) DS VolumeVoxelSize 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",59) US VolumeZPositionSize 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",60) DS VolumeBaseLine 9 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",61) DS VolumeCenterPoint 3 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",63) SL VolumeSkewBase 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",64) DS VolumeRegistrationTransformRotationMatrix 9 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",65) DS VolumeRegistrationTransformTranslationVector 3 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",70) DS KVPList 1-n PrivateTag
+(0047,"GEMS_ADWSoft_3D1",71) IS XRayTubeCurrentList 1-n PrivateTag
+(0047,"GEMS_ADWSoft_3D1",72) IS ExposureList 1-n PrivateTag
+(0047,"GEMS_ADWSoft_3D1",80) LO AcquisitionDLXIdentifier 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",85) SQ AcquisitionDLX2DSeriesSequence 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",89) DS ContrastAgentVolumeList 1-n PrivateTag
+(0047,"GEMS_ADWSoft_3D1",8A) US NumberOfInjections 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",8B) US FrameCount 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",91) LO XA3DReconstructionAlgorithmName 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",92) CS XA3DReconstructionAlgorithmVersion 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",93) DA DLXCalibrationDate 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",94) TM DLXCalibrationTime 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",95) CS DLXCalibrationStatus 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",96) IS UsedFrames 1-n PrivateTag
+(0047,"GEMS_ADWSoft_3D1",98) US TransformCount 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",99) SQ TransformSequence 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",9A) DS TransformRotationMatrix 9 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",9B) DS TransformTranslationVector 3 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",9C) LO TransformLabel 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B0) SQ WireframeList 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B1) US WireframeCount 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B2) US LocationSystem 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B5) LO WireframeName 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B6) LO WireframeGroupName 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B7) LO WireframeColor 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B8) SL WireframeAttributes 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",B9) SL WireframePointCount 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",BA) SL WireframeTimestamp 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",BB) SQ WireframePointList 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",BC) DS WireframePointsCoordinates 3 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",C0) DS VolumeUpperLeftHighCornerRAS 3 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",C1) DS VolumeSliceToRASRotationMatrix 9 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",C2) DS VolumeUpperLeftHighCornerTLOC 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D1) OB VolumeSegmentList 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D2) OB VolumeGradientList 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D3) OB VolumeDensityList 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D4) OB VolumeZPositionList 1 PrivateTag
+(0047,"GEMS_ADWSoft_3D1",D5) OB VolumeOriginalIndexList 1 PrivateTag
+(0039,"GEMS_ADWSoft_DPO",80) IS PrivateEntityNumber 1 PrivateTag
+(0039,"GEMS_ADWSoft_DPO",85) DA PrivateEntityDate 1 PrivateTag
+(0039,"GEMS_ADWSoft_DPO",90) TM PrivateEntityTime 1 PrivateTag
+(0039,"GEMS_ADWSoft_DPO",95) LO PrivateEntityLaunchCommand 1 PrivateTag
+(0039,"GEMS_ADWSoft_DPO",AA) CS PrivateEntityType 1 PrivateTag
+
+(0033,"GEMS_CTHD_01",02) UN Unknown 1 PrivateTag
+
+(0037,"GEMS_DRS_1",10) LO ReferringDepartment 1 PrivateTag
+(0037,"GEMS_DRS_1",20) US ScreenNumber 1 PrivateTag
+(0037,"GEMS_DRS_1",40) SH LeftOrientation 1 PrivateTag
+(0037,"GEMS_DRS_1",42) SH RightOrientation 1 PrivateTag
+(0037,"GEMS_DRS_1",50) CS Inversion 1 PrivateTag
+(0037,"GEMS_DRS_1",60) US DSA 1 PrivateTag
+
+(0009,"GEMS_GENIE_1",10) LO Unknown 1 PrivateTag
+(0009,"GEMS_GENIE_1",11) SL StudyFlags 1 PrivateTag
+(0009,"GEMS_GENIE_1",12) SL StudyType 1 PrivateTag
+(0009,"GEMS_GENIE_1",1e) UI Unknown 1 PrivateTag
+(0009,"GEMS_GENIE_1",20) LO Unknown 1 PrivateTag
+(0009,"GEMS_GENIE_1",21) SL SeriesFlags 1 PrivateTag
+(0009,"GEMS_GENIE_1",22) SH UserOrientation 1 PrivateTag
+(0009,"GEMS_GENIE_1",23) SL InitiationType 1 PrivateTag
+(0009,"GEMS_GENIE_1",24) SL InitiationDelay 1 PrivateTag
+(0009,"GEMS_GENIE_1",25) SL InitiationCountRate 1 PrivateTag
+(0009,"GEMS_GENIE_1",26) SL NumberEnergySets 1 PrivateTag
+(0009,"GEMS_GENIE_1",27) SL NumberDetectors 1 PrivateTag
+(0009,"GEMS_GENIE_1",29) SL Unknown 1 PrivateTag
+(0009,"GEMS_GENIE_1",2a) SL Unknown 1 PrivateTag
+(0009,"GEMS_GENIE_1",2c) LO SeriesComments 1 PrivateTag
+(0009,"GEMS_GENIE_1",2d) SL TrackBeatAverage 1 PrivateTag
+(0009,"GEMS_GENIE_1",2e) FD DistancePrescribed 1 PrivateTag
+(0009,"GEMS_GENIE_1",30) LO Unknown 1 PrivateTag
+(0009,"GEMS_GENIE_1",35) SL GantryLocusType 1 PrivateTag
+(0009,"GEMS_GENIE_1",37) SL StartingHeartRate 1 PrivateTag
+(0009,"GEMS_GENIE_1",38) SL RRWindowWidth 1 PrivateTag
+(0009,"GEMS_GENIE_1",39) SL RRWindowOffset 1 PrivateTag
+(0009,"GEMS_GENIE_1",3a) SL PercentCycleImaged 1 PrivateTag
+(0009,"GEMS_GENIE_1",40) LO Unknown 1 PrivateTag
+(0009,"GEMS_GENIE_1",41) SL PatientFlags 1 PrivateTag
+(0009,"GEMS_GENIE_1",42) DA PatientCreationDate 1 PrivateTag
+(0009,"GEMS_GENIE_1",43) TM PatientCreationTime 1 PrivateTag
+(0011,"GEMS_GENIE_1",0a) SL SeriesType 1 PrivateTag
+(0011,"GEMS_GENIE_1",0b) SL EffectiveSeriesDuration 1 PrivateTag
+(0011,"GEMS_GENIE_1",0c) SL NumBeats 1 PrivateTag
+(0011,"GEMS_GENIE_1",0d) LO RadioNuclideName 1 PrivateTag
+(0011,"GEMS_GENIE_1",10) LO Unknown 1 PrivateTag
+(0011,"GEMS_GENIE_1",12) LO DatasetName 1 PrivateTag
+(0011,"GEMS_GENIE_1",13) SL DatasetType 1 PrivateTag
+(0011,"GEMS_GENIE_1",15) SL DetectorNumber 1 PrivateTag
+(0011,"GEMS_GENIE_1",16) SL EnergyNumber 1 PrivateTag
+(0011,"GEMS_GENIE_1",17) SL RRIntervalWindowNumber 1 PrivateTag
+(0011,"GEMS_GENIE_1",18) SL MGBinNumber 1 PrivateTag
+(0011,"GEMS_GENIE_1",19) FD RadiusOfRotation 1 PrivateTag
+(0011,"GEMS_GENIE_1",1a) SL DetectorCountZone 1 PrivateTag
+(0011,"GEMS_GENIE_1",1b) SL NumEnergyWindows 1 PrivateTag
+(0011,"GEMS_GENIE_1",1c) SL EnergyOffset 4 PrivateTag
+(0011,"GEMS_GENIE_1",1d) SL EnergyRange 1 PrivateTag
+(0011,"GEMS_GENIE_1",1f) SL ImageOrientation 1 PrivateTag
+(0011,"GEMS_GENIE_1",23) SL UseFOVMask 1 PrivateTag
+(0011,"GEMS_GENIE_1",24) SL FOVMaskYCutoffAngle 1 PrivateTag
+(0011,"GEMS_GENIE_1",25) SL FOVMaskCutoffAngle 1 PrivateTag
+(0011,"GEMS_GENIE_1",26) SL TableOrientation 1 PrivateTag
+(0011,"GEMS_GENIE_1",27) SL ROITopLeft 2 PrivateTag
+(0011,"GEMS_GENIE_1",28) SL ROIBottomRight 2 PrivateTag
+(0011,"GEMS_GENIE_1",30) LO Unknown 1 PrivateTag
+(0011,"GEMS_GENIE_1",33) LO EnergyCorrectName 1 PrivateTag
+(0011,"GEMS_GENIE_1",34) LO SpatialCorrectName 1 PrivateTag
+(0011,"GEMS_GENIE_1",35) LO TuningCalibName 1 PrivateTag
+(0011,"GEMS_GENIE_1",36) LO UniformityCorrectName 1 PrivateTag
+(0011,"GEMS_GENIE_1",37) LO AcquisitionSpecificCorrectName 1 PrivateTag
+(0011,"GEMS_GENIE_1",38) SL ByteOrder 1 PrivateTag
+(0011,"GEMS_GENIE_1",3a) SL PictureFormat 1 PrivateTag
+(0011,"GEMS_GENIE_1",3b) FD PixelScale 1 PrivateTag
+(0011,"GEMS_GENIE_1",3c) FD PixelOffset 1 PrivateTag
+(0011,"GEMS_GENIE_1",3e) SL FOVShape 1 PrivateTag
+(0011,"GEMS_GENIE_1",3f) SL DatasetFlags 1 PrivateTag
+(0011,"GEMS_GENIE_1",44) FD ThresholdCenter 1 PrivateTag
+(0011,"GEMS_GENIE_1",45) FD ThresholdWidth 1 PrivateTag
+(0011,"GEMS_GENIE_1",46) SL InterpolationType 1 PrivateTag
+(0011,"GEMS_GENIE_1",55) FD Period 1 PrivateTag
+(0011,"GEMS_GENIE_1",56) FD ElapsedTime 1 PrivateTag
+(0013,"GEMS_GENIE_1",10) FD DigitalFOV 2 PrivateTag
+(0013,"GEMS_GENIE_1",11) SL Unknown 1 PrivateTag
+(0013,"GEMS_GENIE_1",12) SL Unknown 1 PrivateTag
+(0013,"GEMS_GENIE_1",16) SL AutoTrackPeak 1 PrivateTag
+(0013,"GEMS_GENIE_1",17) SL AutoTrackWidth 1 PrivateTag
+(0013,"GEMS_GENIE_1",18) FD TransmissionScanTime 1 PrivateTag
+(0013,"GEMS_GENIE_1",19) FD TransmissionMaskWidth 1 PrivateTag
+(0013,"GEMS_GENIE_1",1a) FD CopperAttenuatorThickness 1 PrivateTag
+(0013,"GEMS_GENIE_1",1c) FD Unknown 1 PrivateTag
+(0013,"GEMS_GENIE_1",1d) FD Unknown 1 PrivateTag
+(0013,"GEMS_GENIE_1",1e) FD TomoViewOffset 1-n PrivateTag
+(0013,"GEMS_GENIE_1",26) LT StudyComments 1 PrivateTag
+
+(0033,"GEMS_GNHD_01",01) UN Unknown 1 PrivateTag
+(0033,"GEMS_GNHD_01",02) UN Unknown 1 PrivateTag
+
+(0009,"GEMS_IDEN_01",01) LO FullFidelity 1 PrivateTag
+(0009,"GEMS_IDEN_01",02) SH SuiteId 1 PrivateTag
+(0009,"GEMS_IDEN_01",04) SH ProductId 1 PrivateTag
+(0009,"GEMS_IDEN_01",17) LT Unknown 1 PrivateTag
+(0009,"GEMS_IDEN_01",1a) US Unknown 1 PrivateTag
+(0009,"GEMS_IDEN_01",20) US Unknown 1 PrivateTag
+(0009,"GEMS_IDEN_01",27) SL ImageActualDate 1 PrivateTag
+(0009,"GEMS_IDEN_01",2f) LT Unknown 1 PrivateTag
+(0009,"GEMS_IDEN_01",30) SH ServiceId 1 PrivateTag
+(0009,"GEMS_IDEN_01",31) SH MobileLocationNumber 1 PrivateTag
+(0009,"GEMS_IDEN_01",e2) LT Unknown 1 PrivateTag
+(0009,"GEMS_IDEN_01",e3) UI EquipmentUID 1 PrivateTag
+(0009,"GEMS_IDEN_01",e6) SH GenesisVersionNow 1 PrivateTag
+(0009,"GEMS_IDEN_01",e7) UL ExamRecordChecksum 1 PrivateTag
+(0009,"GEMS_IDEN_01",e8) UL Unknown 1 PrivateTag
+(0009,"GEMS_IDEN_01",e9) SL ActualSeriesDataTimeStamp 1 PrivateTag
+
+(0027,"GEMS_IMAG_01",06) SL ImageArchiveFlag 1 PrivateTag
+(0027,"GEMS_IMAG_01",10) SS ScoutType 1 PrivateTag
+(0027,"GEMS_IMAG_01",1c) SL VmaMamp 1 PrivateTag
+(0027,"GEMS_IMAG_01",1d) SS VmaPhase 1 PrivateTag
+(0027,"GEMS_IMAG_01",1e) SL VmaMod 1 PrivateTag
+(0027,"GEMS_IMAG_01",1f) SL VmaClip 1 PrivateTag
+(0027,"GEMS_IMAG_01",20) SS SmartScanOnOffFlag 1 PrivateTag
+(0027,"GEMS_IMAG_01",30) SH ForeignImageRevision 1 PrivateTag
+(0027,"GEMS_IMAG_01",31) SS ImagingMode 1 PrivateTag
+(0027,"GEMS_IMAG_01",32) SS PulseSequence 1 PrivateTag
+(0027,"GEMS_IMAG_01",33) SL ImagingOptions 1 PrivateTag
+(0027,"GEMS_IMAG_01",35) SS PlaneType 1 PrivateTag
+(0027,"GEMS_IMAG_01",36) SL ObliquePlane 1 PrivateTag
+(0027,"GEMS_IMAG_01",40) SH RASLetterOfImageLocation 1 PrivateTag
+(0027,"GEMS_IMAG_01",41) FL ImageLocation 1 PrivateTag
+(0027,"GEMS_IMAG_01",42) FL CenterRCoordOfPlaneImage 1 PrivateTag
+(0027,"GEMS_IMAG_01",43) FL CenterACoordOfPlaneImage 1 PrivateTag
+(0027,"GEMS_IMAG_01",44) FL CenterSCoordOfPlaneImage 1 PrivateTag
+(0027,"GEMS_IMAG_01",45) FL NormalRCoord 1 PrivateTag
+(0027,"GEMS_IMAG_01",46) FL NormalACoord 1 PrivateTag
+(0027,"GEMS_IMAG_01",47) FL NormalSCoord 1 PrivateTag
+(0027,"GEMS_IMAG_01",48) FL RCoordOfTopRightCorner 1 PrivateTag
+(0027,"GEMS_IMAG_01",49) FL ACoordOfTopRightCorner 1 PrivateTag
+(0027,"GEMS_IMAG_01",4a) FL SCoordOfTopRightCorner 1 PrivateTag
+(0027,"GEMS_IMAG_01",4b) FL RCoordOfBottomRightCorner 1 PrivateTag
+(0027,"GEMS_IMAG_01",4c) FL ACoordOfBottomRightCorner 1 PrivateTag
+(0027,"GEMS_IMAG_01",4d) FL SCoordOfBottomRightCorner 1 PrivateTag
+(0027,"GEMS_IMAG_01",50) FL TableStartLocation 1 PrivateTag
+(0027,"GEMS_IMAG_01",51) FL TableEndLocation 1 PrivateTag
+(0027,"GEMS_IMAG_01",52) SH RASLetterForSideOfImage 1 PrivateTag
+(0027,"GEMS_IMAG_01",53) SH RASLetterForAnteriorPosterior 1 PrivateTag
+(0027,"GEMS_IMAG_01",54) SH RASLetterForScoutStartLoc 1 PrivateTag
+(0027,"GEMS_IMAG_01",55) SH RASLetterForScoutEndLoc 1 PrivateTag
+(0027,"GEMS_IMAG_01",60) FL ImageDimensionX 1 PrivateTag
+(0027,"GEMS_IMAG_01",61) FL ImageDimensionY 1 PrivateTag
+(0027,"GEMS_IMAG_01",62) FL NumberOfExcitations 1 PrivateTag
+
+(0029,"GEMS_IMPS_01",04) SL LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",05) DS LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",06) DS LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",07) SL LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",08) SH LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",09) SH LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",0a) SS LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",15) SL LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",16) SL LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",17) SL LowerRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",18) SL UpperRangeOfPixels 1 PrivateTag
+(0029,"GEMS_IMPS_01",1a) SL LengthOfTotalHeaderInBytes 1 PrivateTag
+(0029,"GEMS_IMPS_01",26) SS VersionOfHeaderStructure 1 PrivateTag
+(0029,"GEMS_IMPS_01",34) SL AdvantageCompOverflow 1 PrivateTag
+(0029,"GEMS_IMPS_01",35) SL AdvantageCompUnderflow 1 PrivateTag
+
+(0043,"GEMS_PARM_01",01) SS BitmapOfPrescanOptions 1 PrivateTag
+(0043,"GEMS_PARM_01",02) SS GradientOffsetInX 1 PrivateTag
+(0043,"GEMS_PARM_01",03) SS GradientOffsetInY 1 PrivateTag
+(0043,"GEMS_PARM_01",04) SS GradientOffsetInZ 1 PrivateTag
+(0043,"GEMS_PARM_01",05) SS ImageIsOriginalOrUnoriginal 1 PrivateTag
+(0043,"GEMS_PARM_01",06) SS NumberOfEPIShots 1 PrivateTag
+(0043,"GEMS_PARM_01",07) SS ViewsPerSegment 1 PrivateTag
+(0043,"GEMS_PARM_01",08) SS RespiratoryRateInBPM 1 PrivateTag
+(0043,"GEMS_PARM_01",09) SS RespiratoryTriggerPoint 1 PrivateTag
+(0043,"GEMS_PARM_01",0a) SS TypeOfReceiverUsed 1 PrivateTag
+(0043,"GEMS_PARM_01",0b) DS PeakRateOfChangeOfGradientField 1 PrivateTag
+(0043,"GEMS_PARM_01",0c) DS LimitsInUnitsOfPercent 1 PrivateTag
+(0043,"GEMS_PARM_01",0d) DS PSDEstimatedLimit 1 PrivateTag
+(0043,"GEMS_PARM_01",0e) DS PSDEstimatedLimitInTeslaPerSecond 1 PrivateTag
+(0043,"GEMS_PARM_01",0f) DS SARAvgHead 1 PrivateTag
+(0043,"GEMS_PARM_01",10) US WindowValue 1 PrivateTag
+(0043,"GEMS_PARM_01",11) US TotalInputViews 1 PrivateTag
+(0043,"GEMS_PARM_01",12) SS XrayChain 3 PrivateTag
+(0043,"GEMS_PARM_01",13) SS ReconKernelParameters 5 PrivateTag
+(0043,"GEMS_PARM_01",14) SS CalibrationParameters 3 PrivateTag
+(0043,"GEMS_PARM_01",15) SS TotalOutputViews 3 PrivateTag
+(0043,"GEMS_PARM_01",16) SS NumberOfOverranges 5 PrivateTag
+(0043,"GEMS_PARM_01",17) DS IBHImageScaleFactors 1 PrivateTag
+(0043,"GEMS_PARM_01",18) DS BBHCoefficients 3 PrivateTag
+(0043,"GEMS_PARM_01",19) SS NumberOfBBHChainsToBlend 1 PrivateTag
+(0043,"GEMS_PARM_01",1a) SL StartingChannelNumber 1 PrivateTag
+(0043,"GEMS_PARM_01",1b) SS PPScanParameters 1 PrivateTag
+(0043,"GEMS_PARM_01",1c) SS GEImageIntegrity 1 PrivateTag
+(0043,"GEMS_PARM_01",1d) SS LevelValue 1 PrivateTag
+(0043,"GEMS_PARM_01",1e) DS DeltaStartTime 1 PrivateTag
+(0043,"GEMS_PARM_01",1f) SL MaxOverrangesInAView 1 PrivateTag
+(0043,"GEMS_PARM_01",20) DS AvgOverrangesAllViews 1 PrivateTag
+(0043,"GEMS_PARM_01",21) SS CorrectedAfterglowTerms 1 PrivateTag
+(0043,"GEMS_PARM_01",25) SS ReferenceChannels 6 PrivateTag
+(0043,"GEMS_PARM_01",26) US NoViewsRefChannelsBlocked 6 PrivateTag
+(0043,"GEMS_PARM_01",27) SH ScanPitchRatio 1 PrivateTag
+(0043,"GEMS_PARM_01",28) OB UniqueImageIdentifier 1 PrivateTag
+(0043,"GEMS_PARM_01",29) OB HistogramTables 1 PrivateTag
+(0043,"GEMS_PARM_01",2a) OB UserDefinedData 1 PrivateTag
+(0043,"GEMS_PARM_01",2b) SS PrivateScanOptions 4 PrivateTag
+(0043,"GEMS_PARM_01",2c) SS EffectiveEchoSpacing 1 PrivateTag
+(0043,"GEMS_PARM_01",2d) SH StringSlopField1 1 PrivateTag
+(0043,"GEMS_PARM_01",2e) SH StringSlopField2 1 PrivateTag
+(0043,"GEMS_PARM_01",2f) SS RawDataType 1 PrivateTag
+(0043,"GEMS_PARM_01",30) SS RawDataType 1 PrivateTag
+(0043,"GEMS_PARM_01",31) DS RACoordOfTargetReconCentre 2 PrivateTag
+(0043,"GEMS_PARM_01",32) SS RawDataType 1 PrivateTag
+(0043,"GEMS_PARM_01",33) FL NegScanSpacing 1 PrivateTag
+(0043,"GEMS_PARM_01",34) IS OffsetFrequency 1 PrivateTag
+(0043,"GEMS_PARM_01",35) UL UserUsageTag 1 PrivateTag
+(0043,"GEMS_PARM_01",36) UL UserFillMapMSW 1 PrivateTag
+(0043,"GEMS_PARM_01",37) UL UserFillMapLSW 1 PrivateTag
+(0043,"GEMS_PARM_01",38) FL User25ToUser48 24 PrivateTag
+(0043,"GEMS_PARM_01",39) IS SlopInteger6ToSlopInteger9 4 PrivateTag
+(0043,"GEMS_PARM_01",40) FL TriggerOnPosition 4 PrivateTag
+(0043,"GEMS_PARM_01",41) FL DegreeOfRotation 4 PrivateTag
+(0043,"GEMS_PARM_01",42) SL DASTriggerSource 4 PrivateTag
+(0043,"GEMS_PARM_01",43) SL DASFpaGain 4 PrivateTag
+(0043,"GEMS_PARM_01",44) SL DASOutputSource 4 PrivateTag
+(0043,"GEMS_PARM_01",45) SL DASAdInput 4 PrivateTag
+(0043,"GEMS_PARM_01",46) SL DASCalMode 4 PrivateTag
+(0043,"GEMS_PARM_01",47) SL DASCalFrequency 4 PrivateTag
+(0043,"GEMS_PARM_01",48) SL DASRegXm 4 PrivateTag
+(0043,"GEMS_PARM_01",49) SL DASAutoZero 4 PrivateTag
+(0043,"GEMS_PARM_01",4a) SS StartingChannelOfView 4 PrivateTag
+(0043,"GEMS_PARM_01",4b) SL DASXmPattern 4 PrivateTag
+(0043,"GEMS_PARM_01",4c) SS TGGCTriggerMode 4 PrivateTag
+(0043,"GEMS_PARM_01",4d) FL StartScanToXrayOnDelay 4 PrivateTag
+(0043,"GEMS_PARM_01",4e) FL DurationOfXrayOn 4 PrivateTag
+(0043,"GEMS_PARM_01",60) IS SlopInteger10ToSlopInteger17 8 PrivateTag
+(0043,"GEMS_PARM_01",61) UI ScannerStudyEntityUID 1 PrivateTag
+(0043,"GEMS_PARM_01",62) SH ScannerStudyID 1 PrivateTag
+(0043,"GEMS_PARM_01",6f) DS ScannerTableEntry 3 PrivateTag
+(0043,"GEMS_PARM_01",70) LO ParadigmName 1 PrivateTag
+(0043,"GEMS_PARM_01",71) ST ParadigmDescription 1 PrivateTag
+(0043,"GEMS_PARM_01",72) UI ParadigmUID 1 PrivateTag
+(0043,"GEMS_PARM_01",73) US ExperimentType 1 PrivateTag
+(0043,"GEMS_PARM_01",74) US NumberOfRestVolumes 1 PrivateTag
+(0043,"GEMS_PARM_01",75) US NumberOfActiveVolumes 1 PrivateTag
+(0043,"GEMS_PARM_01",76) US NumberOfDummyScans 1 PrivateTag
+(0043,"GEMS_PARM_01",77) SH ApplicationName 1 PrivateTag
+(0043,"GEMS_PARM_01",78) SH ApplicationVersion 1 PrivateTag
+(0043,"GEMS_PARM_01",79) US SlicesPerVolume 1 PrivateTag
+(0043,"GEMS_PARM_01",7a) US ExpectedTimePoints 1 PrivateTag
+(0043,"GEMS_PARM_01",7b) FL RegressorValues 1-n PrivateTag
+(0043,"GEMS_PARM_01",7c) FL DelayAfterSliceGroup 1 PrivateTag
+(0043,"GEMS_PARM_01",7d) US ReconModeFlagWord 1 PrivateTag
+(0043,"GEMS_PARM_01",7e) LO PACCSpecificInformation 1-n PrivateTag
+(0043,"GEMS_PARM_01",7f) DS EDWIScaleFactor 1-n PrivateTag
+(0043,"GEMS_PARM_01",80) LO CoilIDData 1-n PrivateTag
+(0043,"GEMS_PARM_01",81) LO GECoilName 1 PrivateTag
+(0043,"GEMS_PARM_01",82) LO SystemConfigurationInformation 1-n PrivateTag
+(0043,"GEMS_PARM_01",83) DS AssetRFactors 1-2 PrivateTag
+(0043,"GEMS_PARM_01",84) LO AdditionalAssetData 5-n PrivateTag
+(0043,"GEMS_PARM_01",85) UT DebugDataTextFormat 1 PrivateTag
+(0043,"GEMS_PARM_01",86) OB DebugDataBinaryFormat 1 PrivateTag
+(0043,"GEMS_PARM_01",87) UT ScannerSoftwareVersionLongForm 1 PrivateTag
+(0043,"GEMS_PARM_01",88) UI PUREAcquisitionCalibrationSeriesUID 1 PrivateTag
+(0043,"GEMS_PARM_01",89) LO GoverningBodydBdtAndSARDefinition 3 PrivateTag
+(0043,"GEMS_PARM_01",8a) CS PrivateInPlanePhaseEncodingDirection 1 PrivateTag
+(0043,"GEMS_PARM_01",8b) OB FMRIBinaryDataBlock 1 PrivateTag
+(0043,"GEMS_PARM_01",8c) DS VoxelLocation 6 PrivateTag
+(0043,"GEMS_PARM_01",8d) DS SATBandLocations 7-7n PrivateTag
+(0043,"GEMS_PARM_01",8e) DS SpectroPrescanValues 3 PrivateTag
+(0043,"GEMS_PARM_01",8f) DS SpectroParameters 3 PrivateTag
+(0043,"GEMS_PARM_01",90) LO SARDefinition 1-n PrivateTag
+(0043,"GEMS_PARM_01",91) DS SARValue 1-n PrivateTag
+(0043,"GEMS_PARM_01",92) LO ImageErrorText 1 PrivateTag
+(0043,"GEMS_PARM_01",93) DS SpectroQuantitationValues 1-n PrivateTag
+(0043,"GEMS_PARM_01",94) DS SpectroRatioValues 1-n PrivateTag
+(0043,"GEMS_PARM_01",95) LO PrescanReuseString 1 PrivateTag
+(0043,"GEMS_PARM_01",96) CS ContentQualification 1 PrivateTag
+(0043,"GEMS_PARM_01",97) LO ImageFilteringParameters 9 PrivateTag
+(0043,"GEMS_PARM_01",98) UI ASSETAcquisitionCalibrationSeriesUID 1 PrivateTag
+(0043,"GEMS_PARM_01",99) LO ExtendedOptions 1-n PrivateTag
+(0043,"GEMS_PARM_01",9a) IS RxStackIdentification 1 PrivateTag
+(0043,"GEMS_PARM_01",9b) DS NPWFactor 1 PrivateTag
+(0043,"GEMS_PARM_01",9c) OB ResearchTag1 1 PrivateTag
+(0043,"GEMS_PARM_01",9d) OB ResearchTag2 1 PrivateTag
+(0043,"GEMS_PARM_01",9e) OB ResearchTag3 1 PrivateTag
+(0043,"GEMS_PARM_01",9f) OB ResearchTag4 1 PrivateTag
+
+(0011,"GEMS_PATI_01",10) SS PatientStatus 1 PrivateTag
+
+(0021,"GEMS_RELA_01",03) SS SeriesFromWhichPrescribed 1 PrivateTag
+(0021,"GEMS_RELA_01",05) SH GenesisVersionNow 1 PrivateTag
+(0021,"GEMS_RELA_01",07) UL SeriesRecordChecksum 1 PrivateTag
+(0021,"GEMS_RELA_01",15) US Unknown 1 PrivateTag
+(0021,"GEMS_RELA_01",16) SS Unknown 1 PrivateTag
+(0021,"GEMS_RELA_01",18) SH GenesisVersionNow 1 PrivateTag
+(0021,"GEMS_RELA_01",19) UL AcqReconRecordChecksum 1 PrivateTag
+(0021,"GEMS_RELA_01",20) DS TableStartLocation 1 PrivateTag
+(0021,"GEMS_RELA_01",35) SS SeriesFromWhichPrescribed 1 PrivateTag
+(0021,"GEMS_RELA_01",36) SS ImageFromWhichPrescribed 1 PrivateTag
+(0021,"GEMS_RELA_01",37) SS ScreenFormat 1 PrivateTag
+(0021,"GEMS_RELA_01",4a) LO AnatomicalReferenceForScout 1 PrivateTag
+(0021,"GEMS_RELA_01",4e) US Unknown 1 PrivateTag
+(0021,"GEMS_RELA_01",4f) SS LocationsInAcquisition 1 PrivateTag
+(0021,"GEMS_RELA_01",50) SS GraphicallyPrescribed 1 PrivateTag
+(0021,"GEMS_RELA_01",51) DS RotationFromSourceXRot 1 PrivateTag
+(0021,"GEMS_RELA_01",52) DS RotationFromSourceYRot 1 PrivateTag
+(0021,"GEMS_RELA_01",53) DS RotationFromSourceZRot 1 PrivateTag
+(0021,"GEMS_RELA_01",54) SH ImagePosition 3 PrivateTag
+(0021,"GEMS_RELA_01",55) SH ImageOrientation 6 PrivateTag
+(0021,"GEMS_RELA_01",56) SL IntegerSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",57) SL IntegerSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",58) SL IntegerSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",59) SL IntegerSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",5a) SL IntegerSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",5b) DS FloatSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",5c) DS FloatSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",5d) DS FloatSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",5e) DS FloatSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",5f) DS FloatSlop 1 PrivateTag
+(0021,"GEMS_RELA_01",70) LT Unknown 1 PrivateTag
+(0021,"GEMS_RELA_01",71) LT Unknown 1 PrivateTag
+(0021,"GEMS_RELA_01",81) DS AutoWindowLevelAlpha 1 PrivateTag
+(0021,"GEMS_RELA_01",82) DS AutoWindowLevelBeta 1 PrivateTag
+(0021,"GEMS_RELA_01",83) DS AutoWindowLevelWindow 1 PrivateTag
+(0021,"GEMS_RELA_01",84) DS AutoWindowLevelLevel 1 PrivateTag
+(0021,"GEMS_RELA_01",90) SS TubeFocalSpotPosition 1 PrivateTag
+(0021,"GEMS_RELA_01",91) SS BiopsyPosition 1 PrivateTag
+(0021,"GEMS_RELA_01",92) FL BiopsyTLocation 1 PrivateTag
+(0021,"GEMS_RELA_01",93) FL BiopsyRefLocation 1 PrivateTag
+
+(0045,"GEMS_SENO_02",04) CS AES 1 PrivateTag
+(0045,"GEMS_SENO_02",06) DS Angulation 1 PrivateTag
+(0045,"GEMS_SENO_02",09) DS RealMagnificationFactor 1 PrivateTag
+(0045,"GEMS_SENO_02",0b) CS SenographType 1 PrivateTag
+(0045,"GEMS_SENO_02",0c) DS IntegrationTime 1 PrivateTag
+(0045,"GEMS_SENO_02",0d) DS ROIOriginXY 1 PrivateTag
+(0045,"GEMS_SENO_02",11) DS ReceptorSizeCmXY 2 PrivateTag
+(0045,"GEMS_SENO_02",12) IS ReceptorSizePixelsXY 2 PrivateTag
+(0045,"GEMS_SENO_02",13) ST Screen 1 PrivateTag
+(0045,"GEMS_SENO_02",14) DS PixelPitchMicrons 1 PrivateTag
+(0045,"GEMS_SENO_02",15) IS PixelDepthBits 1 PrivateTag
+(0045,"GEMS_SENO_02",16) IS BinningFactorXY 2 PrivateTag
+(0045,"GEMS_SENO_02",1B) CS ClinicalView 1 PrivateTag
+(0045,"GEMS_SENO_02",1D) DS MeanOfRawGrayLevels 1 PrivateTag
+(0045,"GEMS_SENO_02",1E) DS MeanOfOffsetGrayLevels 1 PrivateTag
+(0045,"GEMS_SENO_02",1F) DS MeanOfCorrectedGrayLevels 1 PrivateTag
+(0045,"GEMS_SENO_02",20) DS MeanOfRegionGrayLevels 1 PrivateTag
+(0045,"GEMS_SENO_02",21) DS MeanOfLogRegionGrayLevels 1 PrivateTag
+(0045,"GEMS_SENO_02",22) DS StandardDeviationOfRawGrayLevels 1 PrivateTag
+(0045,"GEMS_SENO_02",23) DS StandardDeviationOfCorrectedGrayLevels 1 PrivateTag
+(0045,"GEMS_SENO_02",24) DS StandardDeviationOfRegionGrayLevels 1 PrivateTag
+(0045,"GEMS_SENO_02",25) DS StandardDeviationOfLogRegionGrayLevels 1 PrivateTag
+(0045,"GEMS_SENO_02",26) OB MAOBuffer 1 PrivateTag
+(0045,"GEMS_SENO_02",27) IS SetNumber 1 PrivateTag
+(0045,"GEMS_SENO_02",28) CS WindowingType 1 PrivateTag
+(0045,"GEMS_SENO_02",29) DS WindowingParameters 1-n PrivateTag
+(0045,"GEMS_SENO_02",2a) IS CrosshairCursorXCoordinates 1 PrivateTag
+(0045,"GEMS_SENO_02",2b) IS CrosshairCursorYCoordinates 1 PrivateTag
+(0045,"GEMS_SENO_02",39) US VignetteRows 1 PrivateTag
+(0045,"GEMS_SENO_02",3a) US VignetteColumns 1 PrivateTag
+(0045,"GEMS_SENO_02",3b) US VignetteBitsAllocated 1 PrivateTag
+(0045,"GEMS_SENO_02",3c) US VignetteBitsStored 1 PrivateTag
+(0045,"GEMS_SENO_02",3d) US VignetteHighBit 1 PrivateTag
+(0045,"GEMS_SENO_02",3e) US VignettePixelRepresentation 1 PrivateTag
+(0045,"GEMS_SENO_02",3f) OB VignettePixelData 1 PrivateTag
+
+(0025,"GEMS_SERS_01",06) SS LastPulseSequenceUsed 1 PrivateTag
+(0025,"GEMS_SERS_01",07) SL ImagesInSeries 1 PrivateTag
+(0025,"GEMS_SERS_01",10) SL LandmarkCounter 1 PrivateTag
+(0025,"GEMS_SERS_01",11) SS NumberOfAcquisitions 1 PrivateTag
+(0025,"GEMS_SERS_01",14) SL IndicatesNumberOfUpdatesToHeader 1 PrivateTag
+(0025,"GEMS_SERS_01",17) SL SeriesCompleteFlag 1 PrivateTag
+(0025,"GEMS_SERS_01",18) SL NumberOfImagesArchived 1 PrivateTag
+(0025,"GEMS_SERS_01",19) SL LastImageNumberUsed 1 PrivateTag
+(0025,"GEMS_SERS_01",1a) SH PrimaryReceiverSuiteAndHost 1 PrivateTag
+
+(0023,"GEMS_STDY_01",01) SL NumberOfSeriesInStudy 1 PrivateTag
+(0023,"GEMS_STDY_01",02) SL NumberOfUnarchivedSeries 1 PrivateTag
+(0023,"GEMS_STDY_01",10) SS ReferenceImageField 1 PrivateTag
+(0023,"GEMS_STDY_01",50) SS SummaryImage 1 PrivateTag
+(0023,"GEMS_STDY_01",70) FD StartTimeSecsInFirstAxial 1 PrivateTag
+(0023,"GEMS_STDY_01",74) SL NumberOfUpdatesToHeader 1 PrivateTag
+(0023,"GEMS_STDY_01",7d) SS IndicatesIfStudyHasCompleteInfo 1 PrivateTag
+
+(0033,"GEMS_YMHD_01",05) UN Unknown 1 PrivateTag
+(0033,"GEMS_YMHD_01",06) UN Unknown 1 PrivateTag
+
+(0019,"GE_GENESIS_REV3.0",39) SS AxialType 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",8f) SS SwapPhaseFrequency 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",9c) SS PulseSequenceName 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",9f) SS CoilType 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",a4) SS SATFatWaterBone 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",c0) SS BitmapOfSATSelections 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",c1) SS SurfaceCoilIntensityCorrectionFlag 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",cb) SS PhaseContrastFlowAxis 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",cc) SS PhaseContrastVelocityEncoding 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",d5) SS FractionalEcho 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",d8) SS VariableEchoFlag 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",d9) DS ConcatenatedSat 1 PrivateTag
+(0019,"GE_GENESIS_REV3.0",f2) SS NumberOfPhases 1 PrivateTag
+(0043,"GE_GENESIS_REV3.0",1e) DS DeltaStartTime 1 PrivateTag
+(0043,"GE_GENESIS_REV3.0",27) SH ScanPitchRatio 1 PrivateTag
+
+(0029,"INTELERAD MEDICAL SYSTEMS",01) FD ImageCompressionFraction 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",02) FD ImageQuality 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",03) FD ImageBytesTransferred 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",10) SH J2cParameterType 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",11) US J2cPixelRepresentation 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",12) US J2cBitsAllocated 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",13) US J2cPixelShiftValue 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",14) US J2cPlanarConfiguration 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",15) DS J2cRescaleIntercept 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",20) LO PixelDataMD5SumPerFrame 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",21) US HistogramPercentileLabels 1 PrivateTag
+(0029,"INTELERAD MEDICAL SYSTEMS",22) FD HistogramPercentileValues 1 PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",01) LO InstitutionCode 1 PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",02) LO RoutedTransferAE 1 PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",03) LO SourceAE 1 PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",04) SH DeferredValidation 1 PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",05) LO SeriesOwner 1 PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",06) LO OrderGroupNumber 1 PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",07) SH StrippedPixelData 1 PrivateTag
+(3f01,"INTELERAD MEDICAL SYSTEMS",08) SH PendingMoveRequest 1 PrivateTag
+
+(0041,"INTEGRIS 1.0",20) FL AccumulatedFluoroscopyDose 1 PrivateTag
+(0041,"INTEGRIS 1.0",30) FL AccumulatedExposureDose 1 PrivateTag
+(0041,"INTEGRIS 1.0",40) FL TotalDose 1 PrivateTag
+(0041,"INTEGRIS 1.0",41) FL TotalNumberOfFrames 1 PrivateTag
+(0041,"INTEGRIS 1.0",50) SQ ExposureInformationSequence 1 PrivateTag
+(0009,"INTEGRIS 1.0",08) CS ExposureChannel 1-n PrivateTag
+(0009,"INTEGRIS 1.0",32) TM ExposureStartTime 1 PrivateTag
+(0019,"INTEGRIS 1.0",00) LO APRName 1 PrivateTag
+(0019,"INTEGRIS 1.0",40) DS FrameRate 1 PrivateTag
+(0021,"INTEGRIS 1.0",12) IS ExposureNumber 1 PrivateTag
+(0029,"INTEGRIS 1.0",08) IS NumberOfExposureResults 1 PrivateTag
+
+(0029,"ISG shadow",70) IS Unknown 1 PrivateTag
+(0029,"ISG shadow",80) IS Unknown 1 PrivateTag
+(0029,"ISG shadow",90) IS Unknown 1 PrivateTag
+
+(0009,"ISI",01) UN SIENETGeneralPurposeIMGEF 1 PrivateTag
+
+(0009,"MERGE TECHNOLOGIES, INC.",00) OB Unknown 1 PrivateTag
+
+(0029,"OCULUS Optikgeraete GmbH",1010) OB OriginalMeasuringData 1 PrivateTag
+(0029,"OCULUS Optikgeraete GmbH",1012) UL OriginalMeasuringDataLength 1 PrivateTag
+(0029,"OCULUS Optikgeraete GmbH",1020) OB OriginalMeasuringRawData 1 PrivateTag
+(0029,"OCULUS Optikgeraete GmbH",1022) UL OriginalMeasuringRawDataLength 1 PrivateTag
+
+(0041,"PAPYRUS 3.0",00) LT PapyrusComments 1 PrivateTag
+(0041,"PAPYRUS 3.0",10) SQ PointerSequence 1 PrivateTag
+(0041,"PAPYRUS 3.0",11) UL ImagePointer 1 PrivateTag
+(0041,"PAPYRUS 3.0",12) UL PixelOffset 1 PrivateTag
+(0041,"PAPYRUS 3.0",13) SQ ImageIdentifierSequence 1 PrivateTag
+(0041,"PAPYRUS 3.0",14) SQ ExternalFileReferenceSequence 1 PrivateTag
+(0041,"PAPYRUS 3.0",15) US NumberOfImages 1 PrivateTag
+(0041,"PAPYRUS 3.0",21) UI ReferencedSOPClassUID 1 PrivateTag
+(0041,"PAPYRUS 3.0",22) UI ReferencedSOPInstanceUID 1 PrivateTag
+(0041,"PAPYRUS 3.0",31) LT ReferencedFileName 1 PrivateTag
+(0041,"PAPYRUS 3.0",32) LT ReferencedFilePath 1-n PrivateTag
+(0041,"PAPYRUS 3.0",41) UI ReferencedImageSOPClassUID 1 PrivateTag
+(0041,"PAPYRUS 3.0",42) UI ReferencedImageSOPInstanceUID 1 PrivateTag
+(0041,"PAPYRUS 3.0",50) SQ ImageSequence 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",00) IS OverlayID 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",01) LT LinkedOverlays 1-n PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",10) US OverlayRows 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",11) US OverlayColumns 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",40) LO OverlayType 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",50) US OverlayOrigin 1-n PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",60) LO Editable 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",70) LO OverlayFont 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",72) LO OverlayStyle 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",74) US OverlayFontSize 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",76) LO OverlayColor 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",78) US ShadowSize 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",80) LO FillPattern 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",82) US OverlayPenSize 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",a0) LO Label 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",a2) LT PostItText 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",a4) US AnchorPoint 2 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",b0) LO ROIType 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",b2) LT AttachedAnnotation 1 PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",ba) US ContourPoints 1-n PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",bc) US MaskData 1-n PrivateTag
+(6001-o-60ff,"PAPYRUS 3.0",c0) SQ UINOverlaySequence 1 PrivateTag
+
+(0009,"PAPYRUS",00) LT OriginalFileName 1 PrivateTag
+(0009,"PAPYRUS",10) LT OriginalFileLocation 1 PrivateTag
+(0009,"PAPYRUS",18) LT DataSetIdentifier 1 PrivateTag
+(0041,"PAPYRUS",00) LT PapyrusComments 1-n PrivateTag
+(0041,"PAPYRUS",10) US FolderType 1 PrivateTag
+(0041,"PAPYRUS",11) LT PatientFolderDataSetID 1 PrivateTag
+(0041,"PAPYRUS",20) LT FolderName 1 PrivateTag
+(0041,"PAPYRUS",30) DA CreationDate 1 PrivateTag
+(0041,"PAPYRUS",32) TM CreationTime 1 PrivateTag
+(0041,"PAPYRUS",34) DA ModifiedDate 1 PrivateTag
+(0041,"PAPYRUS",36) TM ModifiedTime 1 PrivateTag
+(0041,"PAPYRUS",40) LT OwnerName 1-n PrivateTag
+(0041,"PAPYRUS",50) LT FolderStatus 1 PrivateTag
+(0041,"PAPYRUS",60) UL NumberOfImages 1 PrivateTag
+(0041,"PAPYRUS",62) UL NumberOfOther 1 PrivateTag
+(0041,"PAPYRUS",a0) LT ExternalFolderElementDSID 1-n PrivateTag
+(0041,"PAPYRUS",a1) US ExternalFolderElementDataSetType 1-n PrivateTag
+(0041,"PAPYRUS",a2) LT ExternalFolderElementFileLocation 1-n PrivateTag
+(0041,"PAPYRUS",a3) UL ExternalFolderElementLength 1-n PrivateTag
+(0041,"PAPYRUS",b0) LT InternalFolderElementDSID 1-n PrivateTag
+(0041,"PAPYRUS",b1) US InternalFolderElementDataSetType 1-n PrivateTag
+(0041,"PAPYRUS",b2) UL InternalOffsetToDataSet 1-n PrivateTag
+(0041,"PAPYRUS",b3) UL InternalOffsetToImage 1-n
+
+# Note: Some Philips devices use these private tags with reservation value
+# "Philips Imaging DD 001", others use "PHILIPS IMAGING DD 001". All attributes
+# should thus be present twice in this dictionary, once for each spelling variant.
+#
+(2001,"Philips Imaging DD 001",01) FL ChemicalShift 1 PrivateTag
+(2001,"Philips Imaging DD 001",02) IS ChemicalShiftNumberMR 1 PrivateTag
+(2001,"Philips Imaging DD 001",03) FL DiffusionBFactor 1 PrivateTag
+(2001,"Philips Imaging DD 001",04) CS DiffusionDirection 1 PrivateTag
+(2001,"Philips Imaging DD 001",06) CS ImageEnhanced 1 PrivateTag
+(2001,"Philips Imaging DD 001",07) CS ImageTypeEDES 1 PrivateTag
+(2001,"Philips Imaging DD 001",08) IS PhaseNumber 1 PrivateTag
+(2001,"Philips Imaging DD 001",09) FL ImagePrepulseDelay 1 PrivateTag
+(2001,"Philips Imaging DD 001",0a) IS SliceNumberMR 1 PrivateTag
+(2001,"Philips Imaging DD 001",0b) CS SliceOrientation 1 PrivateTag
+(2001,"Philips Imaging DD 001",0c) CS ArrhythmiaRejection 1 PrivateTag
+(2001,"Philips Imaging DD 001",0e) CS CardiacCycled 1 PrivateTag
+(2001,"Philips Imaging DD 001",0f) SS CardiacGateWidth 1 PrivateTag
+(2001,"Philips Imaging DD 001",10) CS CardiacSync 1 PrivateTag
+(2001,"Philips Imaging DD 001",11) FL DiffusionEchoTime 1 PrivateTag
+(2001,"Philips Imaging DD 001",12) CS DynamicSeries 1 PrivateTag
+(2001,"Philips Imaging DD 001",13) SL EPIFactor 1 PrivateTag
+(2001,"Philips Imaging DD 001",14) SL NumberOfEchoes 1 PrivateTag
+(2001,"Philips Imaging DD 001",15) SS NumberOfLocations 1 PrivateTag
+(2001,"Philips Imaging DD 001",16) SS NumberOfPCDirections 1 PrivateTag
+(2001,"Philips Imaging DD 001",17) SL NumberOfPhasesMR 1 PrivateTag
+(2001,"Philips Imaging DD 001",18) SL NumberOfSlicesMR 1 PrivateTag
+(2001,"Philips Imaging DD 001",19) CS PartialMatrixScanned 1 PrivateTag
+(2001,"Philips Imaging DD 001",1a) FL PCVelocity 1-n PrivateTag
+(2001,"Philips Imaging DD 001",1b) FL PrepulseDelay 1 PrivateTag
+(2001,"Philips Imaging DD 001",1c) CS PrepulseType 1 PrivateTag
+(2001,"Philips Imaging DD 001",1d) IS ReconstructionNumberMR 1 PrivateTag
+(2001,"Philips Imaging DD 001",1f) CS RespirationSync 1 PrivateTag
+(2001,"Philips Imaging DD 001",20) LO ScanningTechnique 1 PrivateTag
+(2001,"Philips Imaging DD 001",21) CS SPIR 1 PrivateTag
+(2001,"Philips Imaging DD 001",22) FL WaterFatShift 1 PrivateTag
+(2001,"Philips Imaging DD 001",23) DS FlipAnglePhilips 1 PrivateTag
+(2001,"Philips Imaging DD 001",24) CS SeriesIsInteractive 1 PrivateTag
+(2001,"Philips Imaging DD 001",25) SH EchoTimeDisplayMR 1 PrivateTag
+(2001,"Philips Imaging DD 001",26) CS PresentationStateSubtractionActive 1 PrivateTag
+(2001,"Philips Imaging DD 001",2d) SS StackNumberOfSlices 1 PrivateTag
+(2001,"Philips Imaging DD 001",32) FL StackRadialAngle 1 PrivateTag
+(2001,"Philips Imaging DD 001",33) CS StackRadialAxis 1 PrivateTag
+(2001,"Philips Imaging DD 001",35) SS StackSliceNumber 1 PrivateTag
+(2001,"Philips Imaging DD 001",36) CS StackType 1 PrivateTag
+(2001,"Philips Imaging DD 001",3f) CS ZoomMode 1 PrivateTag
+(2001,"Philips Imaging DD 001",58) UL ContrastTransferTaste 1 PrivateTag
+(2001,"Philips Imaging DD 001",5f) SQ StackSequence 1 PrivateTag
+(2001,"Philips Imaging DD 001",60) SL NumberOfStacks 1 PrivateTag
+(2001,"Philips Imaging DD 001",61) CS SeriesTransmitted 1 PrivateTag
+(2001,"Philips Imaging DD 001",62) CS SeriesCommitted 1 PrivateTag
+(2001,"Philips Imaging DD 001",63) CS ExaminationSource 1 PrivateTag
+(2001,"Philips Imaging DD 001",67) CS LinearPresentationGLTrafoShapeSub 1 PrivateTag
+(2001,"Philips Imaging DD 001",77) CS GLTrafoType 1 PrivateTag
+(2001,"Philips Imaging DD 001",7b) IS AcquisitionNumber 1 PrivateTag
+(2001,"Philips Imaging DD 001",81) IS NumberOfDynamicScans 1 PrivateTag
+(2001,"Philips Imaging DD 001",9f) US PixelProcessingKernelSize 1 PrivateTag
+(2001,"Philips Imaging DD 001",a1) CS IsRawImage 1 PrivateTag
+(2001,"Philips Imaging DD 001",f1) FL ProspectiveMotionCorrection 1 PrivateTag
+(2001,"Philips Imaging DD 001",f2) FL RetrospectiveMotionCorrection 1 PrivateTag
+
+# Note: Some Philips devices use these private tags with reservation value
+# "Philips Imaging DD 001", others use "PHILIPS IMAGING DD 001". All attributes
+# should thus be present twice in this dictionary, once for each spelling variant.
+#
+(2001,"PHILIPS IMAGING DD 001",01) FL ChemicalShift 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",02) IS ChemicalShiftNumberMR 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",03) FL DiffusionBFactor 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",04) CS DiffusionDirection 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",06) CS ImageEnhanced 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",07) CS ImageTypeEDES 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",08) IS PhaseNumber 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",09) FL ImagePrepulseDelay 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0a) IS SliceNumberMR 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0b) CS SliceOrientation 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0c) CS ArrhythmiaRejection 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0e) CS CardiacCycled 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",0f) SS CardiacGateWidth 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",10) CS CardiacSync 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",11) FL DiffusionEchoTime 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",12) CS DynamicSeries 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",13) SL EPIFactor 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",14) SL NumberOfEchoes 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",15) SS NumberOfLocations 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",16) SS NumberOfPCDirections 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",17) SL NumberOfPhasesMR 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",18) SL NumberOfSlicesMR 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",19) CS PartialMatrixScanned 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1a) FL PCVelocity 1-n PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1b) FL PrepulseDelay 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1c) CS PrepulseType 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1d) IS ReconstructionNumberMR 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",1f) CS RespirationSync 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",20) LO ScanningTechnique 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",21) CS SPIR 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",22) FL WaterFatShift 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",23) DS FlipAnglePhilips 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",24) CS SeriesIsInteractive 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",25) SH EchoTimeDisplayMR 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",26) CS PresentationStateSubtractionActive 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",2d) SS StackNumberOfSlices 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",32) FL StackRadialAngle 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",33) CS StackRadialAxis 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",35) SS StackSliceNumber 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",36) CS StackType 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",3f) CS ZoomMode 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",58) UL ContrastTransferTaste 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",5f) SQ StackSequence 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",60) SL NumberOfStacks 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",61) CS SeriesTransmitted 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",62) CS SeriesCommitted 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",63) CS ExaminationSource 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",67) CS LinearPresentationGLTrafoShapeSub 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",77) CS GLTrafoType 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",7b) IS AcquisitionNumber 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",81) IS NumberOfDynamicScans 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",9f) US PixelProcessingKernelSize 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",a1) CS IsRawImage 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",f1) FL ProspectiveMotionCorrection 1 PrivateTag
+(2001,"PHILIPS IMAGING DD 001",f2) FL RetrospectiveMotionCorrection 1 PrivateTag
+
+# Note: Some Philips devices use these private tags with reservation value
+# "Philips MR Imaging DD 001", others use "PHILIPS MR IMAGING DD 001". All attributes
+# should thus be present twice in this dictionary, once for each spelling variant.
+#
+(2005,"Philips MR Imaging DD 001",05) CS SynergyReconstructionType 1 PrivateTag
+(2005,"Philips MR Imaging DD 001",1e) SH MIPProtocol 1 PrivateTag
+(2005,"Philips MR Imaging DD 001",1f) SH MPRProtocol 1 PrivateTag
+(2005,"Philips MR Imaging DD 001",20) SL NumberOfChemicalShifts 1 PrivateTag
+(2005,"Philips MR Imaging DD 001",2d) SS NumberOfStackSlices 1 PrivateTag
+(2005,"Philips MR Imaging DD 001",83) SQ Unknown 1 PrivateTag
+(2005,"Philips MR Imaging DD 001",a1) CS SyncraScanType 1 PrivateTag
+(2005,"Philips MR Imaging DD 001",b0) FL DiffusionDirectionRL 1 PrivateTag
+(2005,"Philips MR Imaging DD 001",b1) FL DiffusionDirectionAP 1 PrivateTag
+(2005,"Philips MR Imaging DD 001",b2) FL DiffusionDirectionFH 1 PrivateTag
+
+(2005,"Philips MR Imaging DD 005",02) SQ Unknown 1 PrivateTag
+
+# Note: Some Philips devices use these private tags with reservation value
+# "Philips MR Imaging DD 001", others use "PHILIPS MR IMAGING DD 001". All attributes
+# should thus be present twice in this dictionary, once for each spelling variant.
+#
+(2005,"PHILIPS MR IMAGING DD 001",05) CS SynergyReconstructionType 1 PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",1e) SH MIPProtocol 1 PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",1f) SH MPRProtocol 1 PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",20) SL NumberOfChemicalShifts 1 PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",2d) SS NumberOfStackSlices 1 PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",83) SQ Unknown 1 PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",a1) CS SyncraScanType 1 PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",b0) FL DiffusionDirectionRL 1 PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",b1) FL DiffusionDirectionAP 1 PrivateTag
+(2005,"PHILIPS MR IMAGING DD 001",b2) FL DiffusionDirectionFH 1 PrivateTag
+
+(0019,"PHILIPS MR R5.5/PART",1000) DS FieldOfView 1 PrivateTag
+(0019,"PHILIPS MR R5.6/PART",1000) DS FieldOfView 1 PrivateTag
+
+(0019,"PHILIPS MR SPECTRO;1",01) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",02) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",03) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",04) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",05) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",06) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",07) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",08) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",09) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",10) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",12) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",13) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",14) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",15) US Unknown 1-n PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",16) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",17) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",18) UN Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",20) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",21) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",22) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",23) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",24) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",25) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",26) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",27) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",28) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",29) IS Unknown 1-n PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",31) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",32) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",41) LT Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",42) IS Unknown 2 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",43) IS Unknown 2 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",45) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",46) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",47) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",48) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",49) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",50) UN Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",60) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",61) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",70) UN Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",71) IS Unknown 1-n PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",72) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",73) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",74) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",76) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",77) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",78) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",79) US Unknown 1 PrivateTag
+(0019,"PHILIPS MR SPECTRO;1",80) IS Unknown 1 PrivateTag
+
+(0009,"PHILIPS MR",10) LO SPIRelease 1 PrivateTag
+(0009,"PHILIPS MR",12) LO Unknown 1 PrivateTag
+
+(0019,"PHILIPS MR/LAST",09) DS MainMagneticField 1 PrivateTag
+(0019,"PHILIPS MR/LAST",0e) IS FlowCompensation 1 PrivateTag
+(0019,"PHILIPS MR/LAST",b1) IS MinimumRRInterval 1 PrivateTag
+(0019,"PHILIPS MR/LAST",b2) IS MaximumRRInterval 1 PrivateTag
+(0019,"PHILIPS MR/LAST",b3) IS NumberOfRejections 1 PrivateTag
+(0019,"PHILIPS MR/LAST",b4) IS NumberOfRRIntervals 1-n PrivateTag
+(0019,"PHILIPS MR/LAST",b5) IS ArrhythmiaRejection 1 PrivateTag
+(0019,"PHILIPS MR/LAST",c0) DS Unknown 1-n PrivateTag
+(0019,"PHILIPS MR/LAST",c6) IS CycledMultipleSlice 1 PrivateTag
+(0019,"PHILIPS MR/LAST",ce) IS REST 1 PrivateTag
+(0019,"PHILIPS MR/LAST",d5) DS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/LAST",d6) IS FourierInterpolation 1 PrivateTag
+(0019,"PHILIPS MR/LAST",d9) IS Unknown 1-n PrivateTag
+(0019,"PHILIPS MR/LAST",e0) IS Prepulse 1 PrivateTag
+(0019,"PHILIPS MR/LAST",e1) DS PrepulseDelay 1 PrivateTag
+(0019,"PHILIPS MR/LAST",e2) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/LAST",e3) DS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/LAST",f0) LT WSProtocolString1 1 PrivateTag
+(0019,"PHILIPS MR/LAST",f1) LT WSProtocolString2 1 PrivateTag
+(0019,"PHILIPS MR/LAST",f2) LT WSProtocolString3 1 PrivateTag
+(0019,"PHILIPS MR/LAST",f3) LT WSProtocolString4 1 PrivateTag
+(0021,"PHILIPS MR/LAST",00) IS Unknown 1 PrivateTag
+(0021,"PHILIPS MR/LAST",10) IS Unknown 1 PrivateTag
+(0021,"PHILIPS MR/LAST",20) IS Unknown 1 PrivateTag
+(0021,"PHILIPS MR/LAST",21) DS SliceGap 1 PrivateTag
+(0021,"PHILIPS MR/LAST",22) DS StackRadialAngle 1 PrivateTag
+(0027,"PHILIPS MR/LAST",00) US Unknown 1 PrivateTag
+(0027,"PHILIPS MR/LAST",11) US Unknown 1-n PrivateTag
+(0027,"PHILIPS MR/LAST",12) DS Unknown 1-n PrivateTag
+(0027,"PHILIPS MR/LAST",13) DS Unknown 1-n PrivateTag
+(0027,"PHILIPS MR/LAST",14) DS Unknown 1-n PrivateTag
+(0027,"PHILIPS MR/LAST",15) DS Unknown 1-n PrivateTag
+(0027,"PHILIPS MR/LAST",16) LO Unknown 1 PrivateTag
+(0029,"PHILIPS MR/LAST",10) DS FPMin 1 PrivateTag
+(0029,"PHILIPS MR/LAST",20) DS FPMax 1 PrivateTag
+(0029,"PHILIPS MR/LAST",30) DS ScaledMinimum 1 PrivateTag
+(0029,"PHILIPS MR/LAST",40) DS ScaledMaximum 1 PrivateTag
+(0029,"PHILIPS MR/LAST",50) DS WindowMinimum 1 PrivateTag
+(0029,"PHILIPS MR/LAST",60) DS WindowMaximum 1 PrivateTag
+(0029,"PHILIPS MR/LAST",61) IS Unknown 1 PrivateTag
+(0029,"PHILIPS MR/LAST",70) DS Unknown 1 PrivateTag
+(0029,"PHILIPS MR/LAST",71) DS Unknown 1 PrivateTag
+(0029,"PHILIPS MR/LAST",72) IS Unknown 1 PrivateTag
+(0029,"PHILIPS MR/LAST",80) IS ViewCenter 1 PrivateTag
+(0029,"PHILIPS MR/LAST",81) IS ViewSize 1 PrivateTag
+(0029,"PHILIPS MR/LAST",82) IS ViewZoom 1 PrivateTag
+(0029,"PHILIPS MR/LAST",83) IS ViewTransform 1 PrivateTag
+(6001,"PHILIPS MR/LAST",00) LT Unknown 1 PrivateTag
+
+(0019,"PHILIPS MR/PART",1000) DS FieldOfView 1 PrivateTag
+(0019,"PHILIPS MR/PART",1005) DS CCAngulation 1 PrivateTag
+(0019,"PHILIPS MR/PART",1006) DS APAngulation 1 PrivateTag
+(0019,"PHILIPS MR/PART",1007) DS LRAngulation 1 PrivateTag
+(0019,"PHILIPS MR/PART",1008) IS PatientPosition 1 PrivateTag
+(0019,"PHILIPS MR/PART",1009) IS PatientOrientation 1 PrivateTag
+(0019,"PHILIPS MR/PART",100a) IS SliceOrientation 1 PrivateTag
+(0019,"PHILIPS MR/PART",100b) DS LROffcenter 1 PrivateTag
+(0019,"PHILIPS MR/PART",100c) DS CCOffcenter 1 PrivateTag
+(0019,"PHILIPS MR/PART",100d) DS APOffcenter 1 PrivateTag
+(0019,"PHILIPS MR/PART",100e) DS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",100f) IS NumberOfSlices 1 PrivateTag
+(0019,"PHILIPS MR/PART",1010) DS SliceFactor 1 PrivateTag
+(0019,"PHILIPS MR/PART",1011) DS EchoTimes 1-n PrivateTag
+(0019,"PHILIPS MR/PART",1015) IS DynamicStudy 1 PrivateTag
+(0019,"PHILIPS MR/PART",1018) DS HeartbeatInterval 1 PrivateTag
+(0019,"PHILIPS MR/PART",1019) DS RepetitionTimeFFE 1 PrivateTag
+(0019,"PHILIPS MR/PART",101a) DS FFEFlipAngle 1 PrivateTag
+(0019,"PHILIPS MR/PART",101b) IS NumberOfScans 1 PrivateTag
+(0019,"PHILIPS MR/PART",1021) DS Unknown 1-n PrivateTag
+(0019,"PHILIPS MR/PART",1022) DS DynamicScanTimeBegin 1 PrivateTag
+(0019,"PHILIPS MR/PART",1024) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",1064) DS RepetitionTimeSE 1 PrivateTag
+(0019,"PHILIPS MR/PART",1065) DS RepetitionTimeIR 1 PrivateTag
+(0019,"PHILIPS MR/PART",1069) IS NumberOfPhases 1 PrivateTag
+(0019,"PHILIPS MR/PART",106a) IS CardiacFrequency 1 PrivateTag
+(0019,"PHILIPS MR/PART",106b) DS InversionDelay 1 PrivateTag
+(0019,"PHILIPS MR/PART",106c) DS GateDelay 1 PrivateTag
+(0019,"PHILIPS MR/PART",106d) DS GateWidth 1 PrivateTag
+(0019,"PHILIPS MR/PART",106e) DS TriggerDelayTime 1 PrivateTag
+(0019,"PHILIPS MR/PART",1080) IS NumberOfChemicalShifts 1 PrivateTag
+(0019,"PHILIPS MR/PART",1081) DS ChemicalShift 1 PrivateTag
+(0019,"PHILIPS MR/PART",1084) IS NumberOfRows 1 PrivateTag
+(0019,"PHILIPS MR/PART",1085) IS NumberOfSamples 1 PrivateTag
+(0019,"PHILIPS MR/PART",1094) LO MagnetizationTransferContrast 1 PrivateTag
+(0019,"PHILIPS MR/PART",1095) LO SpectralPresaturationWithInversionRecovery 1 PrivateTag
+(0019,"PHILIPS MR/PART",1096) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",1097) LO Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10a0) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10a1) DS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10a3) DS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10a4) CS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10c8) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10c9) IS FoldoverDirectionTransverse 1 PrivateTag
+(0019,"PHILIPS MR/PART",10ca) IS FoldoverDirectionSagittal 1 PrivateTag
+(0019,"PHILIPS MR/PART",10cb) IS FoldoverDirectionCoronal 1 PrivateTag
+(0019,"PHILIPS MR/PART",10cc) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10cd) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10ce) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10cf) IS NumberOfEchoes 1 PrivateTag
+(0019,"PHILIPS MR/PART",10d0) IS ScanResolution 1 PrivateTag
+(0019,"PHILIPS MR/PART",10d2) LO WaterFatShift 2 PrivateTag
+(0019,"PHILIPS MR/PART",10d4) IS ArtifactReduction 1 PrivateTag
+(0019,"PHILIPS MR/PART",10d5) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10d6) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10d7) DS ScanPercentage 1 PrivateTag
+(0019,"PHILIPS MR/PART",10d8) IS Halfscan 1 PrivateTag
+(0019,"PHILIPS MR/PART",10d9) IS EPIFactor 1 PrivateTag
+(0019,"PHILIPS MR/PART",10da) IS TurboFactor 1 PrivateTag
+(0019,"PHILIPS MR/PART",10db) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",10e0) IS PercentageOfScanCompleted 1 PrivateTag
+(0019,"PHILIPS MR/PART",10e1) IS Unknown 1 PrivateTag
+(0019,"PHILIPS MR/PART",1100) IS NumberOfStacks 1 PrivateTag
+(0019,"PHILIPS MR/PART",1101) IS StackType 1-n PrivateTag
+(0019,"PHILIPS MR/PART",1102) IS Unknown 1-n PrivateTag
+(0019,"PHILIPS MR/PART",110b) DS LROffcenter 1 PrivateTag
+(0019,"PHILIPS MR/PART",110c) DS CCOffcenter 1 PrivateTag
+(0019,"PHILIPS MR/PART",110d) DS APOffcenter 1 PrivateTag
+(0019,"PHILIPS MR/PART",1145) IS ReconstructionResolution 1 PrivateTag
+(0019,"PHILIPS MR/PART",11fc) IS ResonanceFrequency 1 PrivateTag
+(0019,"PHILIPS MR/PART",12c0) DS TriggerDelayTimes 1 PrivateTag
+(0019,"PHILIPS MR/PART",12e0) IS PrepulseType 1 PrivateTag
+(0019,"PHILIPS MR/PART",12e1) DS PrepulseDelay 1 PrivateTag
+(0019,"PHILIPS MR/PART",12e3) DS PhaseContrastVelocity 1 PrivateTag
+(0021,"PHILIPS MR/PART",1000) IS ReconstructionNumber 1 PrivateTag
+(0021,"PHILIPS MR/PART",1010) IS ImageType 1 PrivateTag
+(0021,"PHILIPS MR/PART",1020) IS SliceNumber 1 PrivateTag
+(0021,"PHILIPS MR/PART",1030) IS EchoNumber 1 PrivateTag
+(0021,"PHILIPS MR/PART",1031) DS PatientReferenceID 1 PrivateTag
+(0021,"PHILIPS MR/PART",1035) IS ChemicalShiftNumber 1 PrivateTag
+(0021,"PHILIPS MR/PART",1040) IS PhaseNumber 1 PrivateTag
+(0021,"PHILIPS MR/PART",1050) IS DynamicScanNumber 1 PrivateTag
+(0021,"PHILIPS MR/PART",1060) IS NumberOfRowsInObject 1 PrivateTag
+(0021,"PHILIPS MR/PART",1061) IS RowNumber 1-n PrivateTag
+(0021,"PHILIPS MR/PART",1062) IS Unknown 1-n PrivateTag
+(0021,"PHILIPS MR/PART",1100) DA ScanDate 1 PrivateTag
+(0021,"PHILIPS MR/PART",1110) TM ScanTime 1 PrivateTag
+(0021,"PHILIPS MR/PART",1221) IS SliceGap 1 PrivateTag
+(0029,"PHILIPS MR/PART",00) DS Unknown 2 PrivateTag
+(0029,"PHILIPS MR/PART",04) US Unknown 1 PrivateTag
+(0029,"PHILIPS MR/PART",10) DS Unknown 1 PrivateTag
+(0029,"PHILIPS MR/PART",11) DS Unknown 1 PrivateTag
+(0029,"PHILIPS MR/PART",20) LO Unknown 1 PrivateTag
+(0029,"PHILIPS MR/PART",31) DS Unknown 2 PrivateTag
+(0029,"PHILIPS MR/PART",32) DS Unknown 2 PrivateTag
+(0029,"PHILIPS MR/PART",c3) IS ScanResolution 1 PrivateTag
+(0029,"PHILIPS MR/PART",c4) IS FieldOfView 1 PrivateTag
+(0029,"PHILIPS MR/PART",d5) LT SliceThickness 1 PrivateTag
+
+(0019,"PHILIPS-MR-1",11) IS ChemicalShiftNumber 1 PrivateTag
+(0019,"PHILIPS-MR-1",12) IS PhaseNumber 1 PrivateTag
+(0021,"PHILIPS-MR-1",01) IS ReconstructionNumber 1 PrivateTag
+(0021,"PHILIPS-MR-1",02) IS SliceNumber 1 PrivateTag
+
+(7001,"Picker NM Private Group",01) UI Unknown 1 PrivateTag
+(7001,"Picker NM Private Group",02) OB Unknown 1 PrivateTag
+
+(0019,"SIEMENS CM VA0 ACQU",10) LT ParameterFileName 1 PrivateTag
+(0019,"SIEMENS CM VA0 ACQU",11) LO SequenceFileName 1 PrivateTag
+(0019,"SIEMENS CM VA0 ACQU",12) LT SequenceFileOwner 1 PrivateTag
+(0019,"SIEMENS CM VA0 ACQU",13) LT SequenceDescription 1 PrivateTag
+(0019,"SIEMENS CM VA0 ACQU",14) LT EPIFileName 1 PrivateTag
+
+(0009,"SIEMENS CM VA0 CMS",00) DS NumberOfMeasurements 1 PrivateTag
+(0009,"SIEMENS CM VA0 CMS",10) LT StorageMode 1 PrivateTag
+(0009,"SIEMENS CM VA0 CMS",12) UL EvaluationMaskImage 1 PrivateTag
+(0009,"SIEMENS CM VA0 CMS",26) DA LastMoveDate 1 PrivateTag
+(0009,"SIEMENS CM VA0 CMS",27) TM LastMoveTime 1 PrivateTag
+(0011,"SIEMENS CM VA0 CMS",0a) LT Unknown 1 PrivateTag
+(0011,"SIEMENS CM VA0 CMS",10) DA RegistrationDate 1 PrivateTag
+(0011,"SIEMENS CM VA0 CMS",11) TM RegistrationTime 1 PrivateTag
+(0011,"SIEMENS CM VA0 CMS",22) LT Unknown 1 PrivateTag
+(0011,"SIEMENS CM VA0 CMS",23) DS UsedPatientWeight 1 PrivateTag
+(0011,"SIEMENS CM VA0 CMS",40) IS OrganCode 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",00) LT ModifyingPhysician 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",10) DA ModificationDate 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",12) TM ModificationTime 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",20) LO PatientName 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",22) LO PatientId 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",30) DA PatientBirthdate 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",31) DS PatientWeight 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",32) LT PatientsMaidenName 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",33) LT ReferringPhysician 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",34) LT AdmittingDiagnosis 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",35) LO PatientSex 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",40) LO ProcedureDescription 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",42) LO RestDirection 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",44) LO PatientPosition 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",46) LT ViewDirection 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",50) LT Unknown 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",51) LT Unknown 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",52) LT Unknown 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",53) LT Unknown 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",54) LT Unknown 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",55) LT Unknown 1 PrivateTag
+(0013,"SIEMENS CM VA0 CMS",56) LT Unknown 1 PrivateTag
+(0019,"SIEMENS CM VA0 CMS",10) DS NetFrequency 1 PrivateTag
+(0019,"SIEMENS CM VA0 CMS",20) LT MeasurementMode 1 PrivateTag
+(0019,"SIEMENS CM VA0 CMS",30) LT CalculationMode 1 PrivateTag
+(0019,"SIEMENS CM VA0 CMS",50) IS NoiseLevel 1 PrivateTag
+(0019,"SIEMENS CM VA0 CMS",60) IS NumberOfDataBytes 1 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",20) DS FoV 2 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",22) DS ImageMagnificationFactor 1 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",24) DS ImageScrollOffset 2 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",26) IS ImagePixelOffset 1 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",30) LT ViewDirection 1 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",32) CS PatientRestDirection 1 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",60) DS ImagePosition 3 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",61) DS ImageNormal 3 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",63) DS ImageDistance 1 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",65) US ImagePositioningHistoryMask 1 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",6a) DS ImageRow 3 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",6b) DS ImageColumn 3 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",70) LT PatientOrientationSet1 3 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",71) LT PatientOrientationSet2 3 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",80) LT StudyName 1 PrivateTag
+(0021,"SIEMENS CM VA0 CMS",82) LT StudyType 3 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",10) LT WindowStyle 1 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",11) LT Unknown 1 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",13) LT Unknown 1 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",20) LT PixelQualityCode 3 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",22) IS PixelQualityValue 3 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",50) LT ArchiveCode 1 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",51) LT ExposureCode 1 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",52) LT SortCode 1 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",53) LT Unknown 1 PrivateTag
+(0029,"SIEMENS CM VA0 CMS",60) LT Splash 1 PrivateTag
+(0051,"SIEMENS CM VA0 CMS",10) LT ImageText 1-n PrivateTag
+(6021,"SIEMENS CM VA0 CMS",00) LT ImageGraphicsFormatCode 1 PrivateTag
+(6021,"SIEMENS CM VA0 CMS",10) LT ImageGraphics 1 PrivateTag
+(7fe1,"SIEMENS CM VA0 CMS",00) OB BinaryData 1-n PrivateTag
+
+(0009,"SIEMENS CM VA0 LAB",10) LT GeneratorIdentificationLabel 1 PrivateTag
+(0009,"SIEMENS CM VA0 LAB",11) LT GantryIdentificationLabel 1 PrivateTag
+(0009,"SIEMENS CM VA0 LAB",12) LT X-RayTubeIdentificationLabel 1 PrivateTag
+(0009,"SIEMENS CM VA0 LAB",13) LT DetectorIdentificationLabel 1 PrivateTag
+(0009,"SIEMENS CM VA0 LAB",14) LT DASIdentificationLabel 1 PrivateTag
+(0009,"SIEMENS CM VA0 LAB",15) LT SMIIdentificationLabel 1 PrivateTag
+(0009,"SIEMENS CM VA0 LAB",16) LT CPUIdentificationLabel 1 PrivateTag
+(0009,"SIEMENS CM VA0 LAB",20) LT HeaderVersion 1 PrivateTag
+
+(0029,"SIEMENS CSA HEADER",08) CS CSAImageHeaderType 1 PrivateTag
+(0029,"SIEMENS CSA HEADER",09) LO CSAImageHeaderVersion 1 PrivateTag
+(0029,"SIEMENS CSA HEADER",10) OB CSAImageHeaderInfo 1 PrivateTag
+(0029,"SIEMENS CSA HEADER",18) CS CSASeriesHeaderType 1 PrivateTag
+(0029,"SIEMENS CSA HEADER",19) LO CSASeriesHeaderVersion 1 PrivateTag
+(0029,"SIEMENS CSA HEADER",20) OB CSASeriesHeaderInfo 1 PrivateTag
+
+(0029,"SIEMENS CSA NON-IMAGE",08) CS CSADataType 1 PrivateTag
+(0029,"SIEMENS CSA NON-IMAGE",09) LO CSADataVersion 1 PrivateTag
+(0029,"SIEMENS CSA NON-IMAGE",10) OB CSADataInfo 1 PrivateTag
+(7FE1,"SIEMENS CSA NON-IMAGE",10) OB CSAData 1 PrivateTag
+
+(0019,"SIEMENS CT VA0 COAD",10) DS DistanceSourceToSourceSideCollimator 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",11) DS DistanceSourceToDetectorSideCollimator 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",20) IS NumberOfPossibleChannels 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",21) IS MeanChannelNumber 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",22) DS DetectorSpacing 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",23) DS DetectorCenter 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",24) DS ReadingIntegrationTime 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",50) DS DetectorAlignment 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",52) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",54) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",60) DS FocusAlignment 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",65) UL FocalSpotDeflectionAmplitude 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",66) UL FocalSpotDeflectionPhase 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",67) UL FocalSpotDeflectionOffset 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",70) DS WaterScalingFactor 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",71) DS InterpolationFactor 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",80) LT PatientRegion 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",82) LT PatientPhaseOfLife 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",90) DS OsteoOffset 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",92) DS OsteoRegressionLineSlope 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",93) DS OsteoRegressionLineIntercept 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",94) DS OsteoStandardizationCode 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",96) IS OsteoPhantomNumber 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",A3) US Unknown 1-n PrivateTag
+(0019,"SIEMENS CT VA0 COAD",A4) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",A5) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",A6) US Unknown 1-n PrivateTag
+(0019,"SIEMENS CT VA0 COAD",A7) US Unknown 1-n PrivateTag
+(0019,"SIEMENS CT VA0 COAD",A8) US Unknown 1-n PrivateTag
+(0019,"SIEMENS CT VA0 COAD",A9) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",AA) LT Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",AB) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",AC) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",AD) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",AE) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",AF) DS Unknown 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",B0) DS FeedPerRotation 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",BD) IS PulmoTriggerLevel 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",BE) DS ExpiratoricReserveVolume 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",BF) DS VitalCapacity 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",C0) DS PulmoWater 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",C1) DS PulmoAir 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",C2) DA PulmoDate 1 PrivateTag
+(0019,"SIEMENS CT VA0 COAD",C3) TM PulmoTime 1 PrivateTag
+
+(0019,"SIEMENS CT VA0 GEN",10) DS SourceSideCollimatorAperture 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",11) DS DetectorSideCollimatorAperture 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",20) DS ExposureTime 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",21) DS ExposureCurrent 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",25) DS KVPGeneratorPowerCurrent 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",26) DS GeneratorVoltage 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",40) UL MasterControlMask 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",42) US ProcessingMask 5 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",44) US Unknown 1-n PrivateTag
+(0019,"SIEMENS CT VA0 GEN",45) US Unknown 1-n PrivateTag
+(0019,"SIEMENS CT VA0 GEN",62) IS NumberOfVirtuellChannels 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",70) IS NumberOfReadings 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",71) LT Unknown 1-n PrivateTag
+(0019,"SIEMENS CT VA0 GEN",74) IS NumberOfProjections 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",75) IS NumberOfBytes 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",80) LT ReconstructionAlgorithmSet 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",81) LT ReconstructionAlgorithmIndex 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",82) LT RegenerationSoftwareVersion 1 PrivateTag
+(0019,"SIEMENS CT VA0 GEN",88) DS Unknown 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",10) IS RotationAngle 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",11) IS StartAngle 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",20) US Unknown 1-n PrivateTag
+(0021,"SIEMENS CT VA0 GEN",30) IS TopogramTubePosition 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",32) DS LengthOfTopogram 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",34) DS TopogramCorrectionFactor 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",36) DS MaximumTablePosition 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",40) IS TableMoveDirectionCode 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",45) IS VOIStartRow 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",46) IS VOIStopRow 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",47) IS VOIStartColumn 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",48) IS VOIStopColumn 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",49) IS VOIStartSlice 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",4a) IS VOIStopSlice 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",50) IS VectorStartRow 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",51) IS VectorRowStep 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",52) IS VectorStartColumn 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",53) IS VectorColumnStep 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",60) IS RangeTypeCode 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",62) IS ReferenceTypeCode 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",70) DS ObjectOrientation 3 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",72) DS LightOrientation 3 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",75) DS LightBrightness 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",76) DS LightContrast 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",7a) IS OverlayThreshold 2 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",7b) IS SurfaceThreshold 2 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",7c) IS GreyScaleThreshold 2 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",a0) DS Unknown 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",a2) LT Unknown 1 PrivateTag
+(0021,"SIEMENS CT VA0 GEN",a7) LT Unknown 1 PrivateTag
+
+(0009,"SIEMENS CT VA0 IDE",10) LT Unknown 1 PrivateTag
+(0009,"SIEMENS CT VA0 IDE",30) LT Unknown 1 PrivateTag
+(0009,"SIEMENS CT VA0 IDE",31) LT Unknown 1 PrivateTag
+(0009,"SIEMENS CT VA0 IDE",32) LT Unknown 1 PrivateTag
+(0009,"SIEMENS CT VA0 IDE",34) LT Unknown 1 PrivateTag
+(0009,"SIEMENS CT VA0 IDE",40) LT Unknown 1 PrivateTag
+(0009,"SIEMENS CT VA0 IDE",42) LT Unknown 1 PrivateTag
+(0009,"SIEMENS CT VA0 IDE",50) LT Unknown 1 PrivateTag
+(0009,"SIEMENS CT VA0 IDE",51) LT Unknown 1 PrivateTag
+
+(0009,"SIEMENS CT VA0 ORI",20) LT Unknown 1 PrivateTag
+(0009,"SIEMENS CT VA0 ORI",30) LT Unknown 1 PrivateTag
+
+(6021,"SIEMENS CT VA0 OST",00) LT OsteoContourComment 1 PrivateTag
+(6021,"SIEMENS CT VA0 OST",10) US OsteoContourBuffer 256 PrivateTag
+
+(0021,"SIEMENS CT VA0 RAW",10) UL CreationMask 2 PrivateTag
+(0021,"SIEMENS CT VA0 RAW",20) UL EvaluationMask 2 PrivateTag
+(0021,"SIEMENS CT VA0 RAW",30) US ExtendedProcessingMask 7 PrivateTag
+(0021,"SIEMENS CT VA0 RAW",40) US Unknown 1-n PrivateTag
+(0021,"SIEMENS CT VA0 RAW",41) US Unknown 1-n PrivateTag
+(0021,"SIEMENS CT VA0 RAW",42) US Unknown 1-n PrivateTag
+(0021,"SIEMENS CT VA0 RAW",43) US Unknown 1-n PrivateTag
+(0021,"SIEMENS CT VA0 RAW",44) US Unknown 1-n PrivateTag
+(0021,"SIEMENS CT VA0 RAW",50) LT Unknown 1 PrivateTag
+
+(0009,"SIEMENS DICOM",10) UN Unknown 1 PrivateTag
+(0009,"SIEMENS DICOM",12) LT Unknown 1 PrivateTag
+
+(0019,"SIEMENS DLR.01",10) LT MeasurementMode 1 PrivateTag
+(0019,"SIEMENS DLR.01",11) LT ImageType 1 PrivateTag
+(0019,"SIEMENS DLR.01",15) LT SoftwareVersion 1 PrivateTag
+(0019,"SIEMENS DLR.01",20) LT MPMCode 1 PrivateTag
+(0019,"SIEMENS DLR.01",21) LT Latitude 1 PrivateTag
+(0019,"SIEMENS DLR.01",22) LT Sensitivity 1 PrivateTag
+(0019,"SIEMENS DLR.01",23) LT EDR 1 PrivateTag
+(0019,"SIEMENS DLR.01",24) LT LFix 1 PrivateTag
+(0019,"SIEMENS DLR.01",25) LT SFix 1 PrivateTag
+(0019,"SIEMENS DLR.01",26) LT PresetMode 1 PrivateTag
+(0019,"SIEMENS DLR.01",27) LT Region 1 PrivateTag
+(0019,"SIEMENS DLR.01",28) LT Subregion 1 PrivateTag
+(0019,"SIEMENS DLR.01",30) LT Orientation 1 PrivateTag
+(0019,"SIEMENS DLR.01",31) LT MarkOnFilm 1 PrivateTag
+(0019,"SIEMENS DLR.01",32) LT RotationOnDRC 1 PrivateTag
+(0019,"SIEMENS DLR.01",40) LT ReaderType 1 PrivateTag
+(0019,"SIEMENS DLR.01",41) LT SubModality 1 PrivateTag
+(0019,"SIEMENS DLR.01",42) LT ReaderSerialNumber 1 PrivateTag
+(0019,"SIEMENS DLR.01",50) LT CassetteScale 1 PrivateTag
+(0019,"SIEMENS DLR.01",51) LT CassetteMatrix 1 PrivateTag
+(0019,"SIEMENS DLR.01",52) LT CassetteSubmatrix 1 PrivateTag
+(0019,"SIEMENS DLR.01",53) LT Barcode 1 PrivateTag
+(0019,"SIEMENS DLR.01",60) LT ContrastType 1 PrivateTag
+(0019,"SIEMENS DLR.01",61) LT RotationAmount 1 PrivateTag
+(0019,"SIEMENS DLR.01",62) LT RotationCenter 1 PrivateTag
+(0019,"SIEMENS DLR.01",63) LT DensityShift 1 PrivateTag
+(0019,"SIEMENS DLR.01",64) US FrequencyRank 1 PrivateTag
+(0019,"SIEMENS DLR.01",65) LT FrequencyEnhancement 1 PrivateTag
+(0019,"SIEMENS DLR.01",66) LT FrequencyType 1 PrivateTag
+(0019,"SIEMENS DLR.01",67) LT KernelLength 1 PrivateTag
+(0019,"SIEMENS DLR.01",68) UL KernelMode 1 PrivateTag
+(0019,"SIEMENS DLR.01",69) UL ConvolutionMode 1 PrivateTag
+(0019,"SIEMENS DLR.01",70) LT PLASource 1 PrivateTag
+(0019,"SIEMENS DLR.01",71) LT PLADestination 1 PrivateTag
+(0019,"SIEMENS DLR.01",75) LT UIDOriginalImage 1 PrivateTag
+(0019,"SIEMENS DLR.01",76) LT Unknown 1 PrivateTag
+(0019,"SIEMENS DLR.01",80) LT ReaderHeader 1 PrivateTag
+(0019,"SIEMENS DLR.01",90) LT PLAOfSecondaryDestination 1 PrivateTag
+(0019,"SIEMENS DLR.01",a0) DS Unknown 1 PrivateTag
+(0019,"SIEMENS DLR.01",a1) DS Unknown 1 PrivateTag
+(0041,"SIEMENS DLR.01",10) US NumberOfHardcopies 1 PrivateTag
+(0041,"SIEMENS DLR.01",20) LT FilmFormat 1 PrivateTag
+(0041,"SIEMENS DLR.01",30) LT FilmSize 1 PrivateTag
+(0041,"SIEMENS DLR.01",31) LT FullFilmFormat 1 PrivateTag
+
+(0003,"SIEMENS ISI",08) US ISICommandField 1 PrivateTag
+(0003,"SIEMENS ISI",11) US AttachIDApplicationCode 1 PrivateTag
+(0003,"SIEMENS ISI",12) UL AttachIDMessageCount 1 PrivateTag
+(0003,"SIEMENS ISI",13) DA AttachIDDate 1 PrivateTag
+(0003,"SIEMENS ISI",14) TM AttachIDTime 1 PrivateTag
+(0003,"SIEMENS ISI",20) US MessageType 1 PrivateTag
+(0003,"SIEMENS ISI",30) DA MaxWaitingDate 1 PrivateTag
+(0003,"SIEMENS ISI",31) TM MaxWaitingTime 1 PrivateTag
+(0009,"SIEMENS ISI",01) UN RISPatientInfoIMGEF 1 PrivateTag
+(0011,"SIEMENS ISI",03) LT PatientUID 1 PrivateTag
+(0011,"SIEMENS ISI",04) LT PatientID 1 PrivateTag
+(0011,"SIEMENS ISI",0a) LT CaseID 1 PrivateTag
+(0011,"SIEMENS ISI",22) LT RequestID 1 PrivateTag
+(0011,"SIEMENS ISI",23) LT ExaminationUID 1 PrivateTag
+(0011,"SIEMENS ISI",a1) DA PatientRegistrationDate 1 PrivateTag
+(0011,"SIEMENS ISI",a2) TM PatientRegistrationTime 1 PrivateTag
+(0011,"SIEMENS ISI",b0) LT PatientLastName 1 PrivateTag
+(0011,"SIEMENS ISI",b2) LT PatientFirstName 1 PrivateTag
+(0011,"SIEMENS ISI",b4) LT PatientHospitalStatus 1 PrivateTag
+(0011,"SIEMENS ISI",bc) TM CurrentLocationTime 1 PrivateTag
+(0011,"SIEMENS ISI",c0) LT PatientInsuranceStatus 1 PrivateTag
+(0011,"SIEMENS ISI",d0) LT PatientBillingType 1 PrivateTag
+(0011,"SIEMENS ISI",d2) LT PatientBillingAddress 1 PrivateTag
+(0031,"SIEMENS ISI",12) LT ExaminationReason 1 PrivateTag
+(0031,"SIEMENS ISI",30) DA RequestedDate 1 PrivateTag
+(0031,"SIEMENS ISI",32) TM WorklistRequestStartTime 1 PrivateTag
+(0031,"SIEMENS ISI",33) TM WorklistRequestEndTime 1 PrivateTag
+(0031,"SIEMENS ISI",4a) TM RequestedTime 1 PrivateTag
+(0031,"SIEMENS ISI",80) LT RequestedLocation 1 PrivateTag
+(0055,"SIEMENS ISI",46) LT CurrentWard 1 PrivateTag
+(0193,"SIEMENS ISI",02) DS RISKey 1 PrivateTag
+(0307,"SIEMENS ISI",01) UN RISWorklistIMGEF 1 PrivateTag
+(0309,"SIEMENS ISI",01) UN RISReportIMGEF 1 PrivateTag
+(4009,"SIEMENS ISI",01) LT ReportID 1 PrivateTag
+(4009,"SIEMENS ISI",20) LT ReportStatus 1 PrivateTag
+(4009,"SIEMENS ISI",30) DA ReportCreationDate 1 PrivateTag
+(4009,"SIEMENS ISI",70) LT ReportApprovingPhysician 1 PrivateTag
+(4009,"SIEMENS ISI",e0) LT ReportText 1 PrivateTag
+(4009,"SIEMENS ISI",e1) LT ReportAuthor 1 PrivateTag
+(4009,"SIEMENS ISI",e3) LT ReportingRadiologist 1 PrivateTag
+
+(0029,"SIEMENS MED DISPLAY",04) LT PhotometricInterpretation 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",10) US RowsOfSubmatrix 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",11) US ColumnsOfSubmatrix 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",20) US Unknown 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",21) US Unknown 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",50) US OriginOfSubmatrix 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",99) LT ShutterType 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",a0) US RowsOfRectangularShutter 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",a1) US ColumnsOfRectangularShutter 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",a2) US OriginOfRectangularShutter 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",b0) US RadiusOfCircularShutter 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",b2) US OriginOfCircularShutter 1 PrivateTag
+(0029,"SIEMENS MED DISPLAY",c1) US ContourOfIrregularShutter 1 PrivateTag
+
+(0029,"SIEMENS MED HG",10) US ListOfGroupNumbers 1 PrivateTag
+(0029,"SIEMENS MED HG",15) LT ListOfShadowOwnerCodes 1 PrivateTag
+(0029,"SIEMENS MED HG",20) US ListOfElementNumbers 1 PrivateTag
+(0029,"SIEMENS MED HG",30) US ListOfTotalDisplayLength 1 PrivateTag
+(0029,"SIEMENS MED HG",40) LT ListOfDisplayPrefix 1 PrivateTag
+(0029,"SIEMENS MED HG",50) LT ListOfDisplayPostfix 1 PrivateTag
+(0029,"SIEMENS MED HG",60) US ListOfTextPosition 1 PrivateTag
+(0029,"SIEMENS MED HG",70) LT ListOfTextConcatenation 1 PrivateTag
+(0029,"SIEMENS MED MG",10) US ListOfGroupNumbers 1 PrivateTag
+(0029,"SIEMENS MED MG",15) LT ListOfShadowOwnerCodes 1 PrivateTag
+(0029,"SIEMENS MED MG",20) US ListOfElementNumbers 1 PrivateTag
+(0029,"SIEMENS MED MG",30) US ListOfTotalDisplayLength 1 PrivateTag
+(0029,"SIEMENS MED MG",40) LT ListOfDisplayPrefix 1 PrivateTag
+(0029,"SIEMENS MED MG",50) LT ListOfDisplayPostfix 1 PrivateTag
+(0029,"SIEMENS MED MG",60) US ListOfTextPosition 1 PrivateTag
+(0029,"SIEMENS MED MG",70) LT ListOfTextConcatenation 1 PrivateTag
+
+(0009,"SIEMENS MED",10) LO RecognitionCode 1 PrivateTag
+(0009,"SIEMENS MED",30) UL ByteOffsetOfOriginalHeader 1 PrivateTag
+(0009,"SIEMENS MED",31) UL LengthOfOriginalHeader 1 PrivateTag
+(0009,"SIEMENS MED",40) UL ByteOffsetOfPixelmatrix 1 PrivateTag
+(0009,"SIEMENS MED",41) UL LengthOfPixelmatrixInBytes 1 PrivateTag
+(0009,"SIEMENS MED",50) LT Unknown 1 PrivateTag
+(0009,"SIEMENS MED",51) LT Unknown 1 PrivateTag
+(0009,"SIEMENS MED",f5) LT PDMEFIDPlaceholder 1 PrivateTag
+(0009,"SIEMENS MED",f6) LT PDMDataObjectTypeExtension 1 PrivateTag
+(0021,"SIEMENS MED",10) DS Zoom 1 PrivateTag
+(0021,"SIEMENS MED",11) DS Target 2 PrivateTag
+(0021,"SIEMENS MED",12) IS TubeAngle 1 PrivateTag
+(0021,"SIEMENS MED",20) US ROIMask 1 PrivateTag
+(7001,"SIEMENS MED",10) LT Dummy 1 PrivateTag
+(7003,"SIEMENS MED",10) LT Header 1 PrivateTag
+(7005,"SIEMENS MED",10) LT Dummy 1 PrivateTag
+
+(0029,"SIEMENS MEDCOM HEADER",08) CS MedComHeaderType 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",09) LO MedComHeaderVersion 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",10) OB MedComHeaderInfo 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",20) OB MedComHistoryInformation 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",31) LO PMTFInformation1 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",32) UL PMTFInformation2 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",33) UL PMTFInformation3 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",34) CS PMTFInformation4 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",35) UL PMTFInformation5 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",40) SQ ApplicationHeaderSequence 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",41) CS ApplicationHeaderType 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",42) LO ApplicationHeaderID 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",43) LO ApplicationHeaderVersion 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",44) OB ApplicationHeaderInfo 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",50) LO WorkflowControlFlags 8 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",51) CS ArchiveManagementFlagKeepOnline 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",52) CS ArchiveManagementFlagDoNotArchive 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",53) CS ImageLocationStatus 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",54) DS EstimatedRetrieveTime 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",55) DS DataSizeOfRetrievedImages 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",70) SQ SiemensLinkSequence 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",71) AT ReferencedTag 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",72) CS ReferencedTagType 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",73) UL ReferencedValueLength 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",74) CS ReferencedObjectDeviceType 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",75) OB ReferencedObjectDeviceLocation 1 PrivateTag
+(0029,"SIEMENS MEDCOM HEADER",76) OB ReferencedObjectDeviceID 1 PrivateTag
+
+(0029,"SIEMENS MEDCOM HEADER2",60) LO SeriesWorkflowStatus 1 PrivateTag
+
+(0029,"SIEMENS MEDCOM OOG",08) CS MEDCOMOOGType 1 PrivateTag
+(0029,"SIEMENS MEDCOM OOG",09) LO MEDCOMOOGVersion 1 PrivateTag
+(0029,"SIEMENS MEDCOM OOG",10) OB MEDCOMOOGInfo 1 PrivateTag
+
+(0019,"SIEMENS MR VA0 COAD",12) DS MagneticFieldStrength 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",14) DS ADCVoltage 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",16) DS ADCOffset 2 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",20) DS TransmitterAmplitude 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",21) IS NumberOfTransmitterAmplitudes 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",22) DS TransmitterAttenuator 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",24) DS TransmitterCalibration 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",26) DS TransmitterReference 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",50) DS ReceiverTotalGain 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",51) DS ReceiverAmplifierGain 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",52) DS ReceiverPreamplifierGain 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",54) DS ReceiverCableAttenuation 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",55) DS ReceiverReferenceGain 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",56) DS ReceiverFilterFrequency 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",60) DS ReconstructionScaleFactor 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",62) DS ReferenceScaleFactor 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",70) DS PhaseGradientAmplitude 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",71) DS ReadoutGradientAmplitude 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",72) DS SelectionGradientAmplitude 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",80) DS GradientDelayTime 3 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",82) DS TotalGradientDelayTime 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",90) LT SensitivityCorrectionLabel 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",91) DS SaturationPhaseEncodingVectorCoronalComponent 6 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",92) DS SaturationReadoutVectorCoronalComponent 6 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",a0) US RFWatchdogMask 3 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",a1) DS EPIReconstructionSlope 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",a2) DS RFPowerErrorIndicator 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",a5) DS SpecificAbsorptionRateWholeBody 3 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",a6) DS SpecificEnergyDose 3 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",b0) UL AdjustmentStatusMask 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",c1) DS EPICapacity 6 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",c2) DS EPIInductance 3 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",c3) IS EPISwitchConfigurationCode 1-n PrivateTag
+(0019,"SIEMENS MR VA0 COAD",c4) IS EPISwitchHardwareCode 1-n PrivateTag
+(0019,"SIEMENS MR VA0 COAD",c5) DS EPISwitchDelayTime 1-n PrivateTag
+(0019,"SIEMENS MR VA0 COAD",d1) DS FlowSensitivity 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",d2) LT CalculationSubmode 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",d3) DS FieldOfViewRatio 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",d4) IS BaseRawMatrixSize 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",d5) IS 2DOversamplingLines 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",d6) IS 3DPhaseOversamplingPartitions 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",d7) IS EchoLinePosition 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",d8) IS EchoColumnPosition 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",d9) IS LinesPerSegment 1 PrivateTag
+(0019,"SIEMENS MR VA0 COAD",da) LT PhaseCodingDirection 1 PrivateTag
+
+(0019,"SIEMENS MR VA0 GEN",10) DS TotalMeasurementTimeNominal 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",11) DS TotalMeasurementTimeCurrent 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",12) DS StartDelayTime 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",13) DS DwellTime 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",14) IS NumberOfPhases 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",16) UL SequenceControlMask 2 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",18) UL MeasurementStatusMask 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",20) IS NumberOfFourierLinesNominal 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",21) IS NumberOfFourierLinesCurrent 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",26) IS NumberOfFourierLinesAfterZero 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",28) IS FirstMeasuredFourierLine 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",30) IS AcquisitionColumns 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",31) IS ReconstructionColumns 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",40) IS ArrayCoilElementNumber 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",41) UL ArrayCoilElementSelectMask 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",42) UL ArrayCoilElementDataMask 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",43) IS ArrayCoilElementToADCConnect 1-n PrivateTag
+(0019,"SIEMENS MR VA0 GEN",44) DS ArrayCoilElementNoiseLevel 1-n PrivateTag
+(0019,"SIEMENS MR VA0 GEN",45) IS ArrayCoilADCPairNumber 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",46) UL ArrayCoilCombinationMask 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",50) IS NumberOfAverages 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",60) DS FlipAngle 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",70) IS NumberOfPrescans 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",81) LT FilterTypeForRawData 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",82) DS FilterParameterForRawData 1-n PrivateTag
+(0019,"SIEMENS MR VA0 GEN",83) LT FilterTypeForImageData 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",84) DS FilterParameterForImageData 1-n PrivateTag
+(0019,"SIEMENS MR VA0 GEN",85) LT FilterTypeForPhaseCorrection 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",86) DS FilterParameterForPhaseCorrection 1-n PrivateTag
+(0019,"SIEMENS MR VA0 GEN",87) LT NormalizationFilterTypeForImageData 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",88) DS NormalizationFilterParameterForImageData 1-n PrivateTag
+(0019,"SIEMENS MR VA0 GEN",90) IS NumberOfSaturationRegions 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",91) DS SaturationPhaseEncodingVectorSagittalComponent 6 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",92) DS SaturationReadoutVectorSagittalComponent 6 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",93) DS EPIStimulationMonitorMode 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",94) DS ImageRotationAngle 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",96) UL CoilIDMask 3 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",97) UL CoilClassMask 2 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",98) DS CoilPosition 3 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",a0) DS EPIReconstructionPhase 1 PrivateTag
+(0019,"SIEMENS MR VA0 GEN",a1) DS EPIReconstructionSlope 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",20) IS PhaseCorrectionRowsSequence 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",21) IS PhaseCorrectionColumnsSequence 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",22) IS PhaseCorrectionRowsReconstruction 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",24) IS PhaseCorrectionColumnsReconstruction 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",30) IS NumberOf3DRawPartitionsNominal 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",31) IS NumberOf3DRawPartitionsCurrent 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",34) IS NumberOf3DImagePartitions 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",36) IS Actual3DImagePartitionNumber 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",39) DS SlabThickness 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",40) IS NumberOfSlicesNominal 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",41) IS NumberOfSlicesCurrent 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",42) IS CurrentSliceNumber 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",43) IS CurrentGroupNumber 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",44) DS CurrentSliceDistanceFactor 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",45) IS MIPStartRow 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",46) IS MIPStopRow 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",47) IS MIPStartColumn 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",48) IS MIPStartColumn 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",49) IS MIPStartSlice Name= 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",4a) IS MIPStartSlice 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",4f) LT OrderofSlices 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",50) US SignalMask 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",52) DS DelayAfterTrigger 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",53) IS RRInterval 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",54) DS NumberOfTriggerPulses 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",56) DS RepetitionTimeEffective 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",57) LT GatePhase 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",58) DS GateThreshold 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",59) DS GatedRatio 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",60) IS NumberOfInterpolatedImages 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",70) IS NumberOfEchoes 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",72) DS SecondEchoTime 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",73) DS SecondRepetitionTime 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",80) IS CardiacCode 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",91) DS SaturationPhaseEncodingVectorTransverseComponent 6 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",92) DS SaturationReadoutVectorTransverseComponent 6 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",93) DS EPIChangeValueOfMagnitude 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",94) DS EPIChangeValueOfXComponent 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",95) DS EPIChangeValueOfYComponent 1 PrivateTag
+(0021,"SIEMENS MR VA0 GEN",96) DS EPIChangeValueOfZComponent 1 PrivateTag
+
+(0021,"SIEMENS MR VA0 RAW",00) LT SequenceType 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",01) IS VectorSizeOriginal 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",02) IS VectorSizeExtended 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",03) DS AcquiredSpectralRange 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",04) DS VOIPosition 3 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",05) DS VOISize 3 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",06) IS CSIMatrixSizeOriginal 3 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",07) IS CSIMatrixSizeExtended 3 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",08) DS SpatialGridShift 3 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",09) DS SignalLimitsMinimum 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",10) DS SignalLimitsMaximum 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",11) DS SpecInfoMask 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",12) DS EPITimeRateOfChangeOfMagnitude 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",13) DS EPITimeRateOfChangeOfXComponent 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",14) DS EPITimeRateOfChangeOfYComponent 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",15) DS EPITimeRateOfChangeOfZComponent 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",16) DS EPITimeRateOfChangeLegalLimit1 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",17) DS EPIOperationModeFlag 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",18) DS EPIFieldCalculationSafetyFactor 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",19) DS EPILegalLimit1OfChangeValue 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",20) DS EPILegalLimit2OfChangeValue 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",21) DS EPIRiseTime 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",30) DS ArrayCoilADCOffset 16 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",31) DS ArrayCoilPreamplifierGain 16 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",50) LT SaturationType 1 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",51) DS SaturationNormalVector 3 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",52) DS SaturationPositionVector 3 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",53) DS SaturationThickness 6 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",54) DS SaturationWidth 6 PrivateTag
+(0021,"SIEMENS MR VA0 RAW",55) DS SaturationDistance 6 PrivateTag
+
+(7fe3,"SIEMENS NUMARIS II",00) LT ImageGraphicsFormatCode 1 PrivateTag
+(7fe3,"SIEMENS NUMARIS II",10) OB ImageGraphics 1 PrivateTag
+(7fe3,"SIEMENS NUMARIS II",20) OB ImageGraphicsDummy 1 PrivateTag
+
+(0011,"SIEMENS RA GEN",20) SL FluoroTimer 1 PrivateTag
+(0011,"SIEMENS RA GEN",25) SL PtopDoseAreaProduct 1 PrivateTag
+(0011,"SIEMENS RA GEN",26) SL PtopTotalSkinDose 1 PrivateTag
+(0011,"SIEMENS RA GEN",30) LT Unknown 1 PrivateTag
+(0011,"SIEMENS RA GEN",35) LO PatientInitialPuckCounter 1 PrivateTag
+(0011,"SIEMENS RA GEN",40) SS SPIDataObjectType 1 PrivateTag
+(0019,"SIEMENS RA GEN",15) LO AcquiredPlane 1 PrivateTag
+(0019,"SIEMENS RA GEN",1f) SS DefaultTableIsoCenterHeight 1 PrivateTag
+(0019,"SIEMENS RA GEN",20) SL SceneFlag 1 PrivateTag
+(0019,"SIEMENS RA GEN",22) SL RefPhotofileFlag 1 PrivateTag
+(0019,"SIEMENS RA GEN",24) LO SceneName 1 PrivateTag
+(0019,"SIEMENS RA GEN",26) SS AcquisitionIndex 1 PrivateTag
+(0019,"SIEMENS RA GEN",28) SS MixedPulseMode 1 PrivateTag
+(0019,"SIEMENS RA GEN",2a) SS NoOfPositions 1 PrivateTag
+(0019,"SIEMENS RA GEN",2c) SS NoOfPhases 1 PrivateTag
+(0019,"SIEMENS RA GEN",2e) SS FrameRateForPositions 1-n PrivateTag
+(0019,"SIEMENS RA GEN",30) SS NoOfFramesForPositions 1-n PrivateTag
+(0019,"SIEMENS RA GEN",32) SS SteppingDirection 1 PrivateTag
+(0019,"SIEMENS RA GEN",34) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",36) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",38) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",3a) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",3c) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",3e) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",40) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",42) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",44) SS ImageTransferDelay 1 PrivateTag
+(0019,"SIEMENS RA GEN",46) SL InversFlag 1 PrivateTag
+(0019,"SIEMENS RA GEN",48) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",4a) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",4c) SS BlankingCircleDiameter 1 PrivateTag
+(0019,"SIEMENS RA GEN",50) SL StandDataValid 1 PrivateTag
+(0019,"SIEMENS RA GEN",52) SS TableTilt 1 PrivateTag
+(0019,"SIEMENS RA GEN",54) SS TableAxisRotation 1 PrivateTag
+(0019,"SIEMENS RA GEN",56) SS TableLongitudalPosition 1 PrivateTag
+(0019,"SIEMENS RA GEN",58) SS TableSideOffset 1 PrivateTag
+(0019,"SIEMENS RA GEN",5a) SS TableIsoCenterHeight 1 PrivateTag
+(0019,"SIEMENS RA GEN",5c) UN Unknown 1 PrivateTag
+(0019,"SIEMENS RA GEN",5e) SL CollimationDataValid 1 PrivateTag
+(0019,"SIEMENS RA GEN",60) SL PeriSequenceNo 1 PrivateTag
+(0019,"SIEMENS RA GEN",62) SL PeriTotalScenes 1 PrivateTag
+(0019,"SIEMENS RA GEN",64) SL PeriOverlapTop 1 PrivateTag
+(0019,"SIEMENS RA GEN",66) SL PeriOverlapBottom 1 PrivateTag
+(0019,"SIEMENS RA GEN",68) SL RawImageNumber 1 PrivateTag
+(0019,"SIEMENS RA GEN",6a) SL XRayDataValid 1 PrivateTag
+(0019,"SIEMENS RA GEN",70) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",72) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",74) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",76) SL FillingAverageFactor 1 PrivateTag
+(0019,"SIEMENS RA GEN",78) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",7a) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",7c) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",7e) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",80) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",82) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",84) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",86) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",88) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",8a) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",8c) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",8e) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",92) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",94) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",96) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",98) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",9a) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA GEN",9c) SL IntensifierLevelCalibrationFactor 1 PrivateTag
+(0019,"SIEMENS RA GEN",9e) SL NativeReviewFlag 1 PrivateTag
+(0019,"SIEMENS RA GEN",a2) SL SceneNumber 1 PrivateTag
+(0019,"SIEMENS RA GEN",a4) SS AcquisitionMode 1 PrivateTag
+(0019,"SIEMENS RA GEN",a5) SS AcquisitonFrameRate 1 PrivateTag
+(0019,"SIEMENS RA GEN",a6) SL ECGFlag 1 PrivateTag
+(0019,"SIEMENS RA GEN",a7) SL AdditionalSceneData 1 PrivateTag
+(0019,"SIEMENS RA GEN",a8) SL FileCopyFlag 1 PrivateTag
+(0019,"SIEMENS RA GEN",a9) SL PhlebovisionFlag 1 PrivateTag
+(0019,"SIEMENS RA GEN",aa) SL Co2Flag 1 PrivateTag
+(0019,"SIEMENS RA GEN",ab) SS MaxSpeed 1 PrivateTag
+(0019,"SIEMENS RA GEN",ac) SS StepWidth 1 PrivateTag
+(0019,"SIEMENS RA GEN",ad) SL DigitalAcquisitionZoom 1 PrivateTag
+(0019,"SIEMENS RA GEN",ff) SS Internal 1-n PrivateTag
+(0021,"SIEMENS RA GEN",15) SS ImagesInStudy 1 PrivateTag
+(0021,"SIEMENS RA GEN",20) SS ScenesInStudy 1 PrivateTag
+(0021,"SIEMENS RA GEN",25) SS ImagesInPhotofile 1 PrivateTag
+(0021,"SIEMENS RA GEN",27) SS PlaneBImagesExist 1 PrivateTag
+(0021,"SIEMENS RA GEN",28) SS NoOf2MBChunks 1 PrivateTag
+(0021,"SIEMENS RA GEN",30) SS ImagesInAllScenes 1 PrivateTag
+(0021,"SIEMENS RA GEN",40) SS ArchiveSWInternalVersion 1 PrivateTag
+
+(0011,"SIEMENS RA PLANE A",28) SL FluoroTimerA 1 PrivateTag
+(0011,"SIEMENS RA PLANE A",29) SL FluoroSkinDoseA 1 PrivateTag
+(0011,"SIEMENS RA PLANE A",2a) SL TotalSkinDoseA 1 PrivateTag
+(0011,"SIEMENS RA PLANE A",2b) SL FluoroDoseAreaProductA 1 PrivateTag
+(0011,"SIEMENS RA PLANE A",2c) SL TotalDoseAreaProductA 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",15) LT OfflineUID 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",18) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",19) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",1a) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",1b) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",1c) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",1d) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",1e) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",1f) SS Internal 1-n PrivateTag
+(0019,"SIEMENS RA PLANE A",20) SS SystemCalibFactorPlaneA 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",22) SS XRayParameterSetNo 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",24) SS XRaySystem 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",26) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",28) SS AcquiredDisplayMode 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",2a) SS AcquisitionDelay 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",2c) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",2e) SS MaxFramesLimit 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",30) US MaximumFrameSizeNIU 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",32) SS SubtractedFilterType 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",34) SS FilterFactorNative 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",36) SS AnatomicBackgroundFactor 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",38) SS WindowUpperLimitNative 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",3a) SS WindowLowerLimitNative 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",3c) SS WindowBrightnessPhase1 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",3e) SS WindowBrightnessPhase2 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",40) SS WindowContrastPhase1 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",42) SS WindowContrastPhase2 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",44) SS FilterFactorSub 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",46) SS PeakOpacified 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",48) SL MaskFrame 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",4a) SL BIHFrame 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",4c) SS CentBeamAngulationCaudCran 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",4e) SS CentBeamAngulationLRAnterior 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",50) SS LongitudinalPosition 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",52) SS SideOffset 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",54) SS IsoCenterHeight 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",56) SS ImageTwist 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",58) SS SourceImageDistance 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",5a) SS MechanicalMagnificationFactor 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",5c) SL CalibrationFlag 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",5e) SL CalibrationAngleCranCaud 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",60) SL CalibrationAngleRAOLAO 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",62) SL CalibrationTableToFloorDist 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",64) SL CalibrationIsocenterToFloorDist 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",66) SL CalibrationIsocenterToSourceDist 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",68) SL CalibrationSourceToII 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",6a) SL CalibrationIIZoom 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",6c) SL CalibrationIIField 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",6e) SL CalibrationFactor 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",70) SL CalibrationObjectToImageDistance 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",72) SL CalibrationSystemFactor 1-n PrivateTag
+(0019,"SIEMENS RA PLANE A",74) SL CalibrationSystemCorrection 1-n PrivateTag
+(0019,"SIEMENS RA PLANE A",76) SL CalibrationSystemIIFormats 1-n PrivateTag
+(0019,"SIEMENS RA PLANE A",78) SL CalibrationGantryDataValid 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",7a) SS CollimatorSquareBreadth 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",7c) SS CollimatorSquareHeight 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",7e) SS CollimatorSquareDiameter 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",80) SS CollimaterFingerTurnAngle 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",82) SS CollimaterFingerPosition 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",84) SS CollimaterDiaphragmTurnAngle 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",86) SS CollimaterDiaphragmPosition1 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",88) SS CollimaterDiaphragmPosition2 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",8a) SS CollimaterDiaphragmMode 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",8c) SS CollimaterBeamLimitBreadth 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",8e) SS CollimaterBeamLimitHeight 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",90) SS CollimaterBeamLimitDiameter 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",92) SS X-RayControlMOde 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",94) SS X-RaySystem 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",96) SS FocalSpot 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",98) SS ExposureControl 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",9a) SL XRayVoltage 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",9c) SL XRayCurrent 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",9e) SL XRayCurrentTimeProduct 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",a0) SL XRayPulseTime 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",a2) SL XRaySceneTimeFluoroClock 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",a4) SS MaximumPulseRate 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",a6) SS PulsesPerScene 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",a8) SL DoseAreaProductOfScene 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",aa) SS Dose 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",ac) SS DoseRate 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",ae) SL IIToCoverDistance 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b0) SS LastFramePhase1 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b1) SS FrameRatePhase1 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b2) SS LastFramePhase2 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b3) SS FrameRatePhase2 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b4) SS LastFramePhase3 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b5) SS FrameRatePhase3 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b6) SS LastFramePhase4 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b7) SS FrameRatePhase4 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b8) SS GammaOfNativeImage 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",b9) SS GammaOfTVSystem 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",bb) SL PixelshiftX 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",bc) SL PixelshiftY 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",bd) SL MaskAverageFactor 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",be) SL BlankingCircleFlag 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",bf) SL CircleRowStart 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c0) SL CircleRowEnd 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c1) SL CircleColumnStart 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c2) SL CircleColumnEnd 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c3) SL CircleDiameter 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c4) SL RectangularCollimaterFlag 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c5) SL RectangleRowStart 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c6) SL RectangleRowEnd 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c7) SL RectangleColumnStart 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c8) SL RectangleColumnEnd 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",c9) SL RectangleAngulation 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",ca) SL IrisCollimatorFlag 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",cb) SL IrisRowStart 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",cc) SL IrisRowEnd 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",cd) SL IrisColumnStart 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",ce) SL IrisColumnEnd 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",cf) SL IrisAngulation 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",d1) SS NumberOfFramesPlane 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",d2) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",d3) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",d4) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",d5) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",d6) SS Internal 1-n PrivateTag
+(0019,"SIEMENS RA PLANE A",d7) SS Internal 1-n PrivateTag
+(0019,"SIEMENS RA PLANE A",d8) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",d9) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",da) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",db) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",dc) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",dd) SL AnatomicBackground 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",de) SL AutoWindowBase 1-n PrivateTag
+(0019,"SIEMENS RA PLANE A",df) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE A",e0) SL Internal 1 PrivateTag
+
+(0011,"SIEMENS RA PLANE B",28) SL FluoroTimerB 1 PrivateTag
+(0011,"SIEMENS RA PLANE B",29) SL FluoroSkinDoseB 1 PrivateTag
+(0011,"SIEMENS RA PLANE B",2a) SL TotalSkinDoseB 1 PrivateTag
+(0011,"SIEMENS RA PLANE B",2b) SL FluoroDoseAreaProductB 1 PrivateTag
+(0011,"SIEMENS RA PLANE B",2c) SL TotalDoseAreaProductB 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",18) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",19) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",1a) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",1b) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",1c) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",1d) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",1e) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",1f) SS Internal 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",20) SL SystemCalibFactorPlaneB 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",22) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",24) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",26) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",28) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",2a) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",2c) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",2e) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",30) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",32) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",34) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",36) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",38) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",3a) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",3c) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",3e) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",40) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",42) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",44) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",46) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",48) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",4a) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",4c) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",4e) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",50) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",52) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",54) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",56) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",58) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",5a) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",5c) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",5e) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",60) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",62) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",64) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",66) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",68) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",6a) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",6c) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",6e) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",70) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",72) UN Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",74) UN Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",76) UN Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",78) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",7a) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",7c) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",7e) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",80) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",82) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",84) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",86) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",88) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",8a) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",8c) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",8e) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",90) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",92) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",94) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",96) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",98) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",9a) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",9c) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",9e) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",a0) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",a2) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",a4) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",a6) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",a8) US Unknown 1-n PrivateTag
+(0019,"SIEMENS RA PLANE B",aa) US Unknown 1 PrivateTag
+(0019,"SIEMENS RA PLANE B",ac) US Unknown 1 PrivateTag
+
+(0011,"SIEMENS RIS",10) LT PatientUID 1 PrivateTag
+(0011,"SIEMENS RIS",11) LT PatientID 1 PrivateTag
+(0011,"SIEMENS RIS",20) DA PatientRegistrationDate 1 PrivateTag
+(0011,"SIEMENS RIS",21) TM PatientRegistrationTime 1 PrivateTag
+(0011,"SIEMENS RIS",30) LT PatientnameRIS 1 PrivateTag
+(0011,"SIEMENS RIS",31) LT PatientprenameRIS 1 PrivateTag
+(0011,"SIEMENS RIS",40) LT PatientHospitalStatus 1 PrivateTag
+(0011,"SIEMENS RIS",41) LT MedicalAlerts 1 PrivateTag
+(0011,"SIEMENS RIS",42) LT ContrastAllergies 1 PrivateTag
+(0031,"SIEMENS RIS",10) LT RequestUID 1 PrivateTag
+(0031,"SIEMENS RIS",45) LT RequestingPhysician 1 PrivateTag
+(0031,"SIEMENS RIS",50) LT RequestedPhysician 1 PrivateTag
+(0033,"SIEMENS RIS",10) LT PatientStudyUID 1 PrivateTag
+
+(0021,"SIEMENS SMS-AX ACQ 1.0",00) US AcquisitionType 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",01) US AcquisitionMode 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",02) US FootswitchIndex 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",03) US AcquisitionRoom 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",04) SL CurrentTimeProduct 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",05) SL Dose 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",06) SL SkinDosePercent 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",07) SL SkinDoseAccumulation 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",08) SL SkinDoseRate 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",0A) UL CopperFilter 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",0B) US MeasuringField 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",0C) SS PostBlankingCircle 3 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",0D) SS DynaAngles 2-2n PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",0E) SS TotalSteps 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",0F) SL DynaXRayInfo 3-3n PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",10) US ModalityLUTInputGamma 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",11) US ModalityLUTOutputGamma 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",12) OB SH_STPAR 1-n PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",13) US AcquisitionZoom 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",14) SS DynaAngulationStepWidth 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",15) US Harmonization 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",16) US DRSingleFlag 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",17) SL SourceToIsocenter 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",18) US PressureData 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",19) SL ECGIndexArray 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",1A) US FDFlag 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",1B) OB SH_ZOOM 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",1C) OB SH_COLPAR 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",1D) US K_Factor 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",1E) US EVE 8 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",1F) SL TotalSceneTime 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",20) US RestoreFlag 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",21) US StandMovementFlag 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",22) US FDRows 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",23) US FDColumns 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",24) US TableMovementFlag 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",25) LO OriginalOrganProgramName 1 PrivateTag
+(0021,"SIEMENS SMS-AX ACQ 1.0",26) DS CrispyXPIFilter 1 PrivateTag
+
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",00) US ViewNative 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",01) US OriginalSeriesNumber 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",02) US OriginalImageNumber 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",03) US WinCenter 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",04) US WinWidth 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",05) US WinBrightness 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",06) US WinContrast 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",07) US OriginalFrameNumber 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",08) US OriginalMaskFrameNumber 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",09) US Opac 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",0A) US OriginalNumberOfFrames 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",0B) DS OriginalSceneDuration 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",0C) LO IdentifierLOID 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",0D) SS OriginalSceneVFRInfo 1-n PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",0E) SS OriginalFrameECGPosition 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",0F) SS OriginalECG1stFrameOffset_retired 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",10) SS ZoomFlag 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",11) US Flex 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",12) US NumberOfMaskFrames 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",13) US NumberOfFillFrames 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",14) US SeriesNumber 1 PrivateTag
+(0025,"SIEMENS SMS-AX ORIGINAL IMAGE INFO 1.0",15) IS ImageNumber 1 PrivateTag
+
+(0023,"SIEMENS SMS-AX QUANT 1.0",00) DS HorizontalCalibrationPixelSize 2 PrivateTag
+(0023,"SIEMENS SMS-AX QUANT 1.0",01) DS VerticalCalibrationPixelSize 2 PrivateTag
+(0023,"SIEMENS SMS-AX QUANT 1.0",02) LO CalibrationObject 1 PrivateTag
+(0023,"SIEMENS SMS-AX QUANT 1.0",03) DS CalibrationObjectSize 1 PrivateTag
+(0023,"SIEMENS SMS-AX QUANT 1.0",04) LO CalibrationMethod 1 PrivateTag
+(0023,"SIEMENS SMS-AX QUANT 1.0",05) ST Filename 1 PrivateTag
+(0023,"SIEMENS SMS-AX QUANT 1.0",06) IS FrameNumber 1 PrivateTag
+(0023,"SIEMENS SMS-AX QUANT 1.0",07) IS CalibrationFactorMultiplicity 2 PrivateTag
+(0023,"SIEMENS SMS-AX QUANT 1.0",08) IS CalibrationTODValue 1 PrivateTag
+
+(0019,"SIEMENS SMS-AX VIEW 1.0",00) US ReviewMode 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",01) US AnatomicalBackgroundPercent 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",02) US NumberOfPhases 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",03) US ApplyAnatomicalBackground 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",04) SS PixelShiftArray 4-4n PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",05) US Brightness 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",06) US Contrast 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",07) US Enabled 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",08) US NativeEdgeEnhancementPercentGain 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",09) SS NativeEdgeEnhancementLUTIndex 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",0A) SS NativeEdgeEnhancementKernelSize 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",0B) US SubtrEdgeEnhancementPercentGain 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",0C) SS SubtrEdgeEnhancementLUTIndex 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",0D) SS SubtrEdgeEnhancementKernelSize 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",0E) US FadePercent 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",0F) US FlippedBeforeLateralityApplied 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",10) US ApplyFade 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",12) US Zoom 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",13) SS PanX 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",14) SS PanY 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",15) SS NativeEdgeEnhancementAdvPercGain 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",16) SS SubtrEdgeEnhancementAdvPercGain 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",17) US InvertFlag 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",1A) OB Quant1KOverlay 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",1B) US OriginalResolution 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",1C) DS AutoWindowCenter 1 PrivateTag
+(0019,"SIEMENS SMS-AX VIEW 1.0",1D) DS AutoWindowWidth 1 PrivateTag
+
+(0009,"SIENET",01) US SIENETCommandField 1 PrivateTag
+(0009,"SIENET",14) LT ReceiverPLA 1 PrivateTag
+(0009,"SIENET",16) US TransferPriority 1 PrivateTag
+(0009,"SIENET",29) LT ActualUser 1 PrivateTag
+(0095,"SIENET",01) LT ExaminationFolderID 1 PrivateTag
+(0095,"SIENET",04) UL FolderReportedStatus 1 PrivateTag
+(0095,"SIENET",05) LT FolderReportingRadiologist 1 PrivateTag
+(0095,"SIENET",07) LT SIENETISAPLA 1 PrivateTag
+(0099,"SIENET",02) UL DataObjectAttributes 1 PrivateTag
+
+(0009,"SPI RELEASE 1",10) LT Comments 1 PrivateTag
+(0009,"SPI RELEASE 1",15) LO SPIImageUID 1 PrivateTag
+(0009,"SPI RELEASE 1",40) US DataObjectType 1 PrivateTag
+(0009,"SPI RELEASE 1",41) LO DataObjectSubtype 1 PrivateTag
+(0011,"SPI RELEASE 1",10) LO Organ 1 PrivateTag
+(0011,"SPI RELEASE 1",15) LO AllergyIndication 1 PrivateTag
+(0011,"SPI RELEASE 1",20) LO Pregnancy 1 PrivateTag
+(0029,"SPI RELEASE 1",60) LT CompressionAlgorithm 1 PrivateTag
+
+(0009,"SPI Release 1",10) LT Comments 1 PrivateTag
+(0009,"SPI Release 1",15) LO SPIImageUID 1 PrivateTag
+(0009,"SPI Release 1",40) US DataObjectType 1 PrivateTag
+(0009,"SPI Release 1",41) LO DataObjectSubtype 1 PrivateTag
+(0011,"SPI Release 1",10) LO Organ 1 PrivateTag
+(0011,"SPI Release 1",15) LO AllergyIndication 1 PrivateTag
+(0011,"SPI Release 1",20) LO Pregnancy 1 PrivateTag
+(0029,"SPI Release 1",60) LT CompressionAlgorithm 1 PrivateTag
+
+(0009,"SPI",10) LO Comments 1 PrivateTag
+(0009,"SPI",15) LO SPIImageUID 1 PrivateTag
+(0009,"SPI",40) US DataObjectType 1 PrivateTag
+(0009,"SPI",41) LT DataObjectSubtype 1 PrivateTag
+(0011,"SPI",10) LT Organ 1 PrivateTag
+(0011,"SPI",15) LT AllergyIndication 1 PrivateTag
+(0011,"SPI",20) LT Pregnancy 1 PrivateTag
+(0029,"SPI",60) LT CompressionAlgorithm 1 PrivateTag
+
+(0011,"SPI RELEASE 1",10) LO Organ 1 PrivateTag
+(0011,"SPI RELEASE 1",15) LO AllergyIndication 1 PrivateTag
+(0011,"SPI RELEASE 1",20) LO Pregnancy 1 PrivateTag
+
+(0009,"SPI-P Release 1",00) LT DataObjectRecognitionCode 1 PrivateTag
+(0009,"SPI-P Release 1",04) LO ImageDataConsistence 1 PrivateTag
+(0009,"SPI-P Release 1",08) US Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",12) LO Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",15) LO UniqueIdentifier 1 PrivateTag
+(0009,"SPI-P Release 1",16) LO Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",18) LO Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",21) LT Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",31) LT PACSUniqueIdentifier 1 PrivateTag
+(0009,"SPI-P Release 1",34) LT ClusterUniqueIdentifier 1 PrivateTag
+(0009,"SPI-P Release 1",38) LT SystemUniqueIdentifier 1 PrivateTag
+(0009,"SPI-P Release 1",39) LT Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",51) LT StudyUniqueIdentifier 1 PrivateTag
+(0009,"SPI-P Release 1",61) LT SeriesUniqueIdentifier 1 PrivateTag
+(0009,"SPI-P Release 1",91) LT Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",f2) LT Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",f3) UN Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",f4) LT Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",f5) UN Unknown 1 PrivateTag
+(0009,"SPI-P Release 1",f7) LT Unknown 1 PrivateTag
+(0011,"SPI-P Release 1",10) LT PatientEntryID 1 PrivateTag
+(0011,"SPI-P Release 1",21) UN Unknown 1 PrivateTag
+(0011,"SPI-P Release 1",22) UN Unknown 1 PrivateTag
+(0011,"SPI-P Release 1",31) UN Unknown 1 PrivateTag
+(0011,"SPI-P Release 1",32) UN Unknown 1 PrivateTag
+(0019,"SPI-P Release 1",00) UN Unknown 1 PrivateTag
+(0019,"SPI-P Release 1",01) UN Unknown 1 PrivateTag
+(0019,"SPI-P Release 1",02) UN Unknown 1 PrivateTag
+(0019,"SPI-P Release 1",10) US MainsFrequency 1 PrivateTag
+(0019,"SPI-P Release 1",25) LT OriginalPixelDataQuality 1-n PrivateTag
+(0019,"SPI-P Release 1",30) US ECGTriggering 1 PrivateTag
+(0019,"SPI-P Release 1",31) UN ECG1Offset 1 PrivateTag
+(0019,"SPI-P Release 1",32) UN ECG2Offset1 1 PrivateTag
+(0019,"SPI-P Release 1",33) UN ECG2Offset2 1 PrivateTag
+(0019,"SPI-P Release 1",50) US VideoScanMode 1 PrivateTag
+(0019,"SPI-P Release 1",51) US VideoLineRate 1 PrivateTag
+(0019,"SPI-P Release 1",60) US XrayTechnique 1 PrivateTag
+(0019,"SPI-P Release 1",61) DS ImageIdentifierFromat 1 PrivateTag
+(0019,"SPI-P Release 1",62) US IrisDiaphragm 1 PrivateTag
+(0019,"SPI-P Release 1",63) CS Filter 1 PrivateTag
+(0019,"SPI-P Release 1",64) CS CineParallel 1 PrivateTag
+(0019,"SPI-P Release 1",65) CS CineMaster 1 PrivateTag
+(0019,"SPI-P Release 1",70) US ExposureChannel 1 PrivateTag
+(0019,"SPI-P Release 1",71) UN ExposureChannelFirstImage 1 PrivateTag
+(0019,"SPI-P Release 1",72) US ProcessingChannel 1 PrivateTag
+(0019,"SPI-P Release 1",80) DS AcquisitionDelay 1 PrivateTag
+(0019,"SPI-P Release 1",81) UN RelativeImageTime 1 PrivateTag
+(0019,"SPI-P Release 1",90) CS VideoWhiteCompression 1 PrivateTag
+(0019,"SPI-P Release 1",a0) US Angulation 1 PrivateTag
+(0019,"SPI-P Release 1",a1) US Rotation 1 PrivateTag
+(0021,"SPI-P Release 1",12) LT SeriesUniqueIdentifier 1 PrivateTag
+(0021,"SPI-P Release 1",14) LT Unknown 1 PrivateTag
+(0029,"SPI-P Release 1",00) DS Unknown 4 PrivateTag
+(0029,"SPI-P Release 1",20) DS PixelAspectRatio 1 PrivateTag
+(0029,"SPI-P Release 1",25) LO ProcessedPixelDataQuality 1-n PrivateTag
+(0029,"SPI-P Release 1",30) LT Unknown 1 PrivateTag
+(0029,"SPI-P Release 1",38) US Unknown 1 PrivateTag
+(0029,"SPI-P Release 1",60) LT Unknown 1 PrivateTag
+(0029,"SPI-P Release 1",61) LT Unknown 1 PrivateTag
+(0029,"SPI-P Release 1",67) LT Unknown 1 PrivateTag
+(0029,"SPI-P Release 1",70) LT WindowID 1 PrivateTag
+(0029,"SPI-P Release 1",71) CS VideoInvertSubtracted 1 PrivateTag
+(0029,"SPI-P Release 1",72) CS VideoInvertNonsubtracted 1 PrivateTag
+(0029,"SPI-P Release 1",77) CS WindowSelectStatus 1 PrivateTag
+(0029,"SPI-P Release 1",78) LT ECGDisplayPrintingID 1 PrivateTag
+(0029,"SPI-P Release 1",79) CS ECGDisplayPrinting 1 PrivateTag
+(0029,"SPI-P Release 1",7e) CS ECGDisplayPrintingEnableStatus 1 PrivateTag
+(0029,"SPI-P Release 1",7f) CS ECGDisplayPrintingSelectStatus 1 PrivateTag
+(0029,"SPI-P Release 1",80) LT PhysiologicalDisplayID 1 PrivateTag
+(0029,"SPI-P Release 1",81) US PreferredPhysiologicalChannelDisplay 1 PrivateTag
+(0029,"SPI-P Release 1",8e) CS PhysiologicalDisplayEnableStatus 1 PrivateTag
+(0029,"SPI-P Release 1",8f) CS PhysiologicalDisplaySelectStatus 1 PrivateTag
+(0029,"SPI-P Release 1",c0) LT FunctionalShutterID 1 PrivateTag
+(0029,"SPI-P Release 1",c1) US FieldOfShutter 1 PrivateTag
+(0029,"SPI-P Release 1",c5) LT FieldOfShutterRectangle 1 PrivateTag
+(0029,"SPI-P Release 1",ce) CS ShutterEnableStatus 1 PrivateTag
+(0029,"SPI-P Release 1",cf) CS ShutterSelectStatus 1 PrivateTag
+(7FE1,"SPI-P Release 1",10) ox PixelData 1 PrivateTag
+
+(0009,"SPI-P Release 1;1",c0) LT Unknown 1 PrivateTag
+(0009,"SPI-P Release 1;1",c1) LT Unknown 1 PrivateTag
+(0019,"SPI-P Release 1;1",00) UN PhysiologicalDataType 1 PrivateTag
+(0019,"SPI-P Release 1;1",01) UN PhysiologicalDataChannelAndKind 1 PrivateTag
+(0019,"SPI-P Release 1;1",02) US SampleBitsAllocated 1 PrivateTag
+(0019,"SPI-P Release 1;1",03) US SampleBitsStored 1 PrivateTag
+(0019,"SPI-P Release 1;1",04) US SampleHighBit 1 PrivateTag
+(0019,"SPI-P Release 1;1",05) US SampleRepresentation 1 PrivateTag
+(0019,"SPI-P Release 1;1",06) UN SmallestSampleValue 1 PrivateTag
+(0019,"SPI-P Release 1;1",07) UN LargestSampleValue 1 PrivateTag
+(0019,"SPI-P Release 1;1",08) UN NumberOfSamples 1 PrivateTag
+(0019,"SPI-P Release 1;1",09) UN SampleData 1 PrivateTag
+(0019,"SPI-P Release 1;1",0a) UN SampleRate 1 PrivateTag
+(0019,"SPI-P Release 1;1",10) UN PhysiologicalDataType2 1 PrivateTag
+(0019,"SPI-P Release 1;1",11) UN PhysiologicalDataChannelAndKind2 1 PrivateTag
+(0019,"SPI-P Release 1;1",12) US SampleBitsAllocated2 1 PrivateTag
+(0019,"SPI-P Release 1;1",13) US SampleBitsStored2 1 PrivateTag
+(0019,"SPI-P Release 1;1",14) US SampleHighBit2 1 PrivateTag
+(0019,"SPI-P Release 1;1",15) US SampleRepresentation2 1 PrivateTag
+(0019,"SPI-P Release 1;1",16) UN SmallestSampleValue2 1 PrivateTag
+(0019,"SPI-P Release 1;1",17) UN LargestSampleValue2 1 PrivateTag
+(0019,"SPI-P Release 1;1",18) UN NumberOfSamples2 1 PrivateTag
+(0019,"SPI-P Release 1;1",19) UN SampleData2 1 PrivateTag
+(0019,"SPI-P Release 1;1",1a) UN SampleRate2 1 PrivateTag
+(0029,"SPI-P Release 1;1",00) LT ZoomID 1 PrivateTag
+(0029,"SPI-P Release 1;1",01) DS ZoomRectangle 1-n PrivateTag
+(0029,"SPI-P Release 1;1",03) DS ZoomFactor 1 PrivateTag
+(0029,"SPI-P Release 1;1",04) US ZoomFunction 1 PrivateTag
+(0029,"SPI-P Release 1;1",0e) CS ZoomEnableStatus 1 PrivateTag
+(0029,"SPI-P Release 1;1",0f) CS ZoomSelectStatus 1 PrivateTag
+(0029,"SPI-P Release 1;1",40) LT MagnifyingGlassID 1 PrivateTag
+(0029,"SPI-P Release 1;1",41) DS MagnifyingGlassRectangle 1-n PrivateTag
+(0029,"SPI-P Release 1;1",43) DS MagnifyingGlassFactor 1 PrivateTag
+(0029,"SPI-P Release 1;1",44) US MagnifyingGlassFunction 1 PrivateTag
+(0029,"SPI-P Release 1;1",4e) CS MagnifyingGlassEnableStatus 1 PrivateTag
+(0029,"SPI-P Release 1;1",4f) CS MagnifyingGlassSelectStatus 1 PrivateTag
+
+(0029,"SPI-P Release 1;2",00) LT SubtractionMaskID 1 PrivateTag
+(0029,"SPI-P Release 1;2",04) UN MaskingFunction 1 PrivateTag
+(0029,"SPI-P Release 1;2",0c) UN ProprietaryMaskingParameters 1 PrivateTag
+(0029,"SPI-P Release 1;2",1e) CS SubtractionMaskEnableStatus 1 PrivateTag
+(0029,"SPI-P Release 1;2",1f) CS SubtractionMaskSelectStatus 1 PrivateTag
+(0029,"SPI-P Release 1;3",00) LT ImageEnhancementID 1 PrivateTag
+(0029,"SPI-P Release 1;3",01) LT ImageEnhancement 1 PrivateTag
+(0029,"SPI-P Release 1;3",02) LT ConvolutionID 1 PrivateTag
+(0029,"SPI-P Release 1;3",03) LT ConvolutionType 1 PrivateTag
+(0029,"SPI-P Release 1;3",04) LT ConvolutionKernelSizeID 1 PrivateTag
+(0029,"SPI-P Release 1;3",05) US ConvolutionKernelSize 2 PrivateTag
+(0029,"SPI-P Release 1;3",06) US ConvolutionKernel 1-n PrivateTag
+(0029,"SPI-P Release 1;3",0c) DS EnhancementGain 1 PrivateTag
+(0029,"SPI-P Release 1;3",1e) CS ImageEnhancementEnableStatus 1 PrivateTag
+(0029,"SPI-P Release 1;3",1f) CS ImageEnhancementSelectStatus 1 PrivateTag
+
+(0011,"SPI-P Release 2;1",18) LT Unknown 1 PrivateTag
+(0023,"SPI-P Release 2;1",0d) UI Unknown 1 PrivateTag
+(0023,"SPI-P Release 2;1",0e) UI Unknown 1 PrivateTag
+
+(0009,"SPI-P-GV-CT Release 1",00) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",10) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",20) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",30) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",40) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",50) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",60) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",70) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",75) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",80) LO Unknown 1 PrivateTag
+(0009,"SPI-P-GV-CT Release 1",90) LO Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",08) IS Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",09) IS Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",0a) IS Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",10) LO Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",20) TM Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",50) LO Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",60) DS Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",61) US Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",63) LO Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",64) US Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",65) IS Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",70) LT Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",80) LO Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",81) LO Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",90) LO Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",a0) LO Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",a1) US Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",a2) US Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",a3) US Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",b0) LO Unknown 1 PrivateTag
+(0019,"SPI-P-GV-CT Release 1",b1) LO Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",20) LO Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",30) DS Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",40) LO Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",50) LO Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",60) DS Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",70) DS Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",80) DS Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",90) DS Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a0) US Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a1) DS Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a2) DS Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a3) LT Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",a4) LT Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",b0) LO Unknown 1 PrivateTag
+(0021,"SPI-P-GV-CT Release 1",c0) LO Unknown 1 PrivateTag
+(0029,"SPI-P-GV-CT Release 1",10) LO Unknown 1 PrivateTag
+(0029,"SPI-P-GV-CT Release 1",30) UL Unknown 1 PrivateTag
+(0029,"SPI-P-GV-CT Release 1",31) UL Unknown 1 PrivateTag
+(0029,"SPI-P-GV-CT Release 1",32) UL Unknown 1 PrivateTag
+(0029,"SPI-P-GV-CT Release 1",33) UL Unknown 1 PrivateTag
+(0029,"SPI-P-GV-CT Release 1",80) LO Unknown 1 PrivateTag
+(0029,"SPI-P-GV-CT Release 1",90) LO Unknown 1 PrivateTag
+(0029,"SPI-P-GV-CT Release 1",d0) IS Unknown 1 PrivateTag
+(0029,"SPI-P-GV-CT Release 1",d1) IS Unknown 1 PrivateTag
+
+(0019,"SPI-P-PCR Release 2",30) US Unknown 1 PrivateTag
+
+(0021,"SPI-P-Private-CWS Release 1",00) LT WindowOfImagesID 1 PrivateTag
+(0021,"SPI-P-Private-CWS Release 1",01) CS WindowOfImagesType 1 PrivateTag
+(0021,"SPI-P-Private-CWS Release 1",02) IS WindowOfImagesScope 1-n PrivateTag
+
+(0019,"SPI-P-Private-DCI Release 1",10) UN ECGTimeMapDataBitsAllocated 1 PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",11) UN ECGTimeMapDataBitsStored 1 PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",12) UN ECGTimeMapDataHighBit 1 PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",13) UN ECGTimeMapDataRepresentation 1 PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",14) UN ECGTimeMapDataSmallestDataValue 1 PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",15) UN ECGTimeMapDataLargestDataValue 1 PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",16) UN ECGTimeMapDataNumberOfDataValues 1 PrivateTag
+(0019,"SPI-P-Private-DCI Release 1",17) UN ECGTimeMapData 1 PrivateTag
+
+(0021,"SPI-P-Private_CDS Release 1",40) IS Unknown 1 PrivateTag
+(0029,"SPI-P-Private_CDS Release 1",00) UN Unknown 1 PrivateTag
+
+(0019,"SPI-P-Private_ICS Release 1",30) DS Unknown 1 PrivateTag
+(0019,"SPI-P-Private_ICS Release 1",31) LO Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",08) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",0f) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",10) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",1b) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",1c) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",21) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",43) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",44) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",4C) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",67) LO Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",68) US Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",6A) LO Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1",6B) US Unknown 1 PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;1",00) SL Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",05) FL Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",06) FL Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",20) FL Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",21) FL Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;1",CD) SQ Unknown 1 PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;2",00) FD Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",01) FD Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",02) FD Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",03) SL Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",04) SL Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;2",05) SL Unknown 1 PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;3",C0) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C1) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C2) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C3) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C4) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;3",C5) SQ Unknown 1 PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;4",02) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;4",9A) SQ Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;4",E0) SQ Unknown 1 PrivateTag
+
+(0029,"SPI-P-Private_ICS Release 1;5",50) CS Unknown 1 PrivateTag
+(0029,"SPI-P-Private_ICS Release 1;5",55) CS Unknown 1 PrivateTag
+
+(0019,"SPI-P-XSB-DCI Release 1",10) LT VideoBeamBoost 1 PrivateTag
+(0019,"SPI-P-XSB-DCI Release 1",11) US ChannelGeneratingVideoSync 1 PrivateTag
+(0019,"SPI-P-XSB-DCI Release 1",12) US VideoGain 1 PrivateTag
+(0019,"SPI-P-XSB-DCI Release 1",13) US VideoOffset 1 PrivateTag
+(0019,"SPI-P-XSB-DCI Release 1",20) DS RTDDataCompressionFactor 1 PrivateTag
+
+(0029,"Silhouette Annot V1.0",11) IS AnnotationName 1 PrivateTag
+(0029,"Silhouette Annot V1.0",12) LT AnnotationFont 1 PrivateTag
+(0029,"Silhouette Annot V1.0",13) LT AnnotationTextForegroundColor 1 PrivateTag
+(0029,"Silhouette Annot V1.0",14) LT AnnotationTextBackgroundColor 1 PrivateTag
+(0029,"Silhouette Annot V1.0",15) UL AnnotationTextBackingMode 1 PrivateTag
+(0029,"Silhouette Annot V1.0",16) UL AnnotationTextJustification 1 PrivateTag
+(0029,"Silhouette Annot V1.0",17) UL AnnotationTextLocation 1 PrivateTag
+(0029,"Silhouette Annot V1.0",18) LT AnnotationTextString 1 PrivateTag
+(0029,"Silhouette Annot V1.0",19) UL AnnotationTextAttachMode 1 PrivateTag
+(0029,"Silhouette Annot V1.0",20) UL AnnotationTextCursorMode 1 PrivateTag
+(0029,"Silhouette Annot V1.0",21) UL AnnotationTextShadowOffsetX 1 PrivateTag
+(0029,"Silhouette Annot V1.0",22) UL AnnotationTextShadowOffsetY 1 PrivateTag
+(0029,"Silhouette Annot V1.0",23) LT AnnotationLineColor 1 PrivateTag
+(0029,"Silhouette Annot V1.0",24) UL AnnotationLineThickness 1 PrivateTag
+(0029,"Silhouette Annot V1.0",25) UL AnnotationLineType 1 PrivateTag
+(0029,"Silhouette Annot V1.0",26) UL AnnotationLineStyle 1 PrivateTag
+(0029,"Silhouette Annot V1.0",27) UL AnnotationLineDashLength 1 PrivateTag
+(0029,"Silhouette Annot V1.0",28) UL AnnotationLineAttachMode 1 PrivateTag
+(0029,"Silhouette Annot V1.0",29) UL AnnotationLinePointCount 1 PrivateTag
+(0029,"Silhouette Annot V1.0",30) FD AnnotationLinePoints 1 PrivateTag
+(0029,"Silhouette Annot V1.0",31) UL AnnotationLineControlSize 1 PrivateTag
+(0029,"Silhouette Annot V1.0",32) LT AnnotationMarkerColor 1 PrivateTag
+(0029,"Silhouette Annot V1.0",33) UL AnnotationMarkerType 1 PrivateTag
+(0029,"Silhouette Annot V1.0",34) UL AnnotationMarkerSize 1 PrivateTag
+(0029,"Silhouette Annot V1.0",35) FD AnnotationMarkerLocation 1 PrivateTag
+(0029,"Silhouette Annot V1.0",36) UL AnnotationMarkerAttachMode 1 PrivateTag
+(0029,"Silhouette Annot V1.0",37) LT AnnotationGeomColor 1 PrivateTag
+(0029,"Silhouette Annot V1.0",38) UL AnnotationGeomThickness 1 PrivateTag
+(0029,"Silhouette Annot V1.0",39) UL AnnotationGeomLineStyle 1 PrivateTag
+(0029,"Silhouette Annot V1.0",40) UL AnnotationGeomDashLength 1 PrivateTag
+(0029,"Silhouette Annot V1.0",41) UL AnnotationGeomFillPattern 1 PrivateTag
+(0029,"Silhouette Annot V1.0",42) UL AnnotationInteractivity 1 PrivateTag
+(0029,"Silhouette Annot V1.0",43) FD AnnotationArrowLength 1 PrivateTag
+(0029,"Silhouette Annot V1.0",44) FD AnnotationArrowAngle 1 PrivateTag
+(0029,"Silhouette Annot V1.0",45) UL AnnotationDontSave 1 PrivateTag
+
+(0029,"Silhouette Graphics Export V1.0",00) UI Unknown 1 PrivateTag
+
+(0029,"Silhouette Line V1.0",11) IS LineName 1 PrivateTag
+(0029,"Silhouette Line V1.0",12) LT LineNameFont 1 PrivateTag
+(0029,"Silhouette Line V1.0",13) UL LineNameDisplay 1 PrivateTag
+(0029,"Silhouette Line V1.0",14) LT LineNormalColor 1 PrivateTag
+(0029,"Silhouette Line V1.0",15) UL LineType 1 PrivateTag
+(0029,"Silhouette Line V1.0",16) UL LineThickness 1 PrivateTag
+(0029,"Silhouette Line V1.0",17) UL LineStyle 1 PrivateTag
+(0029,"Silhouette Line V1.0",18) UL LineDashLength 1 PrivateTag
+(0029,"Silhouette Line V1.0",19) UL LineInteractivity 1 PrivateTag
+(0029,"Silhouette Line V1.0",20) LT LineMeasurementColor 1 PrivateTag
+(0029,"Silhouette Line V1.0",21) LT LineMeasurementFont 1 PrivateTag
+(0029,"Silhouette Line V1.0",22) UL LineMeasurementDashLength 1 PrivateTag
+(0029,"Silhouette Line V1.0",23) UL LinePointSpace 1 PrivateTag
+(0029,"Silhouette Line V1.0",24) FD LinePoints 1 PrivateTag
+(0029,"Silhouette Line V1.0",25) UL LineControlPointSize 1 PrivateTag
+(0029,"Silhouette Line V1.0",26) UL LineControlPointSpace 1 PrivateTag
+(0029,"Silhouette Line V1.0",27) FD LineControlPoints 1 PrivateTag
+(0029,"Silhouette Line V1.0",28) LT LineLabel 1 PrivateTag
+(0029,"Silhouette Line V1.0",29) UL LineDontSave 1 PrivateTag
+
+(0029,"Silhouette ROI V1.0",11) IS ROIName 1 PrivateTag
+(0029,"Silhouette ROI V1.0",12) LT ROINameFont 1 PrivateTag
+(0029,"Silhouette ROI V1.0",13) LT ROINormalColor 1 PrivateTag
+(0029,"Silhouette ROI V1.0",14) UL ROIFillPattern 1 PrivateTag
+(0029,"Silhouette ROI V1.0",15) UL ROIBpSeg 1 PrivateTag
+(0029,"Silhouette ROI V1.0",16) UN ROIBpSegPairs 1 PrivateTag
+(0029,"Silhouette ROI V1.0",17) UL ROISeedSpace 1 PrivateTag
+(0029,"Silhouette ROI V1.0",18) UN ROISeeds 1 PrivateTag
+(0029,"Silhouette ROI V1.0",19) UL ROILineThickness 1 PrivateTag
+(0029,"Silhouette ROI V1.0",20) UL ROILineStyle 1 PrivateTag
+(0029,"Silhouette ROI V1.0",21) UL ROILineDashLength 1 PrivateTag
+(0029,"Silhouette ROI V1.0",22) UL ROIInteractivity 1 PrivateTag
+(0029,"Silhouette ROI V1.0",23) UL ROINamePosition 1 PrivateTag
+(0029,"Silhouette ROI V1.0",24) UL ROINameDisplay 1 PrivateTag
+(0029,"Silhouette ROI V1.0",25) LT ROILabel 1 PrivateTag
+(0029,"Silhouette ROI V1.0",26) UL ROIShape 1 PrivateTag
+(0029,"Silhouette ROI V1.0",27) FD ROIShapeTilt 1 PrivateTag
+(0029,"Silhouette ROI V1.0",28) UL ROIShapePointsCount 1 PrivateTag
+(0029,"Silhouette ROI V1.0",29) UL ROIShapePointsSpace 1 PrivateTag
+(0029,"Silhouette ROI V1.0",30) FD ROIShapePoints 1 PrivateTag
+(0029,"Silhouette ROI V1.0",31) UL ROIShapeControlPointsCount 1 PrivateTag
+(0029,"Silhouette ROI V1.0",32) UL ROIShapeControlPointsSpace 1 PrivateTag
+(0029,"Silhouette ROI V1.0",33) FD ROIShapeControlPoints 1 PrivateTag
+(0029,"Silhouette ROI V1.0",34) UL ROIDontSave 1 PrivateTag
+
+(0029,"Silhouette Sequence Ids V1.0",41) SQ Unknown 1 PrivateTag
+(0029,"Silhouette Sequence Ids V1.0",42) SQ Unknown 1 PrivateTag
+(0029,"Silhouette Sequence Ids V1.0",43) SQ Unknown 1 PrivateTag
+
+(0029,"Silhouette V1.0",13) UL Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",14) UL Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",17) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",18) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",19) UL Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",1a) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",1b) UL Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",1c) UL Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",1d) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",1e) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",21) US Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",22) US Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",23) US Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",24) US Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",25) US Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",27) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",28) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",29) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",30) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",52) US Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",53) LT Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",54) UN Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",55) LT Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",56) LT Unknown 1 PrivateTag
+(0029,"Silhouette V1.0",57) UN Unknown 1 PrivateTag
+
+(0135,"SONOWAND AS",10) LO UltrasoundScannerName 1 PrivateTag
+(0135,"SONOWAND AS",11) LO TransducerSerial 1 PrivateTag
+(0135,"SONOWAND AS",12) LO ProbeApplication 1 PrivateTag
+
+(0017,"SVISION",00) LO ExtendedBodyPart 1 PrivateTag
+(0017,"SVISION",10) LO ExtendedViewPosition 1 PrivateTag
+(0017,"SVISION",F0) IS ImagesSOPClass 1 PrivateTag
+(0019,"SVISION",00) IS AECField 1 PrivateTag
+(0019,"SVISION",01) IS AECFilmScreen 1 PrivateTag
+(0019,"SVISION",02) IS AECDensity 1 PrivateTag
+(0019,"SVISION",10) IS PatientThickness 1 PrivateTag
+(0019,"SVISION",18) IS BeamDistance 1 PrivateTag
+(0019,"SVISION",20) IS WorkstationNumber 1 PrivateTag
+(0019,"SVISION",28) IS TubeNumber 1 PrivateTag
+(0019,"SVISION",30) IS BuckyGrid 1 PrivateTag
+(0019,"SVISION",34) IS Focus 1 PrivateTag
+(0019,"SVISION",38) IS Child 1 PrivateTag
+(0019,"SVISION",40) IS CollimatorDistanceX 1 PrivateTag
+(0019,"SVISION",41) IS CollimatorDistanceY 1 PrivateTag
+(0019,"SVISION",50) IS CentralBeamHeight 1 PrivateTag
+(0019,"SVISION",60) IS BuckyAngle 1 PrivateTag
+(0019,"SVISION",68) IS CArmAngle 1 PrivateTag
+(0019,"SVISION",69) IS CollimatorAngle 1 PrivateTag
+(0019,"SVISION",70) IS FilterNumber 1 PrivateTag
+(0019,"SVISION",74) LO FilterMaterial1 1 PrivateTag
+(0019,"SVISION",75) LO FilterMaterial2 1 PrivateTag
+(0019,"SVISION",78) DS FilterThickness1 1 PrivateTag
+(0019,"SVISION",79) DS FilterThickness2 1 PrivateTag
+(0019,"SVISION",80) IS BuckyFormat 1 PrivateTag
+(0019,"SVISION",81) IS ObjectPosition 1 PrivateTag
+(0019,"SVISION",90) LO DeskCommand 1 PrivateTag
+(0019,"SVISION",A0) DS ExtendedExposureTime 1 PrivateTag
+(0019,"SVISION",A1) DS ActualExposureTime 1 PrivateTag
+(0019,"SVISION",A8) DS ExtendedXRayTubeCurrent 1 PrivateTag
+(0021,"SVISION",00) DS NoiseReduction 1 PrivateTag
+(0021,"SVISION",01) DS ContrastAmplification 1 PrivateTag
+(0021,"SVISION",02) DS EdgeContrastBoosting 1 PrivateTag
+(0021,"SVISION",03) DS LatitudeReduction 1 PrivateTag
+(0021,"SVISION",10) LO FindRangeAlgorithm 1 PrivateTag
+(0021,"SVISION",11) DS ThresholdCAlgorithm 1 PrivateTag
+(0021,"SVISION",20) LO SensometricCurve 1 PrivateTag
+(0021,"SVISION",30) DS LowerWindowOffset 1 PrivateTag
+(0021,"SVISION",31) DS UpperWindowOffset 1 PrivateTag
+(0021,"SVISION",40) DS MinPrintableDensity 1 PrivateTag
+(0021,"SVISION",41) DS MaxPrintableDensity 1 PrivateTag
+(0021,"SVISION",90) DS Brightness 1 PrivateTag
+(0021,"SVISION",91) DS Contrast 1 PrivateTag
+(0021,"SVISION",92) DS ShapeFactor 1 PrivateTag
+(0023,"SVISION",00) LO ImageLaterality 1 PrivateTag
+(0023,"SVISION",01) IS LetterPosition 1 PrivateTag
+(0023,"SVISION",02) IS BurnedInAnnotation 1 PrivateTag
+(0023,"SVISION",03) LO Unknown 1 PrivateTag
+(0023,"SVISION",F0) IS ImageSOPClass 1 PrivateTag
+(0025,"SVISION",00) IS OriginalImage 1 PrivateTag
+(0025,"SVISION",01) IS NotProcessedImage 1 PrivateTag
+(0025,"SVISION",02) IS CutOutImage 1 PrivateTag
+(0025,"SVISION",03) IS DuplicatedImage 1 PrivateTag
+(0025,"SVISION",04) IS StoredImage 1 PrivateTag
+(0025,"SVISION",05) IS RetrievedImage 1 PrivateTag
+(0025,"SVISION",06) IS RemoteImage 1 PrivateTag
+(0025,"SVISION",07) IS MediaStoredImage 1 PrivateTag
+(0025,"SVISION",08) IS ImageState 1 PrivateTag
+(0025,"SVISION",20) LO SourceImageFile 1 PrivateTag
+(0025,"SVISION",21) UI Unknown 1 PrivateTag
+(0027,"SVISION",00) IS NumberOfSeries 1 PrivateTag
+(0027,"SVISION",01) IS NumberOfStudies 1 PrivateTag
+(0027,"SVISION",10) DT OldestSeries 1 PrivateTag
+(0027,"SVISION",11) DT NewestSeries 1 PrivateTag
+(0027,"SVISION",12) DT OldestStudy 1 PrivateTag
+(0027,"SVISION",13) DT NewestStudy 1 PrivateTag
+
+(0009,"TOSHIBA_MEC_1.0",01) LT Unknown 1 PrivateTag
+(0009,"TOSHIBA_MEC_1.0",02) US Unknown 1-n PrivateTag
+(0009,"TOSHIBA_MEC_1.0",03) US Unknown 1-n PrivateTag
+(0009,"TOSHIBA_MEC_1.0",04) US Unknown 1-n PrivateTag
+(0011,"TOSHIBA_MEC_1.0",01) LT Unknown 1 PrivateTag
+(0011,"TOSHIBA_MEC_1.0",02) US Unknown 1-n PrivateTag
+(0019,"TOSHIBA_MEC_1.0",01) US Unknown 1-n PrivateTag
+(0019,"TOSHIBA_MEC_1.0",02) US Unknown 1-n PrivateTag
+(0021,"TOSHIBA_MEC_1.0",01) US Unknown 1-n PrivateTag
+(0021,"TOSHIBA_MEC_1.0",02) US Unknown 1-n PrivateTag
+(0021,"TOSHIBA_MEC_1.0",03) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_1.0",01) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_1.0",02) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_1.0",03) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_1.0",10) US Unknown 1-n PrivateTag
+
+(0019,"TOSHIBA_MEC_CT_1.0",01) IS Unknown 1 PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",02) IS Unknown 1 PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",03) US Unknown 1-n PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",04) LT Unknown 1 PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",05) LT Unknown 1 PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",06) US Unknown 1-n PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",07) US Unknown 1-n PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",08) LT OrientationHeadFeet 1 PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",09) LT ViewDirection 1 PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0a) LT OrientationSupineProne 1 PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0b) DS Unknown 1 PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0c) US Unknown 1-n PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0d) TM Time 1 PrivateTag
+(0019,"TOSHIBA_MEC_CT_1.0",0e) DS Unknown 1 PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",01) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",02) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",03) IS Unknown 1 PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",04) IS Unknown 1 PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",05) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",07) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",08) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",09) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",0a) LT Unknown 1 PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",0b) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",0c) US Unknown 1-n PrivateTag
+(7ff1,"TOSHIBA_MEC_CT_1.0",0d) US Unknown 1-n PrivateTag
+#
+# end of private.dic
+#
diff --git a/Resources/Patches/dcmtk.txt b/Resources/Patches/dcmtk.txt
index 851fa4e..f4c161b 100644
--- a/Resources/Patches/dcmtk.txt
+++ b/Resources/Patches/dcmtk.txt
@@ -1 +1,10 @@
+Generate some patch
+===================
+
diff -urEb dcmtk-3.6.0.orig/ dcmtk-3.6.0
+
+
+For "dcmtk-3.6.1-private.dic"
+=============================
+
+# cp ../../ThirdPartyDownloads/dcmtk-3.6.1_20160216/dcmdata/data/private.dic dcmtk-3.6.1-private.dic
diff --git a/Resources/Samples/Python/ArchiveStudiesInTimeRange.py b/Resources/Samples/Python/ArchiveStudiesInTimeRange.py
index 0da7a21..986a286 100755
--- a/Resources/Samples/Python/ArchiveStudiesInTimeRange.py
+++ b/Resources/Samples/Python/ArchiveStudiesInTimeRange.py
@@ -49,6 +49,12 @@ TARGET = sys.argv[4]
CheckIsDate(START)
CheckIsDate(END)
+def GetTag(tags, key):
+ if key in tags:
+ return tags[key]
+ else:
+ return 'No%s' % key
+
# Loop over the studies
for studyId in RestToolbox.DoGet('%s/studies' % URL):
# Retrieve the DICOM tags of the current study
@@ -61,13 +67,13 @@ for studyId in RestToolbox.DoGet('%s/studies' % URL):
studyDate = study['StudyDate'][:8]
if studyDate >= START and studyDate <= END:
# Create a filename
- filename = '%s - %s %s - %s.zip' % (study['StudyDate'],
- patient['PatientID'],
- patient['PatientName'],
- study['StudyDescription'])
+ filename = '%s - %s %s - %s.zip' % (GetTag(study, 'StudyDate'),
+ GetTag(patient, 'PatientID'),
+ GetTag(patient, 'PatientName'),
+ GetTag(study, 'StudyDescription'))
# Remove any non-ASCII character in the filename
- filename = filename.encode('ascii', errors = 'replace')
+ filename = filename.encode('ascii', errors = 'replace').translate(None, r"'\/:*?\"<>|!=").strip()
# Download the ZIP archive of the study
print('Downloading %s' % filename)
diff --git a/Resources/Samples/Python/AutoClassify.py b/Resources/Samples/Python/AutoClassify.py
index 1efd731..47922dd 100755
--- a/Resources/Samples/Python/AutoClassify.py
+++ b/Resources/Samples/Python/AutoClassify.py
@@ -45,7 +45,7 @@ parser.set_defaults(remove = False)
def FixPath(p):
- return p.encode('ascii', 'ignore').strip().decode()
+ return p.encode('ascii', errors = 'replace').translate(None, r"'\/:*?\"<>|!=").strip()
def GetTag(resource, tag):
if ('MainDicomTags' in resource and
@@ -110,13 +110,17 @@ while True:
if change['ChangeType'] == 'NewInstance':
try:
ClassifyInstance(change['ID'])
+
+ # If requested, remove the instance once it has been
+ # properly handled by "ClassifyInstance()". Thanks to
+ # the "try/except" block, the instance is not removed
+ # if the "ClassifyInstance()" function fails.
+ if args.remove:
+ RestToolbox.DoDelete('%s/instances/%s' % (URL, change['ID']))
+
except:
print('Unable to write instance %s to the disk' % change['ID'])
- # If requested, remove the instance once it has been copied
- if args.remove:
- RestToolbox.DoDelete('%s/instances/%s' % (URL, change['ID']))
-
current = r['Last']
if r['Done']:
diff --git a/Resources/Samples/Python/DownloadAnonymized.py b/Resources/Samples/Python/DownloadAnonymized.py
index 721721e..4674af3 100755
--- a/Resources/Samples/Python/DownloadAnonymized.py
+++ b/Resources/Samples/Python/DownloadAnonymized.py
@@ -44,6 +44,5 @@ for patient in RestToolbox.DoGet('%s/patients' % URL):
# Trigger the download
print('Downloading %s' % name)
zipContent = RestToolbox.DoGet('%s/patients/%s/archive' % (URL, patient))
- f = open(os.path.join('/tmp', name + '.zip'), 'wb')
- f.write(zipContent)
- f.close()
+ with open(os.path.join('/tmp', name + '.zip'), 'wb') as f:
+ f.write(zipContent)
diff --git a/Resources/Samples/Tools/CMakeLists.txt b/Resources/Samples/Tools/CMakeLists.txt
index ce4cb36..c426f5e 100644
--- a/Resources/Samples/Tools/CMakeLists.txt
+++ b/Resources/Samples/Tools/CMakeLists.txt
@@ -22,12 +22,20 @@ include(${ORTHANC_ROOT}/Resources/CMake/BoostConfiguration.cmake)
include(${ORTHANC_ROOT}/Resources/CMake/ZlibConfiguration.cmake)
include(${ORTHANC_ROOT}/Resources/CMake/JsonCppConfiguration.cmake)
+add_definitions(
+ -DORTHANC_ENABLE_BASE64=0
+ -DORTHANC_ENABLE_MD5=0
+ -DORTHANC_ENABLE_PUGIXML=0
+ -DORTHANC_ENABLE_LOGGING=0
+ -DORTHANC_SANDBOXED=0
+ )
+
add_library(CommonLibraries
${BOOST_SOURCES}
${JSONCPP_SOURCES}
${ORTHANC_ROOT}/Core/Enumerations.cpp
+ ${ORTHANC_ROOT}/Core/SystemToolbox.cpp
${ORTHANC_ROOT}/Core/Toolbox.cpp
- ${ORTHANC_ROOT}/Core/Uuid.cpp
${ORTHANC_ROOT}/Resources/ThirdParty/md5/md5.c
${ORTHANC_ROOT}/Resources/ThirdParty/base64/base64.cpp
)
diff --git a/Resources/Samples/Tools/RecoverCompressedFile.cpp b/Resources/Samples/Tools/RecoverCompressedFile.cpp
index b99e4e3..663ec72 100644
--- a/Resources/Samples/Tools/RecoverCompressedFile.cpp
+++ b/Resources/Samples/Tools/RecoverCompressedFile.cpp
@@ -19,7 +19,7 @@
#include "../../../Core/Compression/ZlibCompressor.h"
-#include "../../../Core/Toolbox.h"
+#include "../../../Core/SystemToolbox.h"
#include "../../../Core/OrthancException.h"
#include <stdio.h>
@@ -40,7 +40,7 @@ int main(int argc, const char* argv[])
fflush(stderr);
std::string content;
- Orthanc::Toolbox::ReadFile(content, argv[1]);
+ Orthanc::SystemToolbox::ReadFile(content, argv[1]);
fprintf(stderr, "Decompressing the content of the file...\n");
fflush(stderr);
@@ -56,7 +56,7 @@ int main(int argc, const char* argv[])
if (argc == 3)
{
- Orthanc::Toolbox::WriteFile(uncompressed, argv[2]);
+ Orthanc::SystemToolbox::WriteFile(uncompressed, argv[2]);
}
else
{
diff --git a/Resources/Samples/WebApplications/DrawingDicomizer.js b/Resources/Samples/WebApplications/DrawingDicomizer.js
index 2b80e52..93be150 100644
--- a/Resources/Samples/WebApplications/DrawingDicomizer.js
+++ b/Resources/Samples/WebApplications/DrawingDicomizer.js
@@ -58,7 +58,7 @@ var server = http.createServer(function(req, response) {
toolbox.ServeFile('DrawingDicomizer/orthanc.js', response);
}
else if (req.url == '/jquery.js') {
- toolbox.ServeFile('../../../OrthancExplorer/libs/jquery-1.7.2.min.js', response);
+ toolbox.ServeFile('../../../OrthancExplorer/libs/jquery.min.js', response);
}
else if (req.url.startsWith('/orthanc')) {
toolbox.ForwardGetRequest(orthanc, req.url.substr(8), response);
@@ -96,4 +96,6 @@ var server = http.createServer(function(req, response) {
}
});
+
+console.log('The demo is running at http://localhost:' + port + '/');
server.listen(port);
diff --git a/Resources/ThirdParty/VisualStudio/stdint.h b/Resources/ThirdParty/VisualStudio/stdint.h
index 59d0673..4fe0ef9 100644
--- a/Resources/ThirdParty/VisualStudio/stdint.h
+++ b/Resources/ThirdParty/VisualStudio/stdint.h
@@ -1,247 +1,259 @@
-// ISO C9x compliant stdint.h for Microsoft Visual Studio
-// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
-//
-// Copyright (c) 2006-2008 Alexander Chemeris
-//
-// Redistribution and use in source and binary forms, with or without
-// modification, are permitted provided that the following conditions are met:
-//
-// 1. Redistributions of source code must retain the above copyright notice,
-// this list of conditions and the following disclaimer.
-//
-// 2. Redistributions in binary form must reproduce the above copyright
-// notice, this list of conditions and the following disclaimer in the
-// documentation and/or other materials provided with the distribution.
-//
-// 3. The name of the author may be used to endorse or promote products
-// derived from this software without specific prior written permission.
-//
-// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
-// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
-// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
-// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
-// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
-// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
-// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
-// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
-// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
-// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef _MSC_VER // [
-#error "Use this header only with Microsoft Visual C++ compilers!"
-#endif // _MSC_VER ]
-
-#ifndef _MSC_STDINT_H_ // [
-#define _MSC_STDINT_H_
-
-#if _MSC_VER > 1000
-#pragma once
-#endif
-
-#include <limits.h>
-
-// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
-// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
-// or compiler give many errors like this:
-// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
-#ifdef __cplusplus
-extern "C" {
-#endif
-# include <wchar.h>
-#ifdef __cplusplus
-}
-#endif
-
-// Define _W64 macros to mark types changing their size, like intptr_t.
-#ifndef _W64
-# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
-# define _W64 __w64
-# else
-# define _W64
-# endif
-#endif
-
-
-// 7.18.1 Integer types
-
-// 7.18.1.1 Exact-width integer types
-
-// Visual Studio 6 and Embedded Visual C++ 4 doesn't
-// realize that, e.g. char has the same size as __int8
-// so we give up on __intX for them.
-#if (_MSC_VER < 1300)
- typedef signed char int8_t;
- typedef signed short int16_t;
- typedef signed int int32_t;
- typedef unsigned char uint8_t;
- typedef unsigned short uint16_t;
- typedef unsigned int uint32_t;
-#else
- typedef signed __int8 int8_t;
- typedef signed __int16 int16_t;
- typedef signed __int32 int32_t;
- typedef unsigned __int8 uint8_t;
- typedef unsigned __int16 uint16_t;
- typedef unsigned __int32 uint32_t;
-#endif
-typedef signed __int64 int64_t;
-typedef unsigned __int64 uint64_t;
-
-
-// 7.18.1.2 Minimum-width integer types
-typedef int8_t int_least8_t;
-typedef int16_t int_least16_t;
-typedef int32_t int_least32_t;
-typedef int64_t int_least64_t;
-typedef uint8_t uint_least8_t;
-typedef uint16_t uint_least16_t;
-typedef uint32_t uint_least32_t;
-typedef uint64_t uint_least64_t;
-
-// 7.18.1.3 Fastest minimum-width integer types
-typedef int8_t int_fast8_t;
-typedef int16_t int_fast16_t;
-typedef int32_t int_fast32_t;
-typedef int64_t int_fast64_t;
-typedef uint8_t uint_fast8_t;
-typedef uint16_t uint_fast16_t;
-typedef uint32_t uint_fast32_t;
-typedef uint64_t uint_fast64_t;
-
-// 7.18.1.4 Integer types capable of holding object pointers
-#ifdef _WIN64 // [
- typedef signed __int64 intptr_t;
- typedef unsigned __int64 uintptr_t;
-#else // _WIN64 ][
- typedef _W64 signed int intptr_t;
- typedef _W64 unsigned int uintptr_t;
-#endif // _WIN64 ]
-
-// 7.18.1.5 Greatest-width integer types
-typedef int64_t intmax_t;
-typedef uint64_t uintmax_t;
-
-
-// 7.18.2 Limits of specified-width integer types
-
-#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
-
-// 7.18.2.1 Limits of exact-width integer types
-#define INT8_MIN ((int8_t)_I8_MIN)
-#define INT8_MAX _I8_MAX
-#define INT16_MIN ((int16_t)_I16_MIN)
-#define INT16_MAX _I16_MAX
-#define INT32_MIN ((int32_t)_I32_MIN)
-#define INT32_MAX _I32_MAX
-#define INT64_MIN ((int64_t)_I64_MIN)
-#define INT64_MAX _I64_MAX
-#define UINT8_MAX _UI8_MAX
-#define UINT16_MAX _UI16_MAX
-#define UINT32_MAX _UI32_MAX
-#define UINT64_MAX _UI64_MAX
-
-// 7.18.2.2 Limits of minimum-width integer types
-#define INT_LEAST8_MIN INT8_MIN
-#define INT_LEAST8_MAX INT8_MAX
-#define INT_LEAST16_MIN INT16_MIN
-#define INT_LEAST16_MAX INT16_MAX
-#define INT_LEAST32_MIN INT32_MIN
-#define INT_LEAST32_MAX INT32_MAX
-#define INT_LEAST64_MIN INT64_MIN
-#define INT_LEAST64_MAX INT64_MAX
-#define UINT_LEAST8_MAX UINT8_MAX
-#define UINT_LEAST16_MAX UINT16_MAX
-#define UINT_LEAST32_MAX UINT32_MAX
-#define UINT_LEAST64_MAX UINT64_MAX
-
-// 7.18.2.3 Limits of fastest minimum-width integer types
-#define INT_FAST8_MIN INT8_MIN
-#define INT_FAST8_MAX INT8_MAX
-#define INT_FAST16_MIN INT16_MIN
-#define INT_FAST16_MAX INT16_MAX
-#define INT_FAST32_MIN INT32_MIN
-#define INT_FAST32_MAX INT32_MAX
-#define INT_FAST64_MIN INT64_MIN
-#define INT_FAST64_MAX INT64_MAX
-#define UINT_FAST8_MAX UINT8_MAX
-#define UINT_FAST16_MAX UINT16_MAX
-#define UINT_FAST32_MAX UINT32_MAX
-#define UINT_FAST64_MAX UINT64_MAX
-
-// 7.18.2.4 Limits of integer types capable of holding object pointers
-#ifdef _WIN64 // [
-# define INTPTR_MIN INT64_MIN
-# define INTPTR_MAX INT64_MAX
-# define UINTPTR_MAX UINT64_MAX
-#else // _WIN64 ][
-# define INTPTR_MIN INT32_MIN
-# define INTPTR_MAX INT32_MAX
-# define UINTPTR_MAX UINT32_MAX
-#endif // _WIN64 ]
-
-// 7.18.2.5 Limits of greatest-width integer types
-#define INTMAX_MIN INT64_MIN
-#define INTMAX_MAX INT64_MAX
-#define UINTMAX_MAX UINT64_MAX
-
-// 7.18.3 Limits of other integer types
-
-#ifdef _WIN64 // [
-# define PTRDIFF_MIN _I64_MIN
-# define PTRDIFF_MAX _I64_MAX
-#else // _WIN64 ][
-# define PTRDIFF_MIN _I32_MIN
-# define PTRDIFF_MAX _I32_MAX
-#endif // _WIN64 ]
-
-#define SIG_ATOMIC_MIN INT_MIN
-#define SIG_ATOMIC_MAX INT_MAX
-
-#ifndef SIZE_MAX // [
-# ifdef _WIN64 // [
-# define SIZE_MAX _UI64_MAX
-# else // _WIN64 ][
-# define SIZE_MAX _UI32_MAX
-# endif // _WIN64 ]
-#endif // SIZE_MAX ]
-
-// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
-#ifndef WCHAR_MIN // [
-# define WCHAR_MIN 0
-#endif // WCHAR_MIN ]
-#ifndef WCHAR_MAX // [
-# define WCHAR_MAX _UI16_MAX
-#endif // WCHAR_MAX ]
-
-#define WINT_MIN 0
-#define WINT_MAX _UI16_MAX
-
-#endif // __STDC_LIMIT_MACROS ]
-
-
-// 7.18.4 Limits of other integer types
-
-#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
-
-// 7.18.4.1 Macros for minimum-width integer constants
-
-#define INT8_C(val) val##i8
-#define INT16_C(val) val##i16
-#define INT32_C(val) val##i32
-#define INT64_C(val) val##i64
-
-#define UINT8_C(val) val##ui8
-#define UINT16_C(val) val##ui16
-#define UINT32_C(val) val##ui32
-#define UINT64_C(val) val##ui64
-
-// 7.18.4.2 Macros for greatest-width integer constants
-#define INTMAX_C INT64_C
-#define UINTMAX_C UINT64_C
-
-#endif // __STDC_CONSTANT_MACROS ]
-
-
-#endif // _MSC_STDINT_H_ ]
+// ISO C9x compliant stdint.h for Microsoft Visual Studio
+// Based on ISO/IEC 9899:TC2 Committee draft (May 6, 2005) WG14/N1124
+//
+// Copyright (c) 2006-2013 Alexander Chemeris
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are met:
+//
+// 1. Redistributions of source code must retain the above copyright notice,
+// this list of conditions and the following disclaimer.
+//
+// 2. Redistributions in binary form must reproduce the above copyright
+// notice, this list of conditions and the following disclaimer in the
+// documentation and/or other materials provided with the distribution.
+//
+// 3. Neither the name of the product nor the names of its contributors may
+// be used to endorse or promote products derived from this software
+// without specific prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
+// WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO
+// EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+// OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+// OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+// ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+///////////////////////////////////////////////////////////////////////////////
+
+#ifndef _MSC_VER // [
+#error "Use this header only with Microsoft Visual C++ compilers!"
+#endif // _MSC_VER ]
+
+#ifndef _MSC_STDINT_H_ // [
+#define _MSC_STDINT_H_
+
+#if _MSC_VER > 1000
+#pragma once
+#endif
+
+#if _MSC_VER >= 1600 // [
+#include <stdint.h>
+#else // ] _MSC_VER >= 1600 [
+
+#include <limits.h>
+
+// For Visual Studio 6 in C++ mode and for many Visual Studio versions when
+// compiling for ARM we should wrap <wchar.h> include with 'extern "C++" {}'
+// or compiler give many errors like this:
+// error C2733: second C linkage of overloaded function 'wmemchr' not allowed
+#ifdef __cplusplus
+extern "C" {
+#endif
+# include <wchar.h>
+#ifdef __cplusplus
+}
+#endif
+
+// Define _W64 macros to mark types changing their size, like intptr_t.
+#ifndef _W64
+# if !defined(__midl) && (defined(_X86_) || defined(_M_IX86)) && _MSC_VER >= 1300
+# define _W64 __w64
+# else
+# define _W64
+# endif
+#endif
+
+
+// 7.18.1 Integer types
+
+// 7.18.1.1 Exact-width integer types
+
+// Visual Studio 6 and Embedded Visual C++ 4 doesn't
+// realize that, e.g. char has the same size as __int8
+// so we give up on __intX for them.
+#if (_MSC_VER < 1300)
+ typedef signed char int8_t;
+ typedef signed short int16_t;
+ typedef signed int int32_t;
+ typedef unsigned char uint8_t;
+ typedef unsigned short uint16_t;
+ typedef unsigned int uint32_t;
+#else
+ typedef signed __int8 int8_t;
+ typedef signed __int16 int16_t;
+ typedef signed __int32 int32_t;
+ typedef unsigned __int8 uint8_t;
+ typedef unsigned __int16 uint16_t;
+ typedef unsigned __int32 uint32_t;
+#endif
+typedef signed __int64 int64_t;
+typedef unsigned __int64 uint64_t;
+
+
+// 7.18.1.2 Minimum-width integer types
+typedef int8_t int_least8_t;
+typedef int16_t int_least16_t;
+typedef int32_t int_least32_t;
+typedef int64_t int_least64_t;
+typedef uint8_t uint_least8_t;
+typedef uint16_t uint_least16_t;
+typedef uint32_t uint_least32_t;
+typedef uint64_t uint_least64_t;
+
+// 7.18.1.3 Fastest minimum-width integer types
+typedef int8_t int_fast8_t;
+typedef int16_t int_fast16_t;
+typedef int32_t int_fast32_t;
+typedef int64_t int_fast64_t;
+typedef uint8_t uint_fast8_t;
+typedef uint16_t uint_fast16_t;
+typedef uint32_t uint_fast32_t;
+typedef uint64_t uint_fast64_t;
+
+// 7.18.1.4 Integer types capable of holding object pointers
+#ifdef _WIN64 // [
+ typedef signed __int64 intptr_t;
+ typedef unsigned __int64 uintptr_t;
+#else // _WIN64 ][
+ typedef _W64 signed int intptr_t;
+ typedef _W64 unsigned int uintptr_t;
+#endif // _WIN64 ]
+
+// 7.18.1.5 Greatest-width integer types
+typedef int64_t intmax_t;
+typedef uint64_t uintmax_t;
+
+
+// 7.18.2 Limits of specified-width integer types
+
+#if !defined(__cplusplus) || defined(__STDC_LIMIT_MACROS) // [ See footnote 220 at page 257 and footnote 221 at page 259
+
+// 7.18.2.1 Limits of exact-width integer types
+#define INT8_MIN ((int8_t)_I8_MIN)
+#define INT8_MAX _I8_MAX
+#define INT16_MIN ((int16_t)_I16_MIN)
+#define INT16_MAX _I16_MAX
+#define INT32_MIN ((int32_t)_I32_MIN)
+#define INT32_MAX _I32_MAX
+#define INT64_MIN ((int64_t)_I64_MIN)
+#define INT64_MAX _I64_MAX
+#define UINT8_MAX _UI8_MAX
+#define UINT16_MAX _UI16_MAX
+#define UINT32_MAX _UI32_MAX
+#define UINT64_MAX _UI64_MAX
+
+// 7.18.2.2 Limits of minimum-width integer types
+#define INT_LEAST8_MIN INT8_MIN
+#define INT_LEAST8_MAX INT8_MAX
+#define INT_LEAST16_MIN INT16_MIN
+#define INT_LEAST16_MAX INT16_MAX
+#define INT_LEAST32_MIN INT32_MIN
+#define INT_LEAST32_MAX INT32_MAX
+#define INT_LEAST64_MIN INT64_MIN
+#define INT_LEAST64_MAX INT64_MAX
+#define UINT_LEAST8_MAX UINT8_MAX
+#define UINT_LEAST16_MAX UINT16_MAX
+#define UINT_LEAST32_MAX UINT32_MAX
+#define UINT_LEAST64_MAX UINT64_MAX
+
+// 7.18.2.3 Limits of fastest minimum-width integer types
+#define INT_FAST8_MIN INT8_MIN
+#define INT_FAST8_MAX INT8_MAX
+#define INT_FAST16_MIN INT16_MIN
+#define INT_FAST16_MAX INT16_MAX
+#define INT_FAST32_MIN INT32_MIN
+#define INT_FAST32_MAX INT32_MAX
+#define INT_FAST64_MIN INT64_MIN
+#define INT_FAST64_MAX INT64_MAX
+#define UINT_FAST8_MAX UINT8_MAX
+#define UINT_FAST16_MAX UINT16_MAX
+#define UINT_FAST32_MAX UINT32_MAX
+#define UINT_FAST64_MAX UINT64_MAX
+
+// 7.18.2.4 Limits of integer types capable of holding object pointers
+#ifdef _WIN64 // [
+# define INTPTR_MIN INT64_MIN
+# define INTPTR_MAX INT64_MAX
+# define UINTPTR_MAX UINT64_MAX
+#else // _WIN64 ][
+# define INTPTR_MIN INT32_MIN
+# define INTPTR_MAX INT32_MAX
+# define UINTPTR_MAX UINT32_MAX
+#endif // _WIN64 ]
+
+// 7.18.2.5 Limits of greatest-width integer types
+#define INTMAX_MIN INT64_MIN
+#define INTMAX_MAX INT64_MAX
+#define UINTMAX_MAX UINT64_MAX
+
+// 7.18.3 Limits of other integer types
+
+#ifdef _WIN64 // [
+# define PTRDIFF_MIN _I64_MIN
+# define PTRDIFF_MAX _I64_MAX
+#else // _WIN64 ][
+# define PTRDIFF_MIN _I32_MIN
+# define PTRDIFF_MAX _I32_MAX
+#endif // _WIN64 ]
+
+#define SIG_ATOMIC_MIN INT_MIN
+#define SIG_ATOMIC_MAX INT_MAX
+
+#ifndef SIZE_MAX // [
+# ifdef _WIN64 // [
+# define SIZE_MAX _UI64_MAX
+# else // _WIN64 ][
+# define SIZE_MAX _UI32_MAX
+# endif // _WIN64 ]
+#endif // SIZE_MAX ]
+
+// WCHAR_MIN and WCHAR_MAX are also defined in <wchar.h>
+#ifndef WCHAR_MIN // [
+# define WCHAR_MIN 0
+#endif // WCHAR_MIN ]
+#ifndef WCHAR_MAX // [
+# define WCHAR_MAX _UI16_MAX
+#endif // WCHAR_MAX ]
+
+#define WINT_MIN 0
+#define WINT_MAX _UI16_MAX
+
+#endif // __STDC_LIMIT_MACROS ]
+
+
+// 7.18.4 Limits of other integer types
+
+#if !defined(__cplusplus) || defined(__STDC_CONSTANT_MACROS) // [ See footnote 224 at page 260
+
+// 7.18.4.1 Macros for minimum-width integer constants
+
+#define INT8_C(val) val##i8
+#define INT16_C(val) val##i16
+#define INT32_C(val) val##i32
+#define INT64_C(val) val##i64
+
+#define UINT8_C(val) val##ui8
+#define UINT16_C(val) val##ui16
+#define UINT32_C(val) val##ui32
+#define UINT64_C(val) val##ui64
+
+// 7.18.4.2 Macros for greatest-width integer constants
+// These #ifndef's are needed to prevent collisions with <boost/cstdint.hpp>.
+// Check out Issue 9 for the details.
+#ifndef INTMAX_C // [
+# define INTMAX_C INT64_C
+#endif // INTMAX_C ]
+#ifndef UINTMAX_C // [
+# define UINTMAX_C UINT64_C
+#endif // UINTMAX_C ]
+
+#endif // __STDC_CONSTANT_MACROS ]
+
+#endif // _MSC_VER >= 1600 ]
+
+#endif // _MSC_STDINT_H_ ]
diff --git a/Resources/ThirdParty/base64/base64.cpp b/Resources/ThirdParty/base64/base64.cpp
index 621c81c..33289c9 100644
--- a/Resources/ThirdParty/base64/base64.cpp
+++ b/Resources/ThirdParty/base64/base64.cpp
@@ -1,128 +1,128 @@
-/*
- base64.cpp and base64.h
-
- Copyright (C) 2004-2008 Ren� Nyffenegger
-
- This source code is provided 'as-is', without any express or implied
- warranty. In no event will the author be held liable for any damages
- arising from the use of this software.
-
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
-
- 1. The origin of this source code must not be misrepresented; you must not
- claim that you wrote the original source code. If you use this source code
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
-
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original source code.
-
- 3. This notice may not be removed or altered from any source distribution.
-
- Ren� Nyffenegger rene.nyffenegger at adp-gmbh.ch
-
-*/
-
-#include "base64.h"
-#include <string.h>
-
-static const std::string base64_chars =
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
- "abcdefghijklmnopqrstuvwxyz"
- "0123456789+/";
-
-
-static inline bool is_base64(unsigned char c) {
- return (isalnum(c) || (c == '+') || (c == '/'));
-}
-
-std::string base64_encode(const std::string& stringToEncode)
-{
- const unsigned char* bytes_to_encode = reinterpret_cast<const unsigned char*>
- (stringToEncode.size() > 0 ? &stringToEncode[0] : NULL);
- unsigned int in_len = stringToEncode.size();
-
- std::string ret;
- int i = 0;
- int j = 0;
- unsigned char char_array_3[3];
- unsigned char char_array_4[4];
-
- while (in_len--) {
- char_array_3[i++] = *(bytes_to_encode++);
- if (i == 3) {
- char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
- char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
- char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
- char_array_4[3] = char_array_3[2] & 0x3f;
-
- for(i = 0; (i <4) ; i++)
- ret += base64_chars[char_array_4[i]];
- i = 0;
- }
- }
-
- if (i)
- {
- for(j = i; j < 3; j++)
- char_array_3[j] = '\0';
-
- char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
- char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
- char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
- char_array_4[3] = char_array_3[2] & 0x3f;
-
- for (j = 0; (j < i + 1); j++)
- ret += base64_chars[char_array_4[j]];
-
- while((i++ < 3))
- ret += '=';
-
- }
-
- return ret;
-}
-
-
-std::string base64_decode(const std::string& encoded_string) {
- int in_len = encoded_string.size();
- int i = 0;
- int j = 0;
- int in_ = 0;
- unsigned char char_array_4[4], char_array_3[3];
- std::string ret;
-
- while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
- char_array_4[i++] = encoded_string[in_]; in_++;
- if (i ==4) {
- for (i = 0; i <4; i++)
- char_array_4[i] = base64_chars.find(char_array_4[i]);
-
- char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
- char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
- char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
-
- for (i = 0; (i < 3); i++)
- ret += char_array_3[i];
- i = 0;
- }
- }
-
- if (i) {
- for (j = i; j <4; j++)
- char_array_4[j] = 0;
-
- for (j = 0; j <4; j++)
- char_array_4[j] = base64_chars.find(char_array_4[j]);
-
- char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
- char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
- char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
-
- for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
- }
-
- return ret;
-}
+/*
+ base64.cpp and base64.h
+
+ Copyright (C) 2004-2008 Ren� Nyffenegger
+
+ This source code is provided 'as-is', without any express or implied
+ warranty. In no event will the author be held liable for any damages
+ arising from the use of this software.
+
+ Permission is granted to anyone to use this software for any purpose,
+ including commercial applications, and to alter it and redistribute it
+ freely, subject to the following restrictions:
+
+ 1. The origin of this source code must not be misrepresented; you must not
+ claim that you wrote the original source code. If you use this source code
+ in a product, an acknowledgment in the product documentation would be
+ appreciated but is not required.
+
+ 2. Altered source versions must be plainly marked as such, and must not be
+ misrepresented as being the original source code.
+
+ 3. This notice may not be removed or altered from any source distribution.
+
+ Ren� Nyffenegger rene.nyffenegger at adp-gmbh.ch
+
+*/
+
+#include "base64.h"
+#include <string.h>
+
+static const std::string base64_chars =
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+ "abcdefghijklmnopqrstuvwxyz"
+ "0123456789+/";
+
+
+static inline bool is_base64(unsigned char c) {
+ return (isalnum(c) || (c == '+') || (c == '/'));
+}
+
+std::string base64_encode(const std::string& stringToEncode)
+{
+ const unsigned char* bytes_to_encode = reinterpret_cast<const unsigned char*>
+ (stringToEncode.size() > 0 ? &stringToEncode[0] : NULL);
+ unsigned int in_len = stringToEncode.size();
+
+ std::string ret;
+ int i = 0;
+ int j = 0;
+ unsigned char char_array_3[3];
+ unsigned char char_array_4[4];
+
+ while (in_len--) {
+ char_array_3[i++] = *(bytes_to_encode++);
+ if (i == 3) {
+ char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+ char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+ char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+ char_array_4[3] = char_array_3[2] & 0x3f;
+
+ for(i = 0; (i <4) ; i++)
+ ret += base64_chars[char_array_4[i]];
+ i = 0;
+ }
+ }
+
+ if (i)
+ {
+ for(j = i; j < 3; j++)
+ char_array_3[j] = '\0';
+
+ char_array_4[0] = (char_array_3[0] & 0xfc) >> 2;
+ char_array_4[1] = ((char_array_3[0] & 0x03) << 4) + ((char_array_3[1] & 0xf0) >> 4);
+ char_array_4[2] = ((char_array_3[1] & 0x0f) << 2) + ((char_array_3[2] & 0xc0) >> 6);
+ char_array_4[3] = char_array_3[2] & 0x3f;
+
+ for (j = 0; (j < i + 1); j++)
+ ret += base64_chars[char_array_4[j]];
+
+ while((i++ < 3))
+ ret += '=';
+
+ }
+
+ return ret;
+}
+
+
+std::string base64_decode(const std::string& encoded_string) {
+ int in_len = encoded_string.size();
+ int i = 0;
+ int j = 0;
+ int in_ = 0;
+ unsigned char char_array_4[4], char_array_3[3];
+ std::string ret;
+
+ while (in_len-- && ( encoded_string[in_] != '=') && is_base64(encoded_string[in_])) {
+ char_array_4[i++] = encoded_string[in_]; in_++;
+ if (i ==4) {
+ for (i = 0; i <4; i++)
+ char_array_4[i] = base64_chars.find(char_array_4[i]);
+
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+ for (i = 0; (i < 3); i++)
+ ret += char_array_3[i];
+ i = 0;
+ }
+ }
+
+ if (i) {
+ for (j = i; j <4; j++)
+ char_array_4[j] = 0;
+
+ for (j = 0; j <4; j++)
+ char_array_4[j] = base64_chars.find(char_array_4[j]);
+
+ char_array_3[0] = (char_array_4[0] << 2) + ((char_array_4[1] & 0x30) >> 4);
+ char_array_3[1] = ((char_array_4[1] & 0xf) << 4) + ((char_array_4[2] & 0x3c) >> 2);
+ char_array_3[2] = ((char_array_4[2] & 0x3) << 6) + char_array_4[3];
+
+ for (j = 0; (j < i - 1); j++) ret += char_array_3[j];
+ }
+
+ return ret;
+}
diff --git a/Resources/ThirdParty/base64/base64.h b/Resources/ThirdParty/base64/base64.h
index acdaecd..5e62f1a 100644
--- a/Resources/ThirdParty/base64/base64.h
+++ b/Resources/ThirdParty/base64/base64.h
@@ -1,4 +1,4 @@
-#include <string>
-
-std::string base64_encode(const std::string& stringToEncode);
-std::string base64_decode(const std::string& s);
+#include <string>
+
+std::string base64_encode(const std::string& stringToEncode);
+std::string base64_decode(const std::string& s);
diff --git a/THANKS b/THANKS
deleted file mode 100644
index e6d96b6..0000000
--- a/THANKS
+++ /dev/null
@@ -1,65 +0,0 @@
-Orthanc - A Lightweight, RESTful DICOM Server
-=============================================
-
-Orthanc has originally been written by Sebastien Jodogne
-(cf. "AUTHORS" file). This file contains the list of the people that
-have further contributed to Orthanc by reporting problems, suggesting
-various improvements, or submitting actual code. Please help keep it
-complete and exempt or errors.
-
-
-Contributors
-------------
-
-* Cyril Paulus <cyril.paulus at student.ulg.ac.be>, for the build process
- and suggestions about the REST API.
-* Will Ryder <will.ryder at sydney.edu.au>, for improvements with the
- handling of series with temporal positions (fMRI and dynamic PET).
-* Ryan Walklin <ryanwalklin at gmail.com>, for Mac OS X build.
-* Peter Somlo <peter.somlo at gmail.com>, for ClearCanvas and JPEG support.
-* 12maksqwe at gmail.com, for fixing issue #8.
-* Julien Nabet, for various suggestions to improve the source code.
-* Karsten Hilbert <Karsten.Hilbert at gmx.net>, for in-depth testing.
-* Marek Swiecicki <mswiecicki at archimedic.pl>, for various suggestions
- and sample DICOM files.
-* Chris Hafey <chafey at gmail.com>, for suggesting many features and
- improvements, for a Windows service+installer with .NET/NSIS.
-* Manabu Tokunaga <manabu at lury.net>, for a Windows service with .NET.
-* Vincent Kersten <vincent1234567 at gmail.com>, for DICOMDIR in the GUI.
-* Emsy Chan <emlscs at yahoo.com>, for various contributions
- and sample DICOM files.
-
-
-Thanks also to all the contributors active in our Google Group:
-https://groups.google.com/forum/#!forum/orthanc-users
-
-
-Debian/Ubuntu
--------------
-
-* Mathieu Malaterre <mathieu.malaterre at gmail.com>, for sponsoring Orthanc.
-* Andreas Tille <andreas at an3as.eu>, for help about packaging.
-* Adam Conrad <adconrad at debian.org>, to improve support of big endianness.
-
-
-Fedora and Red Hat
-------------------
-
-* Mario Ceresa <mrceresa at gmail.com>, for help about packaging.
-
-
-FreeBSD
--------
-
-* Mikhail <mp39590 at gmail.com>, for FreeBSD packaging.
-
-
-Artwork
--------
-
-https://code.google.com/p/orthanc/wiki/Logos
-
-* Benjamin Golinvaux <golinvauxb at gmail.com>, for creating the official logo.
-* Jean-François Degbomont <jfdegbo at gmail.com>, for submitting a logo.
-* Martin Jolly <martin.jolly at gmail.com>, for submitting a logo.
-* Philippe Sepers <sepers.philippe at gmail.com>, for submitting a logo.
diff --git a/TODO b/TODO
new file mode 100644
index 0000000..7b2aa1c
--- /dev/null
+++ b/TODO
@@ -0,0 +1,152 @@
+=======================
+=== Orthanc Roadmap ===
+=======================
+
+The wishlist from Orthanc users is available on Trello:
+https://trello.com/b/gcn33tDM/orthanc-wishlist
+
+
+=======
+General
+=======
+
+* Configure an user-defined site UID root if generating DICOM UIDs
+ ("FromDcmtkBridge::GenerateUuid()")
+* Support "/preview" and "/matlab" for LUT color images
+* Improve handling of errors in the command queue:
+ https://groups.google.com/d/msg/orthanc-users/--njEbqcDDI/rBu8XL-Mm-cJ
+* Support partial file retrieval in Orthanc::HttpClient
+* Support retry counter in Orthanc::HttpClient
+
+
+========
+REST API
+========
+
+----------
+Short-term
+----------
+
+* Create multi-frame images with /tools/create-dicom (by adding a
+ "MultiFrame" flag to avoid creating a series)
+
+---------
+Long-term
+---------
+
+* Stick to the JSONapi or JAREST guidelines for a "v2" of the API:
+ https://groups.google.com/forum/#!msg/orthanc-users/Bag-SwEE9ZI/-w7QXI6p7-oJ
+ http://www.admiraalit.nl/jarest/
+
+
+=====
+DICOM
+=====
+
+----------
+Short-term
+----------
+
+* Support C-GET:
+ http://dclunie.blogspot.be/2016/05/to-c-move-is-human-to-c-get-divine.html
+* Check Big Endian transfer syntax in ParsedDicomFile::EmbedImage and
+ DicomImageDecoder
+
+---------
+Long-term
+---------
+
+* Support DICOM TLS (cf. "--enable-tls" in storescp)
+* Support Storage Commitment:
+ https://groups.google.com/forum/#!msg/orthanc-users/VZOn8St65jw/s8kg_OHesj0J
+
+
+=======
+Plugins
+=======
+
+---
+SDK
+---
+
+* Image transcoding API
+* Add plugins for normalized operations (notably so as to support
+ Print SCU/SCP):
+ https://www.medicalconnections.co.uk/kb/DICOM_Print_Service
+
+----------------
+Ideas of plugins
+----------------
+
+* DICOM-RT primitives (RT-STRUCT, RT-PLAN, RT-DOSE)
+* Converter to/from NIfTI
+* MySQL database plugin
+* Decode JPEG2k with grok: https://github.com/GrokImageCompression/grok
+* Generate dynamic content using Lua:
+ https://groups.google.com/d/msg/orthanc-users/KompazkxRSs/5Rh03mzgDAAJ
+
+
+===
+Lua
+===
+
+* Configure HTTP headers from Lua (in HttpGet(), HttpPost(),
+ HttpPut(), HttpDelete(), RestApiGet(), RestApiPost(), RestApiPut()
+ and RestApiDelete().
+ https://groups.google.com/forum/#!msg/orthanc-users/WNnW187OILM/6XX_bm96BwAJ
+
+
+===========
+Performance
+===========
+
+
+============
+Orthanc Book
+============
+
+* Document Lua C-FIND filters (cf. "IncomingFindRequestFilter()")
+
+
+================
+Code refactoring
+================
+
+* Use Semaphore::Locker everywhere (instead of explicit
+ Release() and Acquire())
+* Avoid direct calls to FromDcmtkBridge (make most of its
+ methods private), go through ParsedDicomFile wherever possible
+
+
+=================
+Platform-specific
+=================
+
+---------
+Packaging
+---------
+
+* CentOS and RHEL through EPEL:
+ http://fedoraproject.org/wiki/EPEL_Package_Maintainers
+
+------------------------
+Big-endian architectures
+------------------------
+
+* Check the generated 16bpp PNG images
+
+-----------------
+Microsoft Windows
+-----------------
+
+* Add compatibility with non-ASCII paths (Orthanc expresses its paths
+ as UTF-8 strings, but Windows expects them to be translated to the
+ system locale)
+
+
+=====================
+External applications
+=====================
+
+* Create REST bindings with Slicer
+* Create REST bindings with Horos/OsiriX
diff --git a/UnitTestsSources/DicomMapTests.cpp b/UnitTestsSources/DicomMapTests.cpp
index d3a4474..34245a0 100644
--- a/UnitTestsSources/DicomMapTests.cpp
+++ b/UnitTestsSources/DicomMapTests.cpp
@@ -33,7 +33,6 @@
#include "PrecompiledHeadersUnitTests.h"
#include "gtest/gtest.h"
-#include "../Core/Uuid.h"
#include "../Core/OrthancException.h"
#include "../Core/DicomFormat/DicomMap.h"
#include "../OrthancServer/FromDcmtkBridge.h"
@@ -204,7 +203,7 @@ static void TestModule(ResourceType level,
if (!ok)
{
- std::cout << it->Format() << ": " << FromDcmtkBridge::GetName(*it)
+ std::cout << it->Format() << ": " << FromDcmtkBridge::GetTagName(*it, "")
<< " not expected at level " << EnumerationToString(level) << std::endl;
}
diff --git a/UnitTestsSources/FileStorageTests.cpp b/UnitTestsSources/FileStorageTests.cpp
index 6c9ef75..cabe267 100644
--- a/UnitTestsSources/FileStorageTests.cpp
+++ b/UnitTestsSources/FileStorageTests.cpp
@@ -42,7 +42,6 @@
#include "../Core/Logging.h"
#include "../Core/OrthancException.h"
#include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
#include "../OrthancServer/ServerIndex.h"
using namespace Orthanc;
@@ -61,8 +60,8 @@ TEST(FilesystemStorage, Basic)
{
FilesystemStorage s("UnitTestsStorage");
- std::string data = Toolbox::GenerateUuid();
- std::string uid = Toolbox::GenerateUuid();
+ std::string data = SystemToolbox::GenerateUuid();
+ std::string uid = SystemToolbox::GenerateUuid();
s.Create(uid.c_str(), &data[0], data.size(), FileContentType_Unknown);
std::string d;
s.Read(d, uid, FileContentType_Unknown);
@@ -76,8 +75,8 @@ TEST(FilesystemStorage, Basic2)
FilesystemStorage s("UnitTestsStorage");
std::vector<uint8_t> data;
- StringToVector(data, Toolbox::GenerateUuid());
- std::string uid = Toolbox::GenerateUuid();
+ StringToVector(data, SystemToolbox::GenerateUuid());
+ std::string uid = SystemToolbox::GenerateUuid();
s.Create(uid.c_str(), &data[0], data.size(), FileContentType_Unknown);
std::string d;
s.Read(d, uid, FileContentType_Unknown);
@@ -94,8 +93,8 @@ TEST(FilesystemStorage, EndToEnd)
std::list<std::string> u;
for (unsigned int i = 0; i < 10; i++)
{
- std::string t = Toolbox::GenerateUuid();
- std::string uid = Toolbox::GenerateUuid();
+ std::string t = SystemToolbox::GenerateUuid();
+ std::string uid = SystemToolbox::GenerateUuid();
s.Create(uid.c_str(), &t[0], t.size(), FileContentType_Unknown);
u.push_back(uid);
}
diff --git a/UnitTestsSources/FromDcmtkTests.cpp b/UnitTestsSources/FromDcmtkTests.cpp
index f35bdda..939e057 100644
--- a/UnitTestsSources/FromDcmtkTests.cpp
+++ b/UnitTestsSources/FromDcmtkTests.cpp
@@ -44,7 +44,6 @@
#include "../Core/Images/PngWriter.h"
#include "../Core/Images/Image.h"
#include "../Core/Images/ImageProcessing.h"
-#include "../Core/Uuid.h"
#include "../Core/Endianness.h"
#include "../Resources/EncodingTests.h"
#include "../OrthancServer/DicomProtocol/DicomFindAnswers.h"
@@ -52,12 +51,13 @@
#include "../Plugins/Engine/PluginsEnumerations.h"
#include <dcmtk/dcmdata/dcelem.h>
+#include <dcmtk/dcmdata/dcdeftag.h>
using namespace Orthanc;
TEST(DicomFormat, Tag)
{
- ASSERT_EQ("PatientName", FromDcmtkBridge::GetName(DicomTag(0x0010, 0x0010)));
+ ASSERT_EQ("PatientName", FromDcmtkBridge::GetTagName(DicomTag(0x0010, 0x0010), ""));
DicomTag t = FromDcmtkBridge::ParseTag("SeriesDescription");
ASSERT_EQ(0x0008, t.GetGroup());
@@ -226,7 +226,7 @@ TEST(FromDcmtkBridge, Enumerations)
Encoding e;
ASSERT_FALSE(GetDicomEncoding(e, ""));
- ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 6")); ASSERT_EQ(Encoding_Utf8, e);
+ ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 6")); ASSERT_EQ(Encoding_Ascii, e);
// http://dicom.nema.org/medical/dicom/current/output/html/part03.html#table_C.12-2
ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 100")); ASSERT_EQ(Encoding_Latin1, e);
@@ -242,7 +242,7 @@ TEST(FromDcmtkBridge, Enumerations)
ASSERT_TRUE(GetDicomEncoding(e, "ISO_IR 166")); ASSERT_EQ(Encoding_Thai, e);
// http://dicom.nema.org/medical/dicom/current/output/html/part03.html#table_C.12-3
- ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 6")); ASSERT_EQ(Encoding_Utf8, e);
+ ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 6")); ASSERT_EQ(Encoding_Ascii, e);
ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 100")); ASSERT_EQ(Encoding_Latin1, e);
ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 101")); ASSERT_EQ(Encoding_Latin2, e);
ASSERT_TRUE(GetDicomEncoding(e, "ISO 2022 IR 109")); ASSERT_EQ(Encoding_Latin3, e);
@@ -380,81 +380,85 @@ static void CreateSampleJson(Json::Value& a)
}
-TEST(FromDcmtkBridge, FromJson)
+namespace Orthanc
{
- std::auto_ptr<DcmElement> element;
-
- {
- Json::Value a;
- a = "Hello";
- element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8));
-
- Json::Value b;
- FromDcmtkBridge::ToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
- ASSERT_EQ("Hello", b["0010,0010"].asString());
- }
-
+ // Namespace for the "FRIEND_TEST()" directive in "FromDcmtkBridge" to apply:
+ // https://github.com/google/googletest/blob/master/googletest/docs/AdvancedGuide.md#private-class-members
+ TEST(FromDcmtkBridge, FromJson)
{
- Json::Value a;
- a = "Hello";
- // Cannot assign a string to a sequence
- ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, false, Encoding_Utf8)), OrthancException);
- }
+ std::auto_ptr<DcmElement> element;
- {
- Json::Value a = Json::arrayValue;
- a.append("Hello");
- // Cannot assign an array to a string
- ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8)), OrthancException);
- }
+ {
+ Json::Value a;
+ a = "Hello";
+ element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8));
- {
- Json::Value a;
- a = "data:application/octet-stream;base64,SGVsbG8="; // echo -n "Hello" | base64
- element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, true, Encoding_Utf8));
+ Json::Value b;
+ FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+ ASSERT_EQ("Hello", b["0010,0010"].asString());
+ }
- Json::Value b;
- FromDcmtkBridge::ToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
- ASSERT_EQ("Hello", b["0010,0010"].asString());
- }
+ {
+ Json::Value a;
+ a = "Hello";
+ // Cannot assign a string to a sequence
+ ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, false, Encoding_Utf8)), OrthancException);
+ }
- {
- Json::Value a = Json::arrayValue;
- CreateSampleJson(a);
- element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, true, Encoding_Utf8));
+ {
+ Json::Value a = Json::arrayValue;
+ a.append("Hello");
+ // Cannot assign an array to a string
+ ASSERT_THROW(element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, false, Encoding_Utf8)), OrthancException);
+ }
{
+ Json::Value a;
+ a = "data:application/octet-stream;base64,SGVsbG8="; // echo -n "Hello" | base64
+ element.reset(FromDcmtkBridge::FromJson(DICOM_TAG_PATIENT_NAME, a, true, Encoding_Utf8));
+
Json::Value b;
- FromDcmtkBridge::ToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
- ASSERT_EQ(Json::arrayValue, b["0008,1110"].type());
- ASSERT_EQ(2u, b["0008,1110"].size());
-
- Json::Value::ArrayIndex i = (b["0008,1110"][0]["0010,0010"].asString() == "Hello") ? 0 : 1;
-
- ASSERT_EQ(3u, b["0008,1110"][i].size());
- ASSERT_EQ(2u, b["0008,1110"][1 - i].size());
- ASSERT_EQ(b["0008,1110"][i]["0010,0010"].asString(), "Hello");
- ASSERT_EQ(b["0008,1110"][i]["0010,0020"].asString(), "World");
- ASSERT_EQ(b["0008,1110"][i]["0008,1030"].asString(), "Toto");
- ASSERT_EQ(b["0008,1110"][1 - i]["0010,0010"].asString(), "Hello2");
- ASSERT_EQ(b["0008,1110"][1 - i]["0010,0020"].asString(), "World2");
+ FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+ ASSERT_EQ("Hello", b["0010,0010"].asString());
}
{
- Json::Value b;
- FromDcmtkBridge::ToJson(b, *element, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+ Json::Value a = Json::arrayValue;
+ CreateSampleJson(a);
+ element.reset(FromDcmtkBridge::FromJson(REFERENCED_STUDY_SEQUENCE, a, true, Encoding_Utf8));
+
+ {
+ Json::Value b;
+ FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Short, DicomToJsonFlags_Default, 0, Encoding_Ascii);
+ ASSERT_EQ(Json::arrayValue, b["0008,1110"].type());
+ ASSERT_EQ(2u, b["0008,1110"].size());
+
+ Json::Value::ArrayIndex i = (b["0008,1110"][0]["0010,0010"].asString() == "Hello") ? 0 : 1;
+
+ ASSERT_EQ(3u, b["0008,1110"][i].size());
+ ASSERT_EQ(2u, b["0008,1110"][1 - i].size());
+ ASSERT_EQ(b["0008,1110"][i]["0010,0010"].asString(), "Hello");
+ ASSERT_EQ(b["0008,1110"][i]["0010,0020"].asString(), "World");
+ ASSERT_EQ(b["0008,1110"][i]["0008,1030"].asString(), "Toto");
+ ASSERT_EQ(b["0008,1110"][1 - i]["0010,0010"].asString(), "Hello2");
+ ASSERT_EQ(b["0008,1110"][1 - i]["0010,0020"].asString(), "World2");
+ }
+
+ {
+ Json::Value b;
+ FromDcmtkBridge::ElementToJson(b, *element, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0, Encoding_Ascii);
- Json::Value c;
- Toolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);
+ Json::Value c;
+ ServerToolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);
- a[1]["PatientName"] = "Hello2"; // To remove the Data URI Scheme encoding
- ASSERT_EQ(0, c["ReferencedStudySequence"].compare(a));
+ a[1]["PatientName"] = "Hello2"; // To remove the Data URI Scheme encoding
+ ASSERT_EQ(0, c["ReferencedStudySequence"].compare(a));
+ }
}
}
}
-
TEST(ParsedDicomFile, InsertReplaceStrings)
{
ParsedDicomFile f(true);
@@ -465,6 +469,7 @@ TEST(ParsedDicomFile, InsertReplaceStrings)
f.ReplacePlainString(DICOM_TAG_SOP_CLASS_UID, "Tata"); // (**)
std::string s;
+ ASSERT_FALSE(f.LookupTransferSyntax(s));
ASSERT_THROW(f.Replace(DICOM_TAG_ACCESSION_NUMBER, std::string("Accession"),
false, DicomReplaceMode_ThrowIfAbsent), OrthancException);
@@ -522,10 +527,10 @@ TEST(ParsedDicomFile, InsertReplaceJson)
{
Json::Value b;
- f.ToJson(b, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0);
+ f.DatasetToJson(b, DicomToJsonFormat_Full, DicomToJsonFlags_Default, 0);
Json::Value c;
- Toolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);
+ ServerToolbox::SimplifyTags(c, b, DicomToJsonFormat_Human);
ASSERT_EQ(0, c["ReferencedPatientSequence"].compare(a));
ASSERT_NE(0, c["ReferencedStudySequence"].compare(a)); // Because Data URI Scheme decoding was enabled
@@ -567,7 +572,7 @@ TEST(ParsedDicomFile, JsonEncoding)
f.Replace(DICOM_TAG_PATIENT_NAME, s, false, DicomReplaceMode_InsertIfAbsent);
Json::Value v;
- f.ToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
ASSERT_EQ(v["PatientName"].asString(), std::string(testEncodingsExpected[i]));
}
}
@@ -576,8 +581,8 @@ TEST(ParsedDicomFile, JsonEncoding)
TEST(ParsedDicomFile, ToJsonFlags1)
{
- FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7053, 0x1000), ValueRepresentation_PersonName, "MyPrivateTag", 1, 1);
- FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PersonName, "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
@@ -585,7 +590,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
f.Insert(DicomTag(0x7053, 0x1000), "Some private tag", false); // Odd group => private tag
Json::Value v;
- f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(6u, v.getMemberNames().size());
ASSERT_FALSE(v.isMember("7052,1000"));
@@ -594,7 +599,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
ASSERT_EQ(Json::stringValue, v["7050,1000"].type());
ASSERT_EQ("Some public tag", v["7050,1000"].asString());
- f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(7u, v.getMemberNames().size());
ASSERT_FALSE(v.isMember("7052,1000"));
@@ -603,7 +608,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
ASSERT_EQ("Some public tag", v["7050,1000"].asString());
ASSERT_EQ(Json::nullValue, v["7053,1000"].type());
- f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePrivateTags, 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePrivateTags, 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(7u, v.getMemberNames().size());
ASSERT_FALSE(v.isMember("7052,1000"));
@@ -616,7 +621,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
ASSERT_EQ("application/octet-stream", mime);
ASSERT_EQ("Some private tag", content);
- f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(7u, v.getMemberNames().size());
ASSERT_TRUE(v.isMember("7050,1000"));
@@ -625,7 +630,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
ASSERT_EQ("Some public tag", v["7050,1000"].asString());
ASSERT_EQ(Json::nullValue, v["7052,1000"].type());
- f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags), 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags), 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(7u, v.getMemberNames().size());
ASSERT_TRUE(v.isMember("7050,1000"));
@@ -637,7 +642,7 @@ TEST(ParsedDicomFile, ToJsonFlags1)
ASSERT_EQ("application/octet-stream", mime);
ASSERT_EQ("Some unknown tag", content);
- f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludeUnknownTags | DicomToJsonFlags_IncludePrivateTags | DicomToJsonFlags_ConvertBinaryToNull), 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(8u, v.getMemberNames().size());
ASSERT_TRUE(v.isMember("7050,1000"));
@@ -655,25 +660,25 @@ TEST(ParsedDicomFile, ToJsonFlags2)
f.Insert(DICOM_TAG_PIXEL_DATA, "Pixels", false);
Json::Value v;
- f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_None, 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(5u, v.getMemberNames().size());
ASSERT_FALSE(v.isMember("7fe0,0010"));
- f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData | DicomToJsonFlags_ConvertBinaryToNull), 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData | DicomToJsonFlags_ConvertBinaryToNull), 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(6u, v.getMemberNames().size());
ASSERT_TRUE(v.isMember("7fe0,0010"));
ASSERT_EQ(Json::nullValue, v["7fe0,0010"].type());
- f.ToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData | DicomToJsonFlags_ConvertBinaryToAscii), 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData | DicomToJsonFlags_ConvertBinaryToAscii), 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(6u, v.getMemberNames().size());
ASSERT_TRUE(v.isMember("7fe0,0010"));
ASSERT_EQ(Json::stringValue, v["7fe0,0010"].type());
ASSERT_EQ("Pixels", v["7fe0,0010"].asString());
- f.ToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePixelData, 0);
+ f.DatasetToJson(v, DicomToJsonFormat_Short, DicomToJsonFlags_IncludePixelData, 0);
ASSERT_EQ(Json::objectValue, v.type());
ASSERT_EQ(6u, v.getMemberNames().size());
ASSERT_TRUE(v.isMember("7fe0,0010"));
@@ -687,7 +692,7 @@ TEST(ParsedDicomFile, ToJsonFlags2)
TEST(DicomFindAnswers, Basic)
{
- DicomFindAnswers a;
+ DicomFindAnswers a(false);
{
DicomMap m;
@@ -717,13 +722,17 @@ TEST(DicomFindAnswers, Basic)
TEST(ParsedDicomFile, FromJson)
{
- 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_PersonName, "Declared public tag", 1, 1);
+ FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7057, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag2", 1, 1, "ORTHANC");
+ FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7059, 0x1000), ValueRepresentation_OtherByte, "MyPrivateTag3", 1, 1, "");
+ FromDcmtkBridge::RegisterDictionaryTag(DicomTag(0x7050, 0x1000), ValueRepresentation_PersonName, "Declared public tag2", 1, 1, "");
Json::Value v;
const std::string sopClassUid = "1.2.840.10008.5.1.4.1.1.1"; // CR Image Storage:
+ // Test the private creator
+ ASSERT_EQ(DcmTag_ERROR_TagName, FromDcmtkBridge::GetTagName(DicomTag(0x7057, 0x1000), "NOPE"));
+ ASSERT_EQ("MyPrivateTag2", FromDcmtkBridge::GetTagName(DicomTag(0x7057, 0x1000), "ORTHANC"));
+
{
v["SOPClassUID"] = sopClassUid;
v["SpecificCharacterSet"] = "ISO_IR 148"; // This is latin-5
@@ -760,7 +769,7 @@ TEST(ParsedDicomFile, FromJson)
(ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_GenerateIdentifiers)));
Json::Value vv;
- dicom->ToJson(vv, DicomToJsonFormat_Human, toJsonFlags, 0);
+ dicom->DatasetToJson(vv, DicomToJsonFormat_Human, toJsonFlags, 0);
ASSERT_EQ(vv["SOPClassUID"].asString(), sopClassUid);
ASSERT_EQ(vv["MediaStorageSOPClassUID"].asString(), sopClassUid);
@@ -776,7 +785,7 @@ TEST(ParsedDicomFile, FromJson)
(ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_GenerateIdentifiers)));
Json::Value vv;
- dicom->ToJson(vv, DicomToJsonFormat_Human, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData), 0);
+ dicom->DatasetToJson(vv, DicomToJsonFormat_Human, static_cast<DicomToJsonFlags>(DicomToJsonFlags_IncludePixelData), 0);
std::string mime, content;
ASSERT_TRUE(Toolbox::DecodeDataUriScheme(mime, content, vv["PixelData"].asString()));
@@ -790,7 +799,7 @@ TEST(ParsedDicomFile, FromJson)
(ParsedDicomFile::CreateFromJson(v, static_cast<DicomFromJsonFlags>(DicomFromJsonFlags_DecodeDataUriScheme)));
Json::Value vv;
- dicom->ToJson(vv, DicomToJsonFormat_Short, toJsonFlags, 0);
+ dicom->DatasetToJson(vv, DicomToJsonFormat_Short, toJsonFlags, 0);
ASSERT_FALSE(vv.isMember("SOPInstanceUID"));
ASSERT_FALSE(vv.isMember("SeriesInstanceUID"));
@@ -818,7 +827,7 @@ TEST(TestImages, PatternGrayscale8)
{
static const char* PATH = "UnitTestsResults/PatternGrayscale8.dcm";
- Orthanc::Image image(Orthanc::PixelFormat_Grayscale8, 256, 256);
+ Orthanc::Image image(Orthanc::PixelFormat_Grayscale8, 256, 256, false);
for (int y = 0; y < 256; y++)
{
@@ -849,7 +858,7 @@ TEST(TestImages, PatternGrayscale8)
{
std::string s;
- Orthanc::Toolbox::ReadFile(s, PATH);
+ Orthanc::SystemToolbox::ReadFile(s, PATH);
Orthanc::ParsedDicomFile f(s);
std::auto_ptr<Orthanc::ImageAccessor> decoded(Orthanc::DicomImageDecoder::Decode(f, 0));
@@ -871,7 +880,7 @@ TEST(TestImages, PatternRGB)
{
static const char* PATH = "UnitTestsResults/PatternRGB24.dcm";
- Orthanc::Image image(Orthanc::PixelFormat_RGB24, 384, 256);
+ Orthanc::Image image(Orthanc::PixelFormat_RGB24, 384, 256, false);
for (int y = 0; y < 256; y++)
{
@@ -911,7 +920,7 @@ TEST(TestImages, PatternRGB)
{
std::string s;
- Orthanc::Toolbox::ReadFile(s, PATH);
+ Orthanc::SystemToolbox::ReadFile(s, PATH);
Orthanc::ParsedDicomFile f(s);
std::auto_ptr<Orthanc::ImageAccessor> decoded(Orthanc::DicomImageDecoder::Decode(f, 0));
@@ -933,7 +942,7 @@ TEST(TestImages, PatternUint16)
{
static const char* PATH = "UnitTestsResults/PatternGrayscale16.dcm";
- Orthanc::Image image(Orthanc::PixelFormat_Grayscale16, 256, 256);
+ Orthanc::Image image(Orthanc::PixelFormat_Grayscale16, 256, 256, false);
uint16_t v = 0;
for (int y = 0; y < 256; y++)
@@ -965,7 +974,7 @@ TEST(TestImages, PatternUint16)
{
std::string s;
- Orthanc::Toolbox::ReadFile(s, PATH);
+ Orthanc::SystemToolbox::ReadFile(s, PATH);
Orthanc::ParsedDicomFile f(s);
std::auto_ptr<Orthanc::ImageAccessor> decoded(Orthanc::DicomImageDecoder::Decode(f, 0));
@@ -987,7 +996,7 @@ TEST(TestImages, PatternInt16)
{
static const char* PATH = "UnitTestsResults/PatternSignedGrayscale16.dcm";
- Orthanc::Image image(Orthanc::PixelFormat_SignedGrayscale16, 256, 256);
+ Orthanc::Image image(Orthanc::PixelFormat_SignedGrayscale16, 256, 256, false);
int16_t v = -32768;
for (int y = 0; y < 256; y++)
@@ -1019,7 +1028,7 @@ TEST(TestImages, PatternInt16)
{
std::string s;
- Orthanc::Toolbox::ReadFile(s, PATH);
+ Orthanc::SystemToolbox::ReadFile(s, PATH);
Orthanc::ParsedDicomFile f(s);
std::auto_ptr<Orthanc::ImageAccessor> decoded(Orthanc::DicomImageDecoder::Decode(f, 0));
@@ -1035,3 +1044,175 @@ TEST(TestImages, PatternInt16)
}
}
}
+
+
+
+static void CheckEncoding(const ParsedDicomFile& dicom,
+ Encoding expected)
+{
+ const char* value = NULL;
+ ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->findAndGetString(DCM_SpecificCharacterSet, value).good());
+
+ Encoding encoding;
+ ASSERT_TRUE(GetDicomEncoding(encoding, value));
+ ASSERT_EQ(expected, encoding);
+}
+
+
+TEST(ParsedDicomFile, DicomMapEncodings1)
+{
+ Configuration::SetDefaultEncoding(Encoding_Ascii);
+ ASSERT_EQ(Encoding_Ascii, Configuration::GetDefaultEncoding());
+
+ {
+ DicomMap m;
+ ParsedDicomFile dicom(m);
+ ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+ CheckEncoding(dicom, Encoding_Ascii);
+ }
+
+ {
+ DicomMap m;
+ ParsedDicomFile dicom(m, Encoding_Latin4);
+ ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+ CheckEncoding(dicom, Encoding_Latin4);
+ }
+
+ {
+ DicomMap m;
+ m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, "ISO_IR 148", false);
+ ParsedDicomFile dicom(m);
+ ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+ CheckEncoding(dicom, Encoding_Latin5);
+ }
+
+ {
+ DicomMap m;
+ m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, "ISO_IR 148", false);
+ ParsedDicomFile dicom(m, Encoding_Latin1);
+ ASSERT_EQ(1, dicom.GetDcmtkObject().getDataset()->card());
+ CheckEncoding(dicom, Encoding_Latin5);
+ }
+}
+
+
+TEST(ParsedDicomFile, DicomMapEncodings2)
+{
+ const char* utf8 = NULL;
+ for (unsigned int i = 0; i < testEncodingsCount; i++)
+ {
+ if (testEncodings[i] == Encoding_Utf8)
+ {
+ utf8 = testEncodingsEncoded[i];
+ break;
+ }
+ }
+
+ ASSERT_TRUE(utf8 != NULL);
+
+ for (unsigned int i = 0; i < testEncodingsCount; i++)
+ {
+ // 1251 codepage is not supported by the core DICOM standard, ignore it
+ if (testEncodings[i] != Encoding_Windows1251)
+ {
+ {
+ // Sanity check to test the proper behavior of "EncodingTests.py"
+ std::string encoded = Toolbox::ConvertFromUtf8(testEncodingsExpected[i], testEncodings[i]);
+ ASSERT_STREQ(testEncodingsEncoded[i], encoded.c_str());
+ std::string decoded = Toolbox::ConvertToUtf8(encoded, testEncodings[i]);
+ ASSERT_STREQ(testEncodingsExpected[i], decoded.c_str());
+
+ if (testEncodings[i] != Encoding_Chinese)
+ {
+ // A specific source string is used in "EncodingTests.py" to
+ // test against Chinese, it is normal that it does not correspond to UTF8
+
+ std::string encoded = Toolbox::ConvertToUtf8(Toolbox::ConvertFromUtf8(utf8, testEncodings[i]), testEncodings[i]);
+ ASSERT_STREQ(testEncodingsExpected[i], encoded.c_str());
+ }
+ }
+
+
+ Json::Value v;
+
+ {
+ DicomMap m;
+ m.SetValue(DICOM_TAG_PATIENT_NAME, testEncodingsExpected[i], false);
+
+ ParsedDicomFile dicom(m, testEncodings[i]);
+
+ const char* encoded = NULL;
+ ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->findAndGetString(DCM_PatientName, encoded).good());
+ ASSERT_STREQ(testEncodingsEncoded[i], encoded);
+
+ dicom.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+
+ Encoding encoding;
+ ASSERT_TRUE(GetDicomEncoding(encoding, v["SpecificCharacterSet"].asCString()));
+ ASSERT_EQ(encoding, testEncodings[i]);
+ ASSERT_STREQ(testEncodingsExpected[i], v["PatientName"].asCString());
+ }
+
+
+ {
+ DicomMap m;
+ m.SetValue(DICOM_TAG_SPECIFIC_CHARACTER_SET, GetDicomSpecificCharacterSet(testEncodings[i]), false);
+ m.SetValue(DICOM_TAG_PATIENT_NAME, testEncodingsExpected[i], false);
+
+ ParsedDicomFile dicom(m, testEncodings[i]);
+
+ Json::Value v2;
+ dicom.DatasetToJson(v2, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+
+ ASSERT_EQ(v2["PatientName"].asString(), v["PatientName"].asString());
+ ASSERT_EQ(v2["SpecificCharacterSet"].asString(), v["SpecificCharacterSet"].asString());
+ }
+ }
+ }
+}
+
+
+TEST(ParsedDicomFile, ChangeEncoding)
+{
+ for (unsigned int i = 0; i < testEncodingsCount; i++)
+ {
+ // 1251 codepage is not supported by the core DICOM standard, ignore it
+ if (testEncodings[i] != Encoding_Windows1251)
+ {
+ DicomMap m;
+ m.SetValue(DICOM_TAG_PATIENT_NAME, testEncodingsExpected[i], false);
+
+ std::string tag;
+
+ ParsedDicomFile dicom(m, Encoding_Utf8);
+ ASSERT_EQ(Encoding_Utf8, dicom.GetEncoding());
+ ASSERT_TRUE(dicom.GetTagValue(tag, DICOM_TAG_PATIENT_NAME));
+ ASSERT_EQ(tag, testEncodingsExpected[i]);
+
+ {
+ Json::Value v;
+ dicom.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+ ASSERT_STREQ(v["SpecificCharacterSet"].asCString(), "ISO_IR 192");
+ ASSERT_STREQ(v["PatientName"].asCString(), testEncodingsExpected[i]);
+ }
+
+ dicom.ChangeEncoding(testEncodings[i]);
+
+ ASSERT_EQ(testEncodings[i], dicom.GetEncoding());
+
+ const char* c = NULL;
+ ASSERT_TRUE(dicom.GetDcmtkObject().getDataset()->findAndGetString(DCM_PatientName, c).good());
+ EXPECT_STREQ(c, testEncodingsEncoded[i]);
+
+ ASSERT_TRUE(dicom.GetTagValue(tag, DICOM_TAG_PATIENT_NAME)); // Decodes to UTF-8
+ EXPECT_EQ(tag, testEncodingsExpected[i]);
+
+ {
+ Json::Value v;
+ dicom.DatasetToJson(v, DicomToJsonFormat_Human, DicomToJsonFlags_Default, 0);
+ ASSERT_STREQ(v["SpecificCharacterSet"].asCString(), GetDicomSpecificCharacterSet(testEncodings[i]));
+ ASSERT_STREQ(v["PatientName"].asCString(), testEncodingsExpected[i]);
+ }
+ }
+ }
+}
diff --git a/UnitTestsSources/ImageTests.cpp b/UnitTestsSources/ImageTests.cpp
index 7fc5c77..6c7ed55 100644
--- a/UnitTestsSources/ImageTests.cpp
+++ b/UnitTestsSources/ImageTests.cpp
@@ -41,7 +41,7 @@
#include "../Core/Images/PngReader.h"
#include "../Core/Images/PngWriter.h"
#include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
+#include "../Core/TemporaryFile.h"
#include "../OrthancServer/OrthancInitialization.h"
#include <stdint.h>
@@ -72,7 +72,7 @@ TEST(PngWriter, ColorPattern)
w.WriteToFile("UnitTestsResults/ColorPattern.png", accessor);
std::string f, md5;
- Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/ColorPattern.png");
+ Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/ColorPattern.png");
Orthanc::Toolbox::ComputeMD5(md5, f);
ASSERT_EQ("604e785f53c99cae6ea4584870b2c41d", md5);
}
@@ -100,7 +100,7 @@ TEST(PngWriter, Gray8Pattern)
w.WriteToFile("UnitTestsResults/Gray8Pattern.png", accessor);
std::string f, md5;
- Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/Gray8Pattern.png");
+ Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/Gray8Pattern.png");
Orthanc::Toolbox::ComputeMD5(md5, f);
ASSERT_EQ("5a9b98bea3d0a6d983980cc38bfbcdb3", md5);
}
@@ -129,7 +129,7 @@ TEST(PngWriter, Gray16Pattern)
w.WriteToFile("UnitTestsResults/Gray16Pattern.png", accessor);
std::string f, md5;
- Orthanc::Toolbox::ReadFile(f, "UnitTestsResults/Gray16Pattern.png");
+ Orthanc::SystemToolbox::ReadFile(f, "UnitTestsResults/Gray16Pattern.png");
Orthanc::Toolbox::ComputeMD5(md5, f);
ASSERT_EQ("0785866a08bf0a02d2eeff87f658571c", md5);
}
@@ -180,8 +180,8 @@ TEST(PngWriter, EndToEnd)
}
{
- Orthanc::Toolbox::TemporaryFile tmp;
- Orthanc::Toolbox::WriteFile(s, tmp.GetPath());
+ Orthanc::TemporaryFile tmp;
+ Orthanc::SystemToolbox::WriteFile(s, tmp.GetPath());
Orthanc::PngReader r2;
r2.ReadFromFile(tmp.GetPath());
@@ -211,7 +211,7 @@ TEST(JpegWriter, Basic)
std::string s;
{
- Orthanc::Image img(Orthanc::PixelFormat_Grayscale8, 16, 16);
+ Orthanc::Image img(Orthanc::PixelFormat_Grayscale8, 16, 16, false);
for (unsigned int y = 0, value = 0; y < img.GetHeight(); y++)
{
uint8_t* p = reinterpret_cast<uint8_t*>(img.GetRow(y));
@@ -225,10 +225,10 @@ TEST(JpegWriter, Basic)
w.WriteToFile("UnitTestsResults/hello.jpg", img);
w.WriteToMemory(s, img);
- Orthanc::Toolbox::WriteFile(s, "UnitTestsResults/hello2.jpg");
+ Orthanc::SystemToolbox::WriteFile(s, "UnitTestsResults/hello2.jpg");
std::string t;
- Orthanc::Toolbox::ReadFile(t, "UnitTestsResults/hello.jpg");
+ Orthanc::SystemToolbox::ReadFile(t, "UnitTestsResults/hello.jpg");
ASSERT_EQ(s.size(), t.size());
ASSERT_EQ(0, memcmp(s.c_str(), t.c_str(), s.size()));
}
@@ -258,7 +258,7 @@ TEST(JpegWriter, Basic)
TEST(Font, Basic)
{
- Orthanc::Image s(Orthanc::PixelFormat_RGB24, 640, 480);
+ Orthanc::Image s(Orthanc::PixelFormat_RGB24, 640, 480, false);
memset(s.GetBuffer(), 0, s.GetPitch() * s.GetHeight());
ASSERT_GE(1u, Orthanc::Configuration::GetFontRegistry().GetSize());
diff --git a/UnitTestsSources/JpegLosslessTests.cpp b/UnitTestsSources/JpegLosslessTests.cpp
index a50fb6f..c52eebe 100644
--- a/UnitTestsSources/JpegLosslessTests.cpp
+++ b/UnitTestsSources/JpegLosslessTests.cpp
@@ -35,7 +35,7 @@
#include "../OrthancServer/Internals/DicomImageDecoder.h"
-#if ORTHANC_JPEG_LOSSLESS_ENABLED == 1
+#if ORTHANC_ENABLE_JPEG_LOSSLESS == 1
#include <dcmtk/dcmdata/dcfilefo.h>
diff --git a/UnitTestsSources/LuaTests.cpp b/UnitTestsSources/LuaTests.cpp
index 1453250..52e9afd 100644
--- a/UnitTestsSources/LuaTests.cpp
+++ b/UnitTestsSources/LuaTests.cpp
@@ -287,8 +287,8 @@ TEST(Lua, Http)
Orthanc::LuaContext lua;
#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1
- lua.Execute("JSON = loadstring(HttpGet('http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/JSON.lua')) ()");
- const std::string url("http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/ThirdPartyDownloads/Product.json");
+ lua.Execute("JSON = loadstring(HttpGet('http://www.orthanc-server.com/downloads/third-party/JSON.lua')) ()");
+ const std::string url("http://www.orthanc-server.com/downloads/third-party/Product.json");
#endif
std::string s;
diff --git a/UnitTestsSources/MultiThreadingTests.cpp b/UnitTestsSources/MultiThreadingTests.cpp
index 8ccfd15..bc1154f 100644
--- a/UnitTestsSources/MultiThreadingTests.cpp
+++ b/UnitTestsSources/MultiThreadingTests.cpp
@@ -35,6 +35,7 @@
#include "../OrthancServer/Scheduler/ServerScheduler.h"
#include "../Core/OrthancException.h"
+#include "../Core/SystemToolbox.h"
#include "../Core/Toolbox.h"
#include "../Core/MultiThreading/Locker.h"
#include "../Core/MultiThreading/Mutex.h"
@@ -138,7 +139,7 @@ TEST(ReusableDicomUserConnection, DISABLED_Basic)
{
RemoteModalityParameters remote("STORESCP", "localhost", 2000, ModalityManufacturer_Generic);
ReusableDicomUserConnection::Locker lock(c, "ORTHANC", remote);
- lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676281", 0);
+ lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676281");
}
printf("**\n"); fflush(stdout);
@@ -148,10 +149,10 @@ TEST(ReusableDicomUserConnection, DISABLED_Basic)
{
RemoteModalityParameters remote("STORESCP", "localhost", 2000, ModalityManufacturer_Generic);
ReusableDicomUserConnection::Locker lock(c, "ORTHANC", remote);
- lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676277", 0);
+ lock.GetConnection().StoreFile("/home/jodogne/DICOM/Cardiac/MR.X.1.2.276.0.7230010.3.1.4.2831157719.2256.1336386844.676277");
}
- Toolbox::ServerBarrier();
+ SystemToolbox::ServerBarrier();
printf("DONE\n"); fflush(stdout);
}
@@ -246,7 +247,7 @@ TEST(MultiThreading, ServerScheduler)
printf("** %s\n", i->c_str());
}
- //Toolbox::ServerBarrier();
+ //SystemToolbox::ServerBarrier();
//Toolbox::USleep(3000000);
scheduler.Stop();
diff --git a/UnitTestsSources/PluginsTests.cpp b/UnitTestsSources/PluginsTests.cpp
index 516e140..4bd0f92 100644
--- a/UnitTestsSources/PluginsTests.cpp
+++ b/UnitTestsSources/PluginsTests.cpp
@@ -38,7 +38,7 @@
using namespace Orthanc;
-#if ORTHANC_PLUGINS_ENABLED == 1
+#if ORTHANC_ENABLE_PLUGINS == 1
TEST(SharedLibrary, Enumerations)
{
diff --git a/UnitTestsSources/RestApiTests.cpp b/UnitTestsSources/RestApiTests.cpp
index c60e6fc..03102a6 100644
--- a/UnitTestsSources/RestApiTests.cpp
+++ b/UnitTestsSources/RestApiTests.cpp
@@ -40,8 +40,8 @@
#include "../Core/ChunkedBuffer.h"
#include "../Core/HttpClient.h"
#include "../Core/Logging.h"
+#include "../Core/SystemToolbox.h"
#include "../Core/RestApi/RestApi.h"
-#include "../Core/Uuid.h"
#include "../Core/OrthancException.h"
#include "../Core/Compression/ZlibCompressor.h"
#include "../Core/RestApi/RestApiHierarchy.h"
@@ -66,14 +66,15 @@ TEST(HttpClient, Basic)
#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1
Json::Value v;
- c.SetUrl("http://www.montefiore.ulg.ac.be/~jodogne/Orthanc/Configuration.json");
+ c.SetUrl("http://www.orthanc-server.com/downloads/third-party/Product.json");
c.Apply(v);
- ASSERT_TRUE(v.isMember("StorageDirectory"));
+ ASSERT_TRUE(v.type() == Json::objectValue);
+ ASSERT_TRUE(v.isMember("Description"));
#endif
}
-#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_SSL_ENABLED == 1
+#if UNIT_TESTS_WITH_HTTP_CONNEXIONS == 1 && ORTHANC_ENABLE_SSL == 1
/**
The HTTPS CA certificates for BitBucket were extracted as follows:
@@ -100,12 +101,12 @@ TEST(HttpClient, Basic)
TEST(HttpClient, Ssl)
{
- Toolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert");
+ SystemToolbox::WriteFile(BITBUCKET_CERTIFICATES, "UnitTestsResults/bitbucket.cert");
/*{
std::string s;
- Toolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt");
- Toolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert");
+ SystemToolbox::ReadFile(s, "/usr/share/ca-certificates/mozilla/WoSign.crt");
+ SystemToolbox::WriteFile(s, "UnitTestsResults/bitbucket.cert");
}*/
HttpClient c;
diff --git a/UnitTestsSources/SQLiteTests.cpp b/UnitTestsSources/SQLiteTests.cpp
index c3ddafc..9b39ab9 100644
--- a/UnitTestsSources/SQLiteTests.cpp
+++ b/UnitTestsSources/SQLiteTests.cpp
@@ -33,7 +33,7 @@
#include "PrecompiledHeadersUnitTests.h"
#include "gtest/gtest.h"
-#include "../Core/Toolbox.h"
+#include "../Core/SystemToolbox.h"
#include "../Core/SQLite/Connection.h"
#include "../Core/SQLite/Statement.h"
#include "../Core/SQLite/Transaction.h"
@@ -58,7 +58,7 @@ TEST(SQLite, Configuration)
TEST(SQLite, Connection)
{
- Toolbox::RemoveFile("UnitTestsResults/coucou");
+ SystemToolbox::RemoveFile("UnitTestsResults/coucou");
SQLite::Connection c;
c.Open("UnitTestsResults/coucou");
c.Execute("CREATE TABLE c(k INTEGER PRIMARY KEY AUTOINCREMENT, v INTEGER)");
diff --git a/UnitTestsSources/ServerIndexTests.cpp b/UnitTestsSources/ServerIndexTests.cpp
index 4dd7233..8fe8094 100644
--- a/UnitTestsSources/ServerIndexTests.cpp
+++ b/UnitTestsSources/ServerIndexTests.cpp
@@ -35,7 +35,6 @@
#include "../Core/FileStorage/FilesystemStorage.h"
#include "../Core/Logging.h"
-#include "../Core/Uuid.h"
#include "../OrthancServer/DatabaseWrapper.h"
#include "../OrthancServer/ServerContext.h"
#include "../OrthancServer/ServerIndex.h"
@@ -671,7 +670,7 @@ TEST(ServerIndex, Sequence)
{
const std::string path = "UnitTestsStorage";
- Toolbox::RemoveFile(path + "/index");
+ SystemToolbox::RemoveFile(path + "/index");
FilesystemStorage storage(path);
DatabaseWrapper db; // The SQLite DB is in memory
db.Open();
@@ -769,7 +768,7 @@ TEST(ServerIndex, AttachmentRecycling)
{
const std::string path = "UnitTestsStorage";
- Toolbox::RemoveFile(path + "/index");
+ SystemToolbox::RemoveFile(path + "/index");
FilesystemStorage storage(path);
DatabaseWrapper db; // The SQLite DB is in memory
db.Open();
@@ -794,14 +793,22 @@ TEST(ServerIndex, AttachmentRecycling)
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);
+ instance.SetValue(DICOM_TAG_SOP_CLASS_UID, "1.2.840.10008.5.1.4.1.1.1", false); // CR image
std::map<MetadataType, std::string> instanceMetadata;
DicomInstanceToStore toStore;
toStore.SetSummary(instance);
ASSERT_EQ(StoreStatus_Success, index.Store(instanceMetadata, toStore, attachments));
- ASSERT_EQ(3u, instanceMetadata.size());
+ ASSERT_EQ(5u, instanceMetadata.size());
ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_RemoteAet) != instanceMetadata.end());
ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_ReceptionDate) != instanceMetadata.end());
+ ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_TransferSyntax) != instanceMetadata.end());
+ ASSERT_TRUE(instanceMetadata.find(MetadataType_Instance_SopClassUid) != instanceMetadata.end());
+
+ // By default, an Explicit VR Little Endian is used by Orthanc
+ ASSERT_EQ("1.2.840.10008.1.2.1", instanceMetadata[MetadataType_Instance_TransferSyntax]);
+
+ ASSERT_EQ("1.2.840.10008.5.1.4.1.1.1", instanceMetadata[MetadataType_Instance_SopClassUid]);
DicomInstanceHasher hasher(instance);
ids.push_back(hasher.HashPatient());
@@ -816,7 +823,7 @@ TEST(ServerIndex, AttachmentRecycling)
for (size_t i = 0; i < ids.size(); i++)
{
- FileInfo info(Toolbox::GenerateUuid(), FileContentType_Dicom, 1, "md5");
+ FileInfo info(SystemToolbox::GenerateUuid(), FileContentType_Dicom, 1, "md5");
index.AddAttachment(info, ids[i]);
index.ComputeStatistics(tmp);
@@ -824,7 +831,7 @@ TEST(ServerIndex, AttachmentRecycling)
}
// Because the DB is in memory, the SQLite index must not have been created
- ASSERT_FALSE(Toolbox::IsRegularFile(path + "/index"));
+ ASSERT_FALSE(SystemToolbox::IsRegularFile(path + "/index"));
context.Stop();
db.Close();
@@ -833,6 +840,6 @@ TEST(ServerIndex, AttachmentRecycling)
TEST(LookupIdentifierQuery, NormalizeIdentifier)
{
- ASSERT_EQ("H^L.LO", LookupIdentifierQuery::NormalizeIdentifier(" Hé^l.LO %_ "));
- ASSERT_EQ("1.2.840.113619.2.176.2025", LookupIdentifierQuery::NormalizeIdentifier(" 1.2.840.113619.2.176.2025 "));
+ ASSERT_EQ("H^L.LO", ServerToolbox::NormalizeIdentifier(" Hé^l.LO %_ "));
+ ASSERT_EQ("1.2.840.113619.2.176.2025", ServerToolbox::NormalizeIdentifier(" 1.2.840.113619.2.176.2025 "));
}
diff --git a/UnitTestsSources/StreamTests.cpp b/UnitTestsSources/StreamTests.cpp
index 397c25b..bf95796 100644
--- a/UnitTestsSources/StreamTests.cpp
+++ b/UnitTestsSources/StreamTests.cpp
@@ -33,9 +33,10 @@
#include "PrecompiledHeadersUnitTests.h"
#include "gtest/gtest.h"
+#include "../Core/SystemToolbox.h"
+#include "../Core/SystemToolbox.h"
#include "../Core/Toolbox.h"
#include "../Core/OrthancException.h"
-#include "../Core/Uuid.h"
#include "../Core/HttpServer/BufferHttpSender.h"
#include "../Core/HttpServer/FilesystemHttpSender.h"
#include "../Core/HttpServer/HttpStreamTranscoder.h"
@@ -113,7 +114,7 @@ TEST(Gzip, EmptyWithPrefix)
TEST(Zlib, Basic)
{
- std::string s = Toolbox::GenerateUuid();
+ std::string s = SystemToolbox::GenerateUuid();
s = s + s + s + s;
std::string compressed, compressed2;
@@ -130,7 +131,7 @@ TEST(Zlib, Basic)
TEST(Zlib, Level)
{
- std::string s = Toolbox::GenerateUuid();
+ std::string s = SystemToolbox::GenerateUuid();
s = s + s + s + s;
std::string compressed, compressed2;
@@ -147,7 +148,7 @@ TEST(Zlib, Level)
TEST(Zlib, DISABLED_Corrupted) // Disabled because it may result in a crash
{
- std::string s = Toolbox::GenerateUuid();
+ std::string s = SystemToolbox::GenerateUuid();
s = s + s + s + s;
std::string compressed;
@@ -233,14 +234,14 @@ TEST(FilesystemHttpSender, Basic)
std::string t;
{
- Toolbox::WriteFile(s, path);
+ SystemToolbox::WriteFile(s, path);
FilesystemHttpSender sender(path);
ASSERT_TRUE(ReadAllStream(t, sender));
ASSERT_EQ(s, t);
}
{
- Toolbox::WriteFile("", path);
+ SystemToolbox::WriteFile("", path);
FilesystemHttpSender sender(path);
ASSERT_TRUE(ReadAllStream(t, sender));
ASSERT_EQ(0u, t.size());
@@ -252,7 +253,7 @@ TEST(HttpStreamTranscoder, Basic)
{
ZlibCompressor compressor;
- const std::string s = "Hello world " + Toolbox::GenerateUuid();
+ const std::string s = "Hello world " + SystemToolbox::GenerateUuid();
std::string t;
IBufferCompressor::Compress(t, compressor, s);
diff --git a/UnitTestsSources/UnitTestsMain.cpp b/UnitTestsSources/UnitTestsMain.cpp
index 42882e2..59c7193 100644
--- a/UnitTestsSources/UnitTestsMain.cpp
+++ b/UnitTestsSources/UnitTestsMain.cpp
@@ -41,8 +41,8 @@
#include "../Core/HttpServer/HttpToolbox.h"
#include "../Core/Logging.h"
#include "../Core/OrthancException.h"
+#include "../Core/TemporaryFile.h"
#include "../Core/Toolbox.h"
-#include "../Core/Uuid.h"
#include "../OrthancServer/OrthancInitialization.h"
@@ -53,7 +53,7 @@ TEST(Uuid, Generation)
{
for (int i = 0; i < 10; i++)
{
- std::string s = Toolbox::GenerateUuid();
+ std::string s = SystemToolbox::GenerateUuid();
ASSERT_TRUE(Toolbox::IsUuid(s));
}
}
@@ -374,8 +374,8 @@ TEST(Toolbox, Base64)
TEST(Toolbox, PathToExecutable)
{
- printf("[%s]\n", Toolbox::GetPathToExecutable().c_str());
- printf("[%s]\n", Toolbox::GetDirectoryOfExecutable().c_str());
+ printf("[%s]\n", SystemToolbox::GetPathToExecutable().c_str());
+ printf("[%s]\n", SystemToolbox::GetDirectoryOfExecutable().c_str());
}
TEST(Toolbox, StripSpaces)
@@ -543,7 +543,7 @@ TEST(Toolbox, WriteFile)
std::string path;
{
- Toolbox::TemporaryFile tmp;
+ TemporaryFile tmp;
path = tmp.GetPath();
std::string s;
@@ -552,28 +552,28 @@ TEST(Toolbox, WriteFile)
s.append("World");
ASSERT_EQ(11u, s.size());
- Toolbox::WriteFile(s, path.c_str());
+ SystemToolbox::WriteFile(s, path.c_str());
std::string t;
- Toolbox::ReadFile(t, path.c_str());
+ SystemToolbox::ReadFile(t, path.c_str());
ASSERT_EQ(11u, t.size());
ASSERT_EQ(0, t[5]);
ASSERT_EQ(0, memcmp(s.c_str(), t.c_str(), s.size()));
std::string h;
- ASSERT_EQ(true, Toolbox::ReadHeader(h, path.c_str(), 1));
+ ASSERT_EQ(true, SystemToolbox::ReadHeader(h, path.c_str(), 1));
ASSERT_EQ(1u, h.size());
ASSERT_EQ('H', h[0]);
- ASSERT_TRUE(Toolbox::ReadHeader(h, path.c_str(), 0));
+ ASSERT_TRUE(SystemToolbox::ReadHeader(h, path.c_str(), 0));
ASSERT_EQ(0u, h.size());
- ASSERT_FALSE(Toolbox::ReadHeader(h, path.c_str(), 32));
+ ASSERT_FALSE(SystemToolbox::ReadHeader(h, path.c_str(), 32));
ASSERT_EQ(11u, h.size());
ASSERT_EQ(0, memcmp(s.c_str(), h.c_str(), s.size()));
}
std::string u;
- ASSERT_THROW(Toolbox::ReadFile(u, path.c_str()), OrthancException);
+ ASSERT_THROW(SystemToolbox::ReadFile(u, path.c_str()), OrthancException);
}
@@ -871,7 +871,7 @@ TEST(Toolbox, EndiannessConversions64)
-#if ORTHANC_PUGIXML_ENABLED == 1
+#if ORTHANC_ENABLE_PUGIXML == 1
TEST(Toolbox, Xml)
{
Json::Value a;
@@ -896,7 +896,7 @@ TEST(Toolbox, ExecuteSystemCommand)
args[0] = "Hello";
args[1] = "World";
- Toolbox::ExecuteSystemCommand("echo", args);
+ SystemToolbox::ExecuteSystemCommand("echo", args);
}
#endif
@@ -945,12 +945,49 @@ TEST(Toolbox, UriEncode)
}
+TEST(Toolbox, AccessJson)
+{
+ Json::Value v = Json::arrayValue;
+ ASSERT_EQ("nope", Toolbox::GetJsonStringField(v, "hello", "nope"));
+
+ v = Json::objectValue;
+ ASSERT_EQ("nope", Toolbox::GetJsonStringField(v, "hello", "nope"));
+ ASSERT_EQ(-10, Toolbox::GetJsonIntegerField(v, "hello", -10));
+ ASSERT_EQ(10, Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10));
+ ASSERT_TRUE(Toolbox::GetJsonBooleanField(v, "hello", true));
+
+ v["hello"] = "world";
+ ASSERT_EQ("world", Toolbox::GetJsonStringField(v, "hello", "nope"));
+ ASSERT_THROW(Toolbox::GetJsonIntegerField(v, "hello", -10), OrthancException);
+ ASSERT_THROW(Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10), OrthancException);
+ ASSERT_THROW(Toolbox::GetJsonBooleanField(v, "hello", true), OrthancException);
+
+ v["hello"] = -42;
+ ASSERT_THROW(Toolbox::GetJsonStringField(v, "hello", "nope"), OrthancException);
+ ASSERT_EQ(-42, Toolbox::GetJsonIntegerField(v, "hello", -10));
+ ASSERT_THROW(Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10), OrthancException);
+ ASSERT_THROW(Toolbox::GetJsonBooleanField(v, "hello", true), OrthancException);
+
+ v["hello"] = 42;
+ ASSERT_THROW(Toolbox::GetJsonStringField(v, "hello", "nope"), OrthancException);
+ ASSERT_EQ(42, Toolbox::GetJsonIntegerField(v, "hello", -10));
+ ASSERT_EQ(42, Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10));
+ ASSERT_THROW(Toolbox::GetJsonBooleanField(v, "hello", true), OrthancException);
+
+ v["hello"] = false;
+ ASSERT_THROW(Toolbox::GetJsonStringField(v, "hello", "nope"), OrthancException);
+ ASSERT_THROW(Toolbox::GetJsonIntegerField(v, "hello", -10), OrthancException);
+ ASSERT_THROW(Toolbox::GetJsonUnsignedIntegerField(v, "hello", 10), OrthancException);
+ ASSERT_FALSE(Toolbox::GetJsonBooleanField(v, "hello", true));
+}
+
+
int main(int argc, char **argv)
{
Logging::Initialize();
Logging::EnableInfoLevel(true);
Toolbox::DetectEndianness();
- Toolbox::MakeDirectory("UnitTestsResults");
+ SystemToolbox::MakeDirectory("UnitTestsResults");
OrthancInitialize();
::testing::InitGoogleTest(&argc, argv);
diff --git a/UnitTestsSources/VersionsTests.cpp b/UnitTestsSources/VersionsTests.cpp
index f9b738a..193ce72 100644
--- a/UnitTestsSources/VersionsTests.cpp
+++ b/UnitTestsSources/VersionsTests.cpp
@@ -44,7 +44,7 @@
#include <lua.h>
#include <jpeglib.h>
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
#include <openssl/opensslv.h>
#endif
@@ -108,7 +108,7 @@ TEST(Versions, BoostStatic)
TEST(Versions, CurlStatic)
{
curl_version_info_data* v = curl_version_info(CURLVERSION_NOW);
- ASSERT_STREQ("7.44.0", v->version);
+ ASSERT_STREQ("7.50.3", v->version);
}
TEST(Versions, PngStatic)
@@ -130,7 +130,7 @@ TEST(Versions, CurlSslStatic)
// Check that SSL support is enabled when required
bool curlSupportsSsl = (vinfo->features & CURL_VERSION_SSL) != 0;
-#if ORTHANC_SSL_ENABLED == 0
+#if ORTHANC_ENABLE_SSL == 0
ASSERT_FALSE(curlSupportsSsl);
#else
ASSERT_TRUE(curlSupportsSsl);
@@ -143,7 +143,7 @@ TEST(Version, LuaStatic)
}
-#if ORTHANC_SSL_ENABLED == 1
+#if ORTHANC_ENABLE_SSL == 1
TEST(Version, OpenSslStatic)
{
ASSERT_EQ(0x1000204fL /* openssl-1.0.2d */, OPENSSL_VERSION_NUMBER);
--
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/orthanc.git
More information about the debian-med-commit
mailing list