Mercurial > hg > orthanc-wsi
changeset 116:a18bfe1fdd62
sync
line wrap: on
line diff
--- a/Applications/ApplicationToolbox.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Applications/ApplicationToolbox.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -26,7 +26,7 @@ #include "../Resources/Orthanc/Core/Logging.h" #include "../Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h" #include "../Resources/Orthanc/Core/SystemToolbox.h" -#include "../Resources/Orthanc/OrthancServer/FromDcmtkBridge.h" +#include "../Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h" #include <boost/filesystem.hpp> #include <boost/lexical_cast.hpp>
--- a/Applications/CMakeLists.txt Tue Jan 02 10:01:35 2018 +0100 +++ b/Applications/CMakeLists.txt Thu Jan 04 10:49:34 2018 +0100 @@ -33,8 +33,9 @@ SET(USE_SYSTEM_LIBTIFF ON CACHE BOOL "Use the system version of libtiff") SET(USE_SYSTEM_OPENJPEG ON CACHE BOOL "Use the system version of OpenJpeg") SET(USE_SYSTEM_OPENSSL ON CACHE BOOL "Use the system version of OpenSSL") +SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK") SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib") -SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK") +set(USE_SYSTEM_UUID ON CACHE BOOL "Use the system version of the uuid library from e2fsprogs") SET(DCMTK_DICTIONARY_DIR "" CACHE PATH "Directory containing the DCMTK dictionaries \"dicom.dic\" and \"private.dic\" (only when using system version of DCMTK)") @@ -57,9 +58,11 @@ SET(USE_DCMTK_361_PRIVATE_DIC OFF) # No need for private tags include(CheckFunctionExists) +include(CheckIncludeFile) include(CheckIncludeFiles) include(CheckIncludeFileCXX) include(CheckLibraryExists) +include(CheckStructHasMember) include(FindPythonInterp) include(FindPkgConfig) include(CheckSymbolExists) @@ -76,6 +79,7 @@ include(${ORTHANC_ROOT}/Resources/CMake/LibIconvConfiguration.cmake) include(${ORTHANC_ROOT}/Resources/CMake/LibJpegConfiguration.cmake) include(${ORTHANC_ROOT}/Resources/CMake/LibPngConfiguration.cmake) +include(${ORTHANC_ROOT}/Resources/CMake/UuidConfiguration.cmake) include(${ORTHANC_ROOT}/Resources/CMake/ZlibConfiguration.cmake) # Include components specific to WSI @@ -85,11 +89,15 @@ include(${ORTHANC_WSI_DIR}/Resources/CMake/LibTiffConfiguration.cmake) add_definitions( + -DHAS_ORTHANC_EXCEPTION=1 -DORTHANC_BUILD_UNIT_TESTS=0 # For FromDcmtkBridge + -DORTHANC_DEFAULT_DICOM_ENCODING=Encoding_Latin1 -DORTHANC_ENABLE_BASE64=1 -DORTHANC_ENABLE_CURL=1 -DORTHANC_ENABLE_DCMTK=1 - -DORTHANC_ENABLE_JPEG=0 # Disable DCMTK's support for JPEG + -DORTHANC_ENABLE_DCMTK_JPEG=0 # Disable DCMTK's support for JPEG + -DORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS=0 # Disable DCMTK's support for JPEG-LS + -DORTHANC_ENABLE_JPEG=1 -DORTHANC_ENABLE_LOCALE=1 -DORTHANC_ENABLE_LOGGING=1 -DORTHANC_ENABLE_LOGGING_PLUGIN=0 @@ -97,9 +105,10 @@ -DORTHANC_ENABLE_MD5=0 -DORTHANC_ENABLE_PKCS11=0 -DORTHANC_ENABLE_PLUGINS=1 # To enable class Orthanc::SharedLibrary + -DORTHANC_ENABLE_PNG=1 -DORTHANC_ENABLE_PUGIXML=0 + -DORTHANC_MAXIMUM_TAG_LENGTH=256 -DORTHANC_SANDBOXED=0 - -DHAS_ORTHANC_EXCEPTION=1 ) @@ -172,6 +181,8 @@ ${ORTHANC_ROOT}/Core/DicomFormat/DicomMap.cpp ${ORTHANC_ROOT}/Core/DicomFormat/DicomTag.cpp ${ORTHANC_ROOT}/Core/DicomFormat/DicomValue.cpp + ${ORTHANC_ROOT}/Core/DicomParsing/FromDcmtkBridge.cpp + ${ORTHANC_ROOT}/Core/DicomParsing/ToDcmtkBridge.cpp ${ORTHANC_ROOT}/Core/Enumerations.cpp ${ORTHANC_ROOT}/Core/HttpClient.cpp ${ORTHANC_ROOT}/Core/Images/IImageWriter.cpp @@ -191,9 +202,6 @@ ${ORTHANC_ROOT}/Core/TemporaryFile.cpp ${ORTHANC_ROOT}/Core/Toolbox.cpp ${ORTHANC_ROOT}/Core/WebServiceParameters.cpp - ${ORTHANC_ROOT}/OrthancServer/FromDcmtkBridge.cpp - ${ORTHANC_ROOT}/OrthancServer/ServerEnumerations.cpp - ${ORTHANC_ROOT}/OrthancServer/ToDcmtkBridge.cpp ${ORTHANC_ROOT}/Plugins/Engine/SharedLibrary.cpp ${ORTHANC_ROOT}/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp @@ -253,6 +261,7 @@ ${LIBPNG_SOURCES} ${LIBTIFF_SOURCES} ${OPENJPEG_SOURCES} + ${UUID_SOURCES} ${ZLIB_SOURCES} # Optional components
--- a/Applications/Dicomizer.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Applications/Dicomizer.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -36,7 +36,7 @@ #include "../Resources/Orthanc/Core/Logging.h" #include "../Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h" #include "../Resources/Orthanc/Core/SystemToolbox.h" -#include "../Resources/Orthanc/OrthancServer/FromDcmtkBridge.h" +#include "../Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h" #include "ApplicationToolbox.h"
--- a/Framework/Outputs/DicomPyramidWriter.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Framework/Outputs/DicomPyramidWriter.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -26,7 +26,7 @@ #include "../../Resources/Orthanc/Core/Logging.h" #include "../../Resources/Orthanc/Core/OrthancException.h" -#include "../../Resources/Orthanc/OrthancServer/FromDcmtkBridge.h" +#include "../../Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h" #include <dcmtk/dcmdata/dcdeftag.h> #include <boost/lexical_cast.hpp>
--- a/Resources/Orthanc/Core/Cache/LeastRecentlyUsedIndex.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Cache/LeastRecentlyUsedIndex.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/ChunkedBuffer.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/ChunkedBuffer.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/ChunkedBuffer.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/ChunkedBuffer.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomArray.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/DicomFormat/DicomArray.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomArray.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/DicomFormat/DicomArray.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomElement.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/DicomFormat/DicomElement.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomMap.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/DicomFormat/DicomMap.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -36,7 +36,9 @@ #include <stdio.h> #include <memory> + #include "../Endianness.h" +#include "../Logging.h" #include "../OrthancException.h" @@ -781,4 +783,193 @@ return true; } + + + static std::string ValueAsString(const DicomMap& summary, + const DicomTag& tag) + { + const DicomValue& value = summary.GetValue(tag); + if (value.IsNull()) + { + return "(null)"; + } + else + { + return value.GetContent(); + } + } + + + void DicomMap::LogMissingTagsForStore() const + { + std::string s, t; + + if (HasTag(DICOM_TAG_PATIENT_ID)) + { + if (t.size() > 0) + t += ", "; + t += "PatientID=" + ValueAsString(*this, DICOM_TAG_PATIENT_ID); + } + else + { + if (s.size() > 0) + s += ", "; + s += "PatientID"; + } + + if (HasTag(DICOM_TAG_STUDY_INSTANCE_UID)) + { + if (t.size() > 0) + t += ", "; + t += "StudyInstanceUID=" + ValueAsString(*this, DICOM_TAG_STUDY_INSTANCE_UID); + } + else + { + if (s.size() > 0) + s += ", "; + s += "StudyInstanceUID"; + } + + if (HasTag(DICOM_TAG_SERIES_INSTANCE_UID)) + { + if (t.size() > 0) + t += ", "; + t += "SeriesInstanceUID=" + ValueAsString(*this, DICOM_TAG_SERIES_INSTANCE_UID); + } + else + { + if (s.size() > 0) + s += ", "; + s += "SeriesInstanceUID"; + } + + if (HasTag(DICOM_TAG_SOP_INSTANCE_UID)) + { + if (t.size() > 0) + t += ", "; + t += "SOPInstanceUID=" + ValueAsString(*this, DICOM_TAG_SOP_INSTANCE_UID); + } + else + { + if (s.size() > 0) + s += ", "; + s += "SOPInstanceUID"; + } + + if (t.size() == 0) + { + LOG(ERROR) << "Store has failed because all the required tags (" << s << ") are missing (is it a DICOMDIR file?)"; + } + else + { + LOG(ERROR) << "Store has failed because required tags (" << s << ") are missing for the following instance: " << t; + } + } + + + bool DicomMap::CopyToString(std::string& result, + const DicomTag& tag, + bool allowBinary) const + { + const DicomValue* value = TestAndGetValue(tag); + + if (value == NULL) + { + return false; + } + else + { + return value->CopyToString(result, allowBinary); + } + } + + bool DicomMap::ParseInteger32(int32_t& result, + const DicomTag& tag) const + { + const DicomValue* value = TestAndGetValue(tag); + + if (value == NULL) + { + return false; + } + else + { + return value->ParseInteger32(result); + } + } + + bool DicomMap::ParseInteger64(int64_t& result, + const DicomTag& tag) const + { + const DicomValue* value = TestAndGetValue(tag); + + if (value == NULL) + { + return false; + } + else + { + return value->ParseInteger64(result); + } + } + + bool DicomMap::ParseUnsignedInteger32(uint32_t& result, + const DicomTag& tag) const + { + const DicomValue* value = TestAndGetValue(tag); + + if (value == NULL) + { + return false; + } + else + { + return value->ParseUnsignedInteger32(result); + } + } + + bool DicomMap::ParseUnsignedInteger64(uint64_t& result, + const DicomTag& tag) const + { + const DicomValue* value = TestAndGetValue(tag); + + if (value == NULL) + { + return false; + } + else + { + return value->ParseUnsignedInteger64(result); + } + } + + bool DicomMap::ParseFloat(float& result, + const DicomTag& tag) const + { + const DicomValue* value = TestAndGetValue(tag); + + if (value == NULL) + { + return false; + } + else + { + return value->ParseFloat(result); + } + } + + bool DicomMap::ParseDouble(double& result, + const DicomTag& tag) const + { + const DicomValue* value = TestAndGetValue(tag); + + if (value == NULL) + { + return false; + } + else + { + return value->ParseDouble(result); + } + } }
--- a/Resources/Orthanc/Core/DicomFormat/DicomMap.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/DicomFormat/DicomMap.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -181,5 +181,29 @@ static bool ParseDicomMetaInformation(DicomMap& result, const char* dicom, size_t size); + + void LogMissingTagsForStore() const; + + bool CopyToString(std::string& result, + const DicomTag& tag, + bool allowBinary) const; + + bool ParseInteger32(int32_t& result, + const DicomTag& tag) const; + + bool ParseInteger64(int64_t& result, + const DicomTag& tag) const; + + bool ParseUnsignedInteger32(uint32_t& result, + const DicomTag& tag) const; + + bool ParseUnsignedInteger64(uint64_t& result, + const DicomTag& tag) const; + + bool ParseFloat(float& result, + const DicomTag& tag) const; + + bool ParseDouble(double& result, + const DicomTag& tag) const; }; }
--- a/Resources/Orthanc/Core/DicomFormat/DicomTag.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/DicomFormat/DicomTag.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/DicomFormat/DicomTag.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/DicomFormat/DicomTag.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -173,6 +173,17 @@ static const DicomTag DICOM_TAG_ACQUISITION_DEVICE_PROCESSING_DESCRIPTION(0x0018, 0x1400); static const DicomTag DICOM_TAG_CONTRAST_BOLUS_AGENT(0x0018, 0x0010); + // Tags used within the Stone of Orthanc + static const DicomTag DICOM_TAG_FRAME_INCREMENT_POINTER(0x0028, 0x0009); + static const DicomTag DICOM_TAG_GRID_FRAME_OFFSET_VECTOR(0x3004, 0x000c); + static const DicomTag DICOM_TAG_PIXEL_SPACING(0x0028, 0x0030); + static const DicomTag DICOM_TAG_RESCALE_INTERCEPT(0x0028, 0x1052); + static const DicomTag DICOM_TAG_RESCALE_SLOPE(0x0028, 0x1053); + static const DicomTag DICOM_TAG_SLICE_THICKNESS(0x0018, 0x0050); + static const DicomTag DICOM_TAG_WINDOW_CENTER(0x0028, 0x1050); + static const DicomTag DICOM_TAG_WINDOW_WIDTH(0x0028, 0x1051); + static const DicomTag DICOM_TAG_DOSE_GRID_SCALING(0x3004, 0x000e); + // Counting patients, studies and series // https://www.medicalconnections.co.uk/kb/Counting_Studies_Series_and_Instances static const DicomTag DICOM_TAG_NUMBER_OF_PATIENT_RELATED_STUDIES(0x0020, 0x1200);
--- a/Resources/Orthanc/Core/DicomFormat/DicomValue.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/DicomFormat/DicomValue.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -37,6 +37,8 @@ #include "../OrthancException.h" #include "../Toolbox.h" +#include <boost/lexical_cast.hpp> + namespace Orthanc { DicomValue::DicomValue(const DicomValue& other) : @@ -91,4 +93,104 @@ } #endif + + template <typename T, + bool allowSigned> + static bool ParseValue(T& result, + const DicomValue& source) + { + if (source.IsBinary() || + source.IsNull()) + { + return false; + } + + try + { + std::string value = Toolbox::StripSpaces(source.GetContent()); + if (value.empty()) + { + return false; + } + + if (!allowSigned && + value[0] == '-') + { + return false; + } + + result = boost::lexical_cast<T>(value); + return true; + } + catch (boost::bad_lexical_cast&) + { + return false; + } + } + + bool DicomValue::ParseInteger32(int32_t& result) const + { + int64_t tmp; + if (ParseValue<int64_t, true>(tmp, *this)) + { + result = static_cast<int32_t>(tmp); + return (tmp == static_cast<int64_t>(result)); // Check no overflow occurs + } + else + { + return false; + } + } + + bool DicomValue::ParseInteger64(int64_t& result) const + { + return ParseValue<int64_t, true>(result, *this); + } + + bool DicomValue::ParseUnsignedInteger32(uint32_t& result) const + { + uint64_t tmp; + if (ParseValue<uint64_t, false>(tmp, *this)) + { + result = static_cast<uint32_t>(tmp); + return (tmp == static_cast<uint64_t>(result)); // Check no overflow occurs + } + else + { + return false; + } + } + + bool DicomValue::ParseUnsignedInteger64(uint64_t& result) const + { + return ParseValue<uint64_t, false>(result, *this); + } + + bool DicomValue::ParseFloat(float& result) const + { + return ParseValue<float, true>(result, *this); + } + + bool DicomValue::ParseDouble(double& result) const + { + return ParseValue<double, true>(result, *this); + } + + bool DicomValue::CopyToString(std::string& result, + bool allowBinary) const + { + if (IsNull()) + { + return false; + } + else if (IsBinary() && !allowBinary) + { + return false; + } + else + { + result.assign(content_); + return true; + } + } }
--- a/Resources/Orthanc/Core/DicomFormat/DicomValue.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/DicomFormat/DicomValue.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +33,7 @@ #pragma once +#include <stdint.h> #include <string> #include <boost/noncopyable.hpp> @@ -93,5 +94,20 @@ FormatDataUriScheme(target, "application/octet-stream"); } #endif + + bool CopyToString(std::string& result, + bool allowBinary) const; + + bool ParseInteger32(int32_t& result) const; + + bool ParseInteger64(int64_t& result) const; + + bool ParseUnsignedInteger32(uint32_t& result) const; + + bool ParseUnsignedInteger64(uint64_t& result) const; + + bool ParseFloat(float& result) const; + + bool ParseDouble(double& result) const; }; }
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -0,0 +1,2098 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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" + +#ifndef NOMINMAX +#define NOMINMAX +#endif + +#include "FromDcmtkBridge.h" +#include "ToDcmtkBridge.h" +#include "../Logging.h" +#include "../SystemToolbox.h" +#include "../Toolbox.h" +#include "../TemporaryFile.h" +#include "../OrthancException.h" + +#include <list> +#include <limits> + +#include <boost/lexical_cast.hpp> +#include <boost/filesystem.hpp> +#include <boost/algorithm/string/predicate.hpp> + +#include <dcmtk/dcmdata/dcdeftag.h> +#include <dcmtk/dcmdata/dcdicent.h> +#include <dcmtk/dcmdata/dcdict.h> +#include <dcmtk/dcmdata/dcfilefo.h> +#include <dcmtk/dcmdata/dcostrmb.h> +#include <dcmtk/dcmdata/dcpixel.h> +#include <dcmtk/dcmdata/dcuid.h> +#include <dcmtk/dcmdata/dcistrmb.h> + +#include <dcmtk/dcmdata/dcvrae.h> +#include <dcmtk/dcmdata/dcvras.h> +#include <dcmtk/dcmdata/dcvrat.h> +#include <dcmtk/dcmdata/dcvrcs.h> +#include <dcmtk/dcmdata/dcvrda.h> +#include <dcmtk/dcmdata/dcvrds.h> +#include <dcmtk/dcmdata/dcvrdt.h> +#include <dcmtk/dcmdata/dcvrfd.h> +#include <dcmtk/dcmdata/dcvrfl.h> +#include <dcmtk/dcmdata/dcvris.h> +#include <dcmtk/dcmdata/dcvrlo.h> +#include <dcmtk/dcmdata/dcvrlt.h> +#include <dcmtk/dcmdata/dcvrpn.h> +#include <dcmtk/dcmdata/dcvrsh.h> +#include <dcmtk/dcmdata/dcvrsl.h> +#include <dcmtk/dcmdata/dcvrss.h> +#include <dcmtk/dcmdata/dcvrst.h> +#include <dcmtk/dcmdata/dcvrtm.h> +#include <dcmtk/dcmdata/dcvrui.h> +#include <dcmtk/dcmdata/dcvrul.h> +#include <dcmtk/dcmdata/dcvrus.h> +#include <dcmtk/dcmdata/dcvrut.h> + +#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 +# include <EmbeddedResources.h> +#endif + +#if ORTHANC_ENABLE_DCMTK_JPEG == 1 +# include <dcmtk/dcmjpeg/djdecode.h> +#endif + +#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 +# include <dcmtk/dcmjpls/djdecode.h> +#endif + + +namespace Orthanc +{ + static inline uint16_t GetCharValue(char c) + { + if (c >= '0' && c <= '9') + return c - '0'; + else if (c >= 'a' && c <= 'f') + return c - 'a' + 10; + else if (c >= 'A' && c <= 'F') + return c - 'A' + 10; + else + return 0; + } + + static inline uint16_t GetTagValue(const char* c) + { + return ((GetCharValue(c[0]) << 12) + + (GetCharValue(c[1]) << 8) + + (GetCharValue(c[2]) << 4) + + GetCharValue(c[3])); + } + + +#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 + static void LoadEmbeddedDictionary(DcmDataDictionary& dictionary, + EmbeddedResources::FileResourceId resource) + { + std::string content; + EmbeddedResources::GetFileResource(content, resource); + + TemporaryFile tmp; + tmp.Write(content); + + if (!dictionary.loadDictionary(tmp.GetPath().c_str())) + { + LOG(ERROR) << "Cannot read embedded dictionary. Under Windows, make sure that " + << "your TEMP directory does not contain special characters."; + throw OrthancException(ErrorCode_InternalError); + } + } + +#else + static void LoadExternalDictionary(DcmDataDictionary& dictionary, + const std::string& directory, + const std::string& filename) + { + boost::filesystem::path p = directory; + p = p / filename; + + LOG(WARNING) << "Loading the external DICOM dictionary " << p; + + if (!dictionary.loadDictionary(p.string().c_str())) + { + throw OrthancException(ErrorCode_InternalError); + } + } +#endif + + + namespace + { + class DictionaryLocker + { + private: + DcmDataDictionary& dictionary_; + + public: + DictionaryLocker() : dictionary_(dcmDataDict.wrlock()) + { + } + + ~DictionaryLocker() + { + dcmDataDict.unlock(); + } + + DcmDataDictionary& operator*() + { + return dictionary_; + } + + DcmDataDictionary* operator->() + { + return &dictionary_; + } + }; + } + + + void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary) + { + LOG(INFO) << "Using DCTMK version: " << DCMTK_VERSION_NUMBER; + + { + DictionaryLocker locker; + + locker->clear(); + +#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 + LOG(WARNING) << "Loading the embedded dictionaries"; + /** + * Do not load DICONDE dictionary, it breaks the other tags. The + * command "strace storescu 2>&1 |grep dic" shows that DICONDE + * dictionary is not loaded by storescu. + **/ + //LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICONDE); + + LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICOM); + + 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__) || defined(__FreeBSD__) || defined(__OpenBSD__) + std::string path = DCMTK_DICTIONARY_DIR; + + const char* env = std::getenv(DCM_DICT_ENVIRONMENT_VARIABLE); + if (env != NULL) + { + path = std::string(env); + } + + LoadExternalDictionary(*locker, path, "dicom.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 +#endif + } + + /* make sure data dictionary is loaded */ + if (!dcmDataDict.isDictionaryLoaded()) + { + LOG(ERROR) << "No DICOM dictionary loaded, check environment variable: " << DCM_DICT_ENVIRONMENT_VARIABLE; + throw OrthancException(ErrorCode_InternalError); + } + + { + // Test the dictionary with a simple DICOM tag + DcmTag key(0x0010, 0x1030); // This is PatientWeight + if (key.getEVR() != EVR_DS) + { + LOG(ERROR) << "The DICOM dictionary has not been correctly read"; + throw OrthancException(ErrorCode_InternalError); + } + } + } + + + void FromDcmtkBridge::RegisterDictionaryTag(const DicomTag& tag, + ValueRepresentation vr, + const std::string& name, + unsigned int minMultiplicity, + unsigned int maxMultiplicity, + const std::string& privateCreator) + { + if (minMultiplicity < 1) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + bool arbitrary = false; + if (maxMultiplicity == 0) + { + maxMultiplicity = DcmVariableVM; + arbitrary = true; + } + else if (maxMultiplicity < minMultiplicity) + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + DcmEVR evr = ToDcmtkBridge::Convert(vr); + + LOG(INFO) << "Registering tag in dictionary: " << tag << " " << (DcmVR(evr).getValidVRName()) << " " + << name << " (multiplicity: " << minMultiplicity << "-" + << (arbitrary ? "n" : boost::lexical_cast<std::string>(maxMultiplicity)) << ")"; + + 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()); + } + } + + + Encoding FromDcmtkBridge::DetectEncoding(DcmItem& dataset, + Encoding defaultEncoding) + { + Encoding encoding = defaultEncoding; + + OFString tmp; + if (dataset.findAndGetOFString(DCM_SpecificCharacterSet, tmp).good()) + { + std::string characterSet = Toolbox::StripSpaces(std::string(tmp.c_str())); + + if (characterSet.empty()) + { + // Empty specific character set tag: Use the default encoding + } + else if (GetDicomEncoding(encoding, characterSet.c_str())) + { + // The specific character set is supported by the Orthanc core + } + else + { + LOG(WARNING) << "Value of Specific Character Set (0008,0005) is not supported: " << characterSet + << ", fallback to ASCII (remove all special characters)"; + encoding = Encoding_Ascii; + } + } + else + { + // No specific character set tag: Use the default encoding + } + + return encoding; + } + + + void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target, + DcmItem& dataset, + unsigned int maxStringLength, + Encoding defaultEncoding) + { + std::set<DicomTag> ignoreTagLength; + + Encoding encoding = DetectEncoding(dataset, defaultEncoding); + + target.Clear(); + for (unsigned long i = 0; i < dataset.card(); i++) + { + DcmElement* element = dataset.getElement(i); + if (element && element->isLeaf()) + { + target.SetValue(element->getTag().getGTag(), + element->getTag().getETag(), + ConvertLeafElement(*element, DicomToJsonFlags_Default, + maxStringLength, encoding, ignoreTagLength)); + } + } + } + + + DicomTag FromDcmtkBridge::Convert(const DcmTag& tag) + { + return DicomTag(tag.getGTag(), tag.getETag()); + } + + + DicomTag FromDcmtkBridge::GetTag(const DcmElement& element) + { + return DicomTag(element.getGTag(), element.getETag()); + } + + + DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element, + DicomToJsonFlags flags, + unsigned int maxStringLength, + Encoding encoding, + const std::set<DicomTag>& ignoreTagLength) + { + if (!element.isLeaf()) + { + // This function is only applicable to leaf elements + throw OrthancException(ErrorCode_BadParameterType); + } + + char *c = NULL; + if (element.isaString() && + element.getString(c).good()) + { + if (c == NULL) // This case corresponds to the empty string + { + return new DicomValue("", false); + } + else + { + std::string s(c); + std::string utf8 = Toolbox::ConvertToUtf8(s, encoding); + + if (maxStringLength != 0 && + utf8.size() > maxStringLength && + ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end()) + { + return new DicomValue; // Too long, create a NULL value + } + else + { + return new DicomValue(utf8, false); + } + } + } + + + 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 && + ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end()) + { + 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 + switch (element.getVR()) + { + + /** + * Deal with binary data (including PixelData). + **/ + + case EVR_OB: // other byte + case EVR_OF: // other float + case EVR_OW: // other word + case EVR_UN: // unknown value representation + case EVR_ox: // OB or OW depending on context + case EVR_DS: // decimal string + case EVR_IS: // integer string + case EVR_AS: // age string + case EVR_DA: // date string + case EVR_DT: // date time string + case EVR_TM: // time string + case EVR_AE: // application entity title + case EVR_CS: // code string + case EVR_SH: // short string + case EVR_LO: // long string + case EVR_ST: // short text + case EVR_LT: // long text + case EVR_UT: // unlimited text + case EVR_PN: // person name + case EVR_UI: // unique identifier + case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) + case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR + { + if (!(flags & DicomToJsonFlags_ConvertBinaryToNull)) + { + Uint8* data = NULL; + if (element.getUint8Array(data) == EC_Normal) + { + return new DicomValue(reinterpret_cast<const char*>(data), element.getLength(), true); + } + } + + return new DicomValue; + } + + /** + * Numeric types + **/ + + case EVR_SL: // signed long + { + Sint32 f; + if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good()) + return new DicomValue(boost::lexical_cast<std::string>(f), false); + else + return new DicomValue; + } + + case EVR_SS: // signed short + { + Sint16 f; + if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good()) + return new DicomValue(boost::lexical_cast<std::string>(f), false); + else + return new DicomValue; + } + + case EVR_UL: // unsigned long + { + Uint32 f; + if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good()) + return new DicomValue(boost::lexical_cast<std::string>(f), false); + else + return new DicomValue; + } + + case EVR_US: // unsigned short + { + Uint16 f; + if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good()) + return new DicomValue(boost::lexical_cast<std::string>(f), false); + else + return new DicomValue; + } + + case EVR_FL: // float single-precision + { + Float32 f; + if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good()) + return new DicomValue(boost::lexical_cast<std::string>(f), false); + else + return new DicomValue; + } + + case EVR_FD: // float double-precision + { + Float64 f; + if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good()) + return new DicomValue(boost::lexical_cast<std::string>(f), false); + else + return new DicomValue; + } + + + /** + * Attribute tag. + **/ + + case EVR_AT: + { + DcmTagKey tag; + if (dynamic_cast<DcmAttributeTag&>(element).getTagVal(tag, 0).good()) + { + DicomTag t(tag.getGroup(), tag.getElement()); + return new DicomValue(t.Format(), false); + } + else + { + return new DicomValue; + } + } + + + /** + * Sequence types, should never occur at this point because of + * "element.isLeaf()". + **/ + + case EVR_SQ: // sequence of items + return new DicomValue; + + + /** + * Internal to DCMTK. + **/ + + case EVR_xs: // SS or US depending on context + case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) + case EVR_na: // na="not applicable", for data which has no VR + case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor + case EVR_item: // used internally for items + case EVR_metainfo: // used internally for meta info datasets + case EVR_dataset: // used internally for datasets + case EVR_fileFormat: // used internally for DICOM files + case EVR_dicomDir: // used internally for DICOMDIR objects + case EVR_dirRecord: // used internally for DICOMDIR records + case EVR_pixelSQ: // used internally for pixel sequences in a compressed image + case EVR_pixelItem: // used internally for pixel items in a compressed image + case EVR_PixelData: // used internally for uncompressed pixeld data + case EVR_OverlayData: // used internally for overlay data + return new DicomValue; + + + /** + * Default case. + **/ + + default: + return new DicomValue; + } + } + catch (boost::bad_lexical_cast) + { + return new DicomValue; + } + catch (std::bad_cast) + { + return new DicomValue; + } + } + + + static Json::Value& PrepareNode(Json::Value& parent, + DcmElement& element, + DicomToJsonFormat format) + { + assert(parent.type() == Json::objectValue); + + DicomTag tag(FromDcmtkBridge::GetTag(element)); + const std::string formattedTag = tag.Format(); + + if (format == DicomToJsonFormat_Short) + { + parent[formattedTag] = Json::nullValue; + return parent[formattedTag]; + } + + // This code gives access to the name of the private tags + std::string tagName = FromDcmtkBridge::GetTagName(element); + + switch (format) + { + case DicomToJsonFormat_Human: + parent[tagName] = Json::nullValue; + return parent[tagName]; + + case DicomToJsonFormat_Full: + { + parent[formattedTag] = Json::objectValue; + Json::Value& node = parent[formattedTag]; + + if (element.isLeaf()) + { + node["Name"] = tagName; + + if (element.getTag().getPrivateCreator() != NULL) + { + node["PrivateCreator"] = element.getTag().getPrivateCreator(); + } + + return node; + } + else + { + node["Name"] = tagName; + node["Type"] = "Sequence"; + node["Value"] = Json::nullValue; + return node["Value"]; + } + } + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + static void LeafValueToJson(Json::Value& target, + const DicomValue& value, + DicomToJsonFormat format, + DicomToJsonFlags flags, + unsigned int maxStringLength) + { + Json::Value* targetValue = NULL; + Json::Value* targetType = NULL; + + switch (format) + { + case DicomToJsonFormat_Short: + case DicomToJsonFormat_Human: + { + assert(target.type() == Json::nullValue); + targetValue = ⌖ + break; + } + + case DicomToJsonFormat_Full: + { + assert(target.type() == Json::objectValue); + target["Value"] = Json::nullValue; + target["Type"] = Json::nullValue; + targetType = &target["Type"]; + targetValue = &target["Value"]; + break; + } + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + assert(targetValue != NULL); + assert(targetValue->type() == Json::nullValue); + assert(targetType == NULL || targetType->type() == Json::nullValue); + + if (value.IsNull()) + { + if (targetType != NULL) + { + *targetType = "Null"; + } + } + else if (value.IsBinary()) + { + if (flags & DicomToJsonFlags_ConvertBinaryToAscii) + { + *targetValue = Toolbox::ConvertToAscii(value.GetContent()); + } + else + { + std::string s; + value.FormatDataUriScheme(s); + *targetValue = s; + } + + if (targetType != NULL) + { + *targetType = "Binary"; + } + } + else if (maxStringLength == 0 || + value.GetContent().size() <= maxStringLength) + { + *targetValue = value.GetContent(); + + if (targetType != NULL) + { + *targetType = "String"; + } + } + else + { + if (targetType != NULL) + { + *targetType = "TooLong"; + } + } + } + + + void FromDcmtkBridge::ElementToJson(Json::Value& parent, + DcmElement& element, + DicomToJsonFormat format, + DicomToJsonFlags flags, + unsigned int maxStringLength, + Encoding encoding, + const std::set<DicomTag>& ignoreTagLength) + { + if (parent.type() == Json::nullValue) + { + parent = Json::objectValue; + } + + assert(parent.type() == Json::objectValue); + Json::Value& target = PrepareNode(parent, element, format); + + if (element.isLeaf()) + { + // The "0" below lets "LeafValueToJson()" take care of "TooLong" values + std::auto_ptr<DicomValue> v(FromDcmtkBridge::ConvertLeafElement + (element, flags, 0, encoding, ignoreTagLength)); + + if (ignoreTagLength.find(GetTag(element)) == ignoreTagLength.end()) + { + LeafValueToJson(target, *v, format, flags, maxStringLength); + } + else + { + LeafValueToJson(target, *v, format, flags, 0); + } + } + else + { + assert(target.type() == Json::nullValue); + target = Json::arrayValue; + + // "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 i = 0; i < sequence.card(); i++) + { + DcmItem* child = sequence.getItem(i); + Json::Value& v = target.append(Json::objectValue); + DatasetToJson(v, *child, format, flags, maxStringLength, encoding, ignoreTagLength); + } + } + } + + + void FromDcmtkBridge::DatasetToJson(Json::Value& parent, + DcmItem& item, + DicomToJsonFormat format, + DicomToJsonFlags flags, + unsigned int maxStringLength, + Encoding encoding, + const std::set<DicomTag>& ignoreTagLength) + { + assert(parent.type() == Json::objectValue); + + for (unsigned long i = 0; i < item.card(); i++) + { + DcmElement* element = item.getElement(i); + if (element == NULL) + { + throw OrthancException(ErrorCode_InternalError); + } + + DicomTag tag(FromDcmtkBridge::Convert(element->getTag())); + + /*element->getTag().isPrivate()*/ + if (tag.IsPrivate() && + !(flags & DicomToJsonFlags_IncludePrivateTags)) + { + continue; + } + + if (!(flags & DicomToJsonFlags_IncludeUnknownTags)) + { + DictionaryLocker locker; + if (locker->findEntry(element->getTag(), NULL) == NULL) + { + continue; + } + } + + DcmEVR evr = element->getTag().getEVR(); + if (evr == EVR_OB || + evr == EVR_OF || + evr == EVR_OW || + evr == EVR_UN || + evr == EVR_ox) + { + // This is a binary tag + if ((tag == DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludePixelData)) || + (tag != DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludeBinary))) + { + continue; + } + } + + FromDcmtkBridge::ElementToJson(parent, *element, format, flags, + maxStringLength, encoding, ignoreTagLength); + } + } + + + void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target, + DcmDataset& dataset, + DicomToJsonFormat format, + DicomToJsonFlags flags, + unsigned int maxStringLength, + Encoding defaultEncoding, + const std::set<DicomTag>& ignoreTagLength) + { + Encoding encoding = DetectEncoding(dataset, defaultEncoding); + + target = Json::objectValue; + DatasetToJson(target, dataset, format, flags, maxStringLength, encoding, ignoreTagLength); + } + + + void FromDcmtkBridge::ExtractHeaderAsJson(Json::Value& target, + DcmMetaInfo& dataset, + DicomToJsonFormat format, + DicomToJsonFlags flags, + unsigned int maxStringLength) + { + std::set<DicomTag> ignoreTagLength; + target = Json::objectValue; + DatasetToJson(target, dataset, format, flags, maxStringLength, Encoding_Ascii, ignoreTagLength); + } + + + + static std::string GetTagNameInternal(DcmTag& tag) + { + { + // 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 + } + +#if 0 + // This version explicitly calls the dictionary + const DcmDataDictionary& dict = dcmDataDict.rdlock(); + const DcmDictEntry* entry = dict.findEntry(tag, NULL); + + std::string s(DcmTag_ERROR_TagName); + if (entry != NULL) + { + s = std::string(entry->getTagName()); + } + + dcmDataDict.unlock(); + return s; +#else + const char* name = tag.getTagName(); + if (name == NULL) + { + return DcmTag_ERROR_TagName; + } + else + { + return std::string(name); + } +#endif + } + + + 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 && + isxdigit(name[0]) && + isxdigit(name[1]) && + isxdigit(name[2]) && + isxdigit(name[3]) && + (name[4] == '-' || name[4] == ',') && + isxdigit(name[5]) && + isxdigit(name[6]) && + isxdigit(name[7]) && + isxdigit(name[8])) + { + uint16_t group = GetTagValue(name); + uint16_t element = GetTagValue(name + 5); + return DicomTag(group, element); + } + + if (strlen(name) == 8 && + isxdigit(name[0]) && + isxdigit(name[1]) && + isxdigit(name[2]) && + isxdigit(name[3]) && + isxdigit(name[4]) && + isxdigit(name[5]) && + isxdigit(name[6]) && + isxdigit(name[7])) + { + uint16_t group = GetTagValue(name); + uint16_t element = GetTagValue(name + 4); + return DicomTag(group, element); + } + +#if 0 + const DcmDataDictionary& dict = dcmDataDict.rdlock(); + const DcmDictEntry* entry = dict.findEntry(name); + + if (entry == NULL) + { + dcmDataDict.unlock(); + throw OrthancException(ErrorCode_UnknownDicomTag); + } + else + { + DcmTagKey key = entry->getKey(); + DicomTag tag(key.getGroup(), key.getElement()); + dcmDataDict.unlock(); + return tag; + } +#else + DcmTag tag; + if (DcmTag::findTagFromName(name, tag).good()) + { + return DicomTag(tag.getGTag(), tag.getETag()); + } + else + { + throw OrthancException(ErrorCode_UnknownDicomTag); + } +#endif + } + + + bool FromDcmtkBridge::IsUnknownTag(const DicomTag& tag) + { + DcmTag tmp(tag.GetGroup(), tag.GetElement()); + return tmp.isUnknownVR(); + } + + + void FromDcmtkBridge::ToJson(Json::Value& result, + const DicomMap& values, + bool simplify) + { + if (result.type() != Json::objectValue) + { + throw OrthancException(ErrorCode_BadParameterType); + } + + result.clear(); + + 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[tagName] = Json::nullValue; + } + else + { + // TODO IsBinary + result[tagName] = it->second->GetContent(); + } + } + else + { + Json::Value value = Json::objectValue; + + value["Name"] = tagName; + + if (it->second->IsNull()) + { + value["Type"] = "Null"; + value["Value"] = Json::nullValue; + } + else + { + // TODO IsBinary + value["Type"] = "String"; + value["Value"] = it->second->GetContent(); + } + + result[it->first.Format()] = value; + } + } + } + + + std::string FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType level) + { + char uid[100]; + + switch (level) + { + case ResourceType_Patient: + // 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 SystemToolbox::GenerateUuid(); + + case ResourceType_Instance: + return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT); + + case ResourceType_Series: + return dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT); + + case ResourceType_Study: + return dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT); + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, + DcmDataset& dataSet) + { + // Determine the transfer syntax which shall be used to write the + // information to the file. We always switch to the Little Endian + // syntax, with explicit length. + + // http://support.dcmtk.org/docs/dcxfer_8h-source.html + + + /** + * Note that up to Orthanc 0.7.1 (inclusive), the + * "EXS_LittleEndianExplicit" was always used to save the DICOM + * dataset into memory. We now keep the original transfer syntax + * (if available). + **/ + E_TransferSyntax xfer = dataSet.getOriginalXfer(); + if (xfer == EXS_Unknown) + { + // No information about the original transfer syntax: This is + // most probably a DICOM dataset that was read from memory. + xfer = EXS_LittleEndianExplicit; + } + + E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength; + + // Create the meta-header information + DcmFileFormat ff(&dataSet); + ff.validateMetaInfo(xfer); + ff.removeInvalidGroups(); + + // Create a memory buffer with the proper size + { + const uint32_t estimatedSize = ff.calcElementLength(xfer, encodingType); // (*) + buffer.resize(estimatedSize); + } + + DcmOutputBufferStream ob(&buffer[0], buffer.size()); + + // Fill the memory buffer with the meta-header and the dataset + ff.transferInit(); + OFCondition c = ff.write(ob, xfer, encodingType, NULL, + /*opt_groupLength*/ EGL_recalcGL, + /*opt_paddingType*/ EPD_withoutPadding); + ff.transferEnd(); + + if (c.good()) + { + // The DICOM file is successfully written, truncate the target + // buffer if its size was overestimated by (*) + ob.flush(); + + size_t effectiveSize = static_cast<size_t>(ob.tell()); + if (effectiveSize < buffer.size()) + { + buffer.resize(effectiveSize); + } + + return true; + } + else + { + // Error + buffer.clear(); + return false; + } + } + + + ValueRepresentation FromDcmtkBridge::LookupValueRepresentation(const DicomTag& tag) + { + DcmTag t(tag.GetGroup(), tag.GetElement()); + return Convert(t.getEVR()); + } + + ValueRepresentation FromDcmtkBridge::Convert(const DcmEVR vr) + { + switch (vr) + { + case EVR_AE: + return ValueRepresentation_ApplicationEntity; + + case EVR_AS: + return ValueRepresentation_AgeString; + + case EVR_AT: + return ValueRepresentation_AttributeTag; + + case EVR_CS: + return ValueRepresentation_CodeString; + + case EVR_DA: + return ValueRepresentation_Date; + + case EVR_DS: + return ValueRepresentation_DecimalString; + + case EVR_DT: + return ValueRepresentation_DateTime; + + case EVR_FL: + return ValueRepresentation_FloatingPointSingle; + + case EVR_FD: + return ValueRepresentation_FloatingPointDouble; + + case EVR_IS: + return ValueRepresentation_IntegerString; + + case EVR_LO: + return ValueRepresentation_LongString; + + case EVR_LT: + return ValueRepresentation_LongText; + + case EVR_OB: + return ValueRepresentation_OtherByte; + + // Not supported as of DCMTK 3.6.0 + /*case EVR_OD: + return ValueRepresentation_OtherDouble;*/ + + case EVR_OF: + return ValueRepresentation_OtherFloat; + + // Not supported as of DCMTK 3.6.0 + /*case EVR_OL: + return ValueRepresentation_OtherLong;*/ + + case EVR_OW: + return ValueRepresentation_OtherWord; + + case EVR_PN: + return ValueRepresentation_PersonName; + + case EVR_SH: + return ValueRepresentation_ShortString; + + case EVR_SL: + return ValueRepresentation_SignedLong; + + case EVR_SQ: + return ValueRepresentation_Sequence; + + case EVR_SS: + return ValueRepresentation_SignedShort; + + case EVR_ST: + return ValueRepresentation_ShortText; + + case EVR_TM: + return ValueRepresentation_Time; + + // Not supported as of DCMTK 3.6.0 + /*case EVR_UC: + return ValueRepresentation_UnlimitedCharacters;*/ + + case EVR_UI: + return ValueRepresentation_UniqueIdentifier; + + case EVR_UL: + return ValueRepresentation_UnsignedLong; + + case EVR_UN: + return ValueRepresentation_Unknown; + + // Not supported as of DCMTK 3.6.0 + /*case EVR_UR: + return ValueRepresentation_UniversalResource;*/ + + case EVR_US: + return ValueRepresentation_UnsignedShort; + + case EVR_UT: + return ValueRepresentation_UnlimitedText; + + default: + return ValueRepresentation_NotSupported; + } + } + + + static bool IsBinaryTag(const DcmTag& key) + { + return (key.isUnknownVR() || + key.getEVR() == EVR_OB || + key.getEVR() == EVR_OF || + key.getEVR() == EVR_OW || + key.getEVR() == EVR_UN || + key.getEVR() == EVR_ox); + } + + + DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag) + { + DcmTag key(tag.GetGroup(), tag.GetElement()); + + if (tag.IsPrivate() || + IsBinaryTag(key)) + { + return new DcmOtherByteOtherWord(key); + } + + switch (key.getEVR()) + { + // http://support.dcmtk.org/docs/dcvr_8h-source.html + + /** + * Binary types, handled above + **/ + + case EVR_OB: // other byte + case EVR_OF: // other float + case EVR_OW: // other word + case EVR_UN: // unknown value representation + case EVR_ox: // OB or OW depending on context + throw OrthancException(ErrorCode_InternalError); + + + /** + * String types. + * http://support.dcmtk.org/docs/classDcmByteString.html + **/ + + case EVR_AS: // age string + return new DcmAgeString(key); + + case EVR_AE: // application entity title + return new DcmApplicationEntity(key); + + case EVR_CS: // code string + return new DcmCodeString(key); + + case EVR_DA: // date string + return new DcmDate(key); + + case EVR_DT: // date time string + return new DcmDateTime(key); + + case EVR_DS: // decimal string + return new DcmDecimalString(key); + + case EVR_IS: // integer string + return new DcmIntegerString(key); + + case EVR_TM: // time string + return new DcmTime(key); + + case EVR_UI: // unique identifier + return new DcmUniqueIdentifier(key); + + case EVR_ST: // short text + return new DcmShortText(key); + + case EVR_LO: // long string + return new DcmLongString(key); + + case EVR_LT: // long text + return new DcmLongText(key); + + case EVR_UT: // unlimited text + return new DcmUnlimitedText(key); + + case EVR_SH: // short string + return new DcmShortString(key); + + case EVR_PN: // person name + return new DcmPersonName(key); + + + /** + * Numerical types + **/ + + case EVR_SL: // signed long + return new DcmSignedLong(key); + + case EVR_SS: // signed short + return new DcmSignedShort(key); + + case EVR_UL: // unsigned long + return new DcmUnsignedLong(key); + + case EVR_US: // unsigned short + return new DcmUnsignedShort(key); + + case EVR_FL: // float single-precision + return new DcmFloatingPointSingle(key); + + case EVR_FD: // float double-precision + return new DcmFloatingPointDouble(key); + + + /** + * Sequence types, should never occur at this point. + **/ + + case EVR_SQ: // sequence of items + throw OrthancException(ErrorCode_ParameterOutOfRange); + + + /** + * TODO + **/ + + case EVR_AT: // attribute tag + throw OrthancException(ErrorCode_NotImplemented); + + + /** + * Internal to DCMTK. + **/ + + case EVR_xs: // SS or US depending on context + case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) + case EVR_na: // na="not applicable", for data which has no VR + case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor + case EVR_item: // used internally for items + case EVR_metainfo: // used internally for meta info datasets + case EVR_dataset: // used internally for datasets + case EVR_fileFormat: // used internally for DICOM files + case EVR_dicomDir: // used internally for DICOMDIR objects + case EVR_dirRecord: // used internally for DICOMDIR records + case EVR_pixelSQ: // used internally for pixel sequences in a compressed image + case EVR_pixelItem: // used internally for pixel items in a compressed image + case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) + case EVR_PixelData: // used internally for uncompressed pixeld data + case EVR_OverlayData: // used internally for overlay data + case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR + default: + break; + } + + throw OrthancException(ErrorCode_InternalError); + } + + + + void FromDcmtkBridge::FillElementWithString(DcmElement& element, + const DicomTag& tag, + const std::string& utf8Value, + bool decodeDataUriScheme, + Encoding dicomEncoding) + { + std::string binary; + const std::string* decoded = &utf8Value; + + if (decodeDataUriScheme && + boost::starts_with(utf8Value, "data:application/octet-stream;base64,")) + { + std::string mime; + if (!Toolbox::DecodeDataUriScheme(mime, binary, utf8Value)) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + decoded = &binary; + } + else if (dicomEncoding != Encoding_Utf8) + { + binary = Toolbox::ConvertFromUtf8(utf8Value, dicomEncoding); + decoded = &binary; + } + + DcmTag key(tag.GetGroup(), tag.GetElement()); + + if (tag.IsPrivate() || + IsBinaryTag(key)) + { + if (element.putUint8Array((const Uint8*) decoded->c_str(), decoded->size()).good()) + { + return; + } + else + { + throw OrthancException(ErrorCode_InternalError); + } + } + + bool ok = false; + + try + { + switch (key.getEVR()) + { + // http://support.dcmtk.org/docs/dcvr_8h-source.html + + /** + * TODO. + **/ + + case EVR_OB: // other byte + case EVR_OF: // other float + case EVR_OW: // other word + case EVR_AT: // attribute tag + throw OrthancException(ErrorCode_NotImplemented); + + case EVR_UN: // unknown value representation + throw OrthancException(ErrorCode_ParameterOutOfRange); + + + /** + * String types. + **/ + + case EVR_DS: // decimal string + case EVR_IS: // integer string + case EVR_AS: // age string + case EVR_DA: // date string + case EVR_DT: // date time string + case EVR_TM: // time string + case EVR_AE: // application entity title + case EVR_CS: // code string + case EVR_SH: // short string + case EVR_LO: // long string + case EVR_ST: // short text + case EVR_LT: // long text + case EVR_UT: // unlimited text + case EVR_PN: // person name + case EVR_UI: // unique identifier + { + ok = element.putString(decoded->c_str()).good(); + break; + } + + + /** + * Numerical types + **/ + + case EVR_SL: // signed long + { + ok = element.putSint32(boost::lexical_cast<Sint32>(*decoded)).good(); + break; + } + + case EVR_SS: // signed short + { + ok = element.putSint16(boost::lexical_cast<Sint16>(*decoded)).good(); + break; + } + + case EVR_UL: // unsigned long + { + ok = element.putUint32(boost::lexical_cast<Uint32>(*decoded)).good(); + break; + } + + case EVR_US: // unsigned short + { + ok = element.putUint16(boost::lexical_cast<Uint16>(*decoded)).good(); + break; + } + + case EVR_FL: // float single-precision + { + ok = element.putFloat32(boost::lexical_cast<float>(*decoded)).good(); + break; + } + + case EVR_FD: // float double-precision + { + ok = element.putFloat64(boost::lexical_cast<double>(*decoded)).good(); + break; + } + + + /** + * Sequence types, should never occur at this point. + **/ + + case EVR_SQ: // sequence of items + { + ok = false; + break; + } + + + /** + * Internal to DCMTK. + **/ + + case EVR_ox: // OB or OW depending on context + case EVR_xs: // SS or US depending on context + case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) + case EVR_na: // na="not applicable", for data which has no VR + case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor + case EVR_item: // used internally for items + case EVR_metainfo: // used internally for meta info datasets + case EVR_dataset: // used internally for datasets + case EVR_fileFormat: // used internally for DICOM files + case EVR_dicomDir: // used internally for DICOMDIR objects + case EVR_dirRecord: // used internally for DICOMDIR records + case EVR_pixelSQ: // used internally for pixel sequences in a compressed image + case EVR_pixelItem: // used internally for pixel items in a compressed image + case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) + case EVR_PixelData: // used internally for uncompressed pixeld data + case EVR_OverlayData: // used internally for overlay data + case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR + default: + break; + } + } + catch (boost::bad_lexical_cast&) + { + ok = false; + } + + if (!ok) + { + LOG(ERROR) << "While creating a DICOM instance, tag (" << tag.Format() + << ") has out-of-range value: \"" << *decoded << "\""; + throw OrthancException(ErrorCode_BadFileFormat); + } + } + + + DcmElement* FromDcmtkBridge::FromJson(const DicomTag& tag, + const Json::Value& value, + bool decodeDataUriScheme, + Encoding dicomEncoding) + { + std::auto_ptr<DcmElement> element; + + switch (value.type()) + { + case Json::stringValue: + element.reset(CreateElementForTag(tag)); + 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()); + if (key.getEVR() != EVR_SQ) + { + throw OrthancException(ErrorCode_BadParameterType); + } + + DcmSequenceOfItems* sequence = new DcmSequenceOfItems(key); + element.reset(sequence); + + for (Json::Value::ArrayIndex i = 0; i < value.size(); i++) + { + std::auto_ptr<DcmItem> item(new DcmItem); + + Json::Value::Members members = value[i].getMemberNames(); + for (Json::Value::ArrayIndex j = 0; j < members.size(); j++) + { + item->insert(FromJson(ParseTag(members[j]), value[i][members[j]], decodeDataUriScheme, dicomEncoding)); + } + + sequence->append(item.release()); + } + + break; + } + + default: + throw OrthancException(ErrorCode_BadParameterType); + } + + return element.release(); + } + + + DcmPixelSequence* FromDcmtkBridge::GetPixelSequence(DcmDataset& dataset) + { + DcmElement *element = NULL; + if (!dataset.findAndGetElement(DCM_PixelData, element).good()) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(*element); + DcmPixelSequence* pixelSequence = NULL; + if (!pixelData.getEncapsulatedRepresentation + (dataset.getOriginalXfer(), NULL, pixelSequence).good()) + { + return NULL; + } + else + { + return pixelSequence; + } + } + + + Encoding FromDcmtkBridge::ExtractEncoding(const Json::Value& json, + Encoding defaultEncoding) + { + if (json.type() != Json::objectValue) + { + throw OrthancException(ErrorCode_BadParameterType); + } + + Encoding encoding = defaultEncoding; + + const Json::Value::Members tags = json.getMemberNames(); + + // Look for SpecificCharacterSet (0008,0005) in the JSON file + for (size_t i = 0; i < tags.size(); i++) + { + DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]); + if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) + { + const Json::Value& value = json[tags[i]]; + if (value.type() != Json::stringValue || + (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; + } + } + } + + return encoding; + } + + + static void SetString(DcmDataset& target, + const DcmTag& tag, + const std::string& value) + { + if (!target.putAndInsertString(tag, value.c_str()).good()) + { + throw OrthancException(ErrorCode_InternalError); + } + } + + + DcmDataset* FromDcmtkBridge::FromJson(const Json::Value& json, // Encoded using UTF-8 + bool generateIdentifiers, + bool decodeDataUriScheme, + Encoding defaultEncoding) + { + std::auto_ptr<DcmDataset> result(new DcmDataset); + Encoding encoding = ExtractEncoding(json, defaultEncoding); + + SetString(*result, DCM_SpecificCharacterSet, GetDicomSpecificCharacterSet(encoding)); + + const Json::Value::Members tags = json.getMemberNames(); + + bool hasPatientId = false; + bool hasStudyInstanceUid = false; + bool hasSeriesInstanceUid = false; + bool hasSopInstanceUid = false; + + for (size_t i = 0; i < tags.size(); i++) + { + DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]); + const Json::Value& value = json[tags[i]]; + + if (tag == DICOM_TAG_PATIENT_ID) + { + hasPatientId = true; + } + else if (tag == DICOM_TAG_STUDY_INSTANCE_UID) + { + hasStudyInstanceUid = true; + } + else if (tag == DICOM_TAG_SERIES_INSTANCE_UID) + { + hasSeriesInstanceUid = true; + } + else if (tag == DICOM_TAG_SOP_INSTANCE_UID) + { + hasSopInstanceUid = true; + } + + if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET) + { + std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding)); + const DcmTagKey& tag = element->getTag(); + + result->findAndDeleteElement(tag); + + DcmElement* tmp = element.release(); + if (!result->insert(tmp, false, false).good()) + { + delete tmp; + throw OrthancException(ErrorCode_InternalError); + } + } + } + + if (!hasPatientId && + generateIdentifiers) + { + SetString(*result, DCM_PatientID, GenerateUniqueIdentifier(ResourceType_Patient)); + } + + if (!hasStudyInstanceUid && + generateIdentifiers) + { + SetString(*result, DCM_StudyInstanceUID, GenerateUniqueIdentifier(ResourceType_Study)); + } + + if (!hasSeriesInstanceUid && + generateIdentifiers) + { + SetString(*result, DCM_SeriesInstanceUID, GenerateUniqueIdentifier(ResourceType_Series)); + } + + if (!hasSopInstanceUid && + generateIdentifiers) + { + SetString(*result, DCM_SOPInstanceUID, GenerateUniqueIdentifier(ResourceType_Instance)); + } + + return result.release(); + } + + + DcmFileFormat* FromDcmtkBridge::LoadFromMemoryBuffer(const void* buffer, + size_t size) + { + DcmInputBufferStream is; + if (size > 0) + { + is.setBuffer(buffer, size); + } + is.setEos(); + + std::auto_ptr<DcmFileFormat> result(new DcmFileFormat); + + result->transferInit(); + if (!result->read(is).good()) + { + LOG(ERROR) << "Cannot parse an invalid DICOM file (size: " << size << " bytes)"; + throw OrthancException(ErrorCode_BadFileFormat); + } + + result->loadAllDataIntoMemory(); + result->transferEnd(); + + return result.release(); + } + + + void FromDcmtkBridge::FromJson(DicomMap& target, + const Json::Value& source) + { + if (source.type() != Json::objectValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + target.Clear(); + + Json::Value::Members members = source.getMemberNames(); + + for (size_t i = 0; i < members.size(); i++) + { + const Json::Value& value = source[members[i]]; + + if (value.type() != Json::stringValue) + { + throw OrthancException(ErrorCode_BadFileFormat); + } + + 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; + } + } + + +#if ORTHANC_ENABLE_LUA == 1 + 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); + } + } +#endif + + + void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target, + DcmItem& dataset) + { + ExtractDicomSummary(target, dataset, + ORTHANC_MAXIMUM_TAG_LENGTH, + GetDefaultDicomEncoding()); + } + + + void FromDcmtkBridge::ExtractDicomAsJson(Json::Value& target, + DcmDataset& dataset, + const std::set<DicomTag>& ignoreTagLength) + { + ExtractDicomAsJson(target, dataset, + DicomToJsonFormat_Full, + DicomToJsonFlags_Default, + ORTHANC_MAXIMUM_TAG_LENGTH, + GetDefaultDicomEncoding(), + ignoreTagLength); + } + + + void FromDcmtkBridge::InitializeCodecs() + { +#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 + LOG(WARNING) << "Registering JPEG Lossless codecs in DCMTK"; + DJLSDecoderRegistration::registerCodecs(); +#endif + +#if ORTHANC_ENABLE_DCMTK_JPEG == 1 + LOG(WARNING) << "Registering JPEG codecs in DCMTK"; + DJDecoderRegistration::registerCodecs(); +#endif + } + + + void FromDcmtkBridge::FinalizeCodecs() + { +#if ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS == 1 + // Unregister JPEG-LS codecs + DJLSDecoderRegistration::cleanup(); +#endif + +#if ORTHANC_ENABLE_DCMTK_JPEG == 1 + // Unregister JPEG codecs + DJDecoderRegistration::cleanup(); +#endif + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Orthanc/Core/DicomParsing/FromDcmtkBridge.h Thu Jan 04 10:49:34 2018 +0100 @@ -0,0 +1,244 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "../DicomFormat/DicomElement.h" +#include "../DicomFormat/DicomMap.h" + +#include <dcmtk/dcmdata/dcdatset.h> +#include <dcmtk/dcmdata/dcmetinf.h> +#include <dcmtk/dcmdata/dcpixseq.h> +#include <dcmtk/dcmdata/dcfilefo.h> +#include <json/json.h> + +#if !defined(ORTHANC_ENABLE_LUA) +# error The macro ORTHANC_ENABLE_LUA must be defined +#endif + +#if ORTHANC_ENABLE_DCMTK != 1 +# error The macro ORTHANC_ENABLE_DCMTK must be set to 1 +#endif + +#if ORTHANC_BUILD_UNIT_TESTS == 1 +# include <gtest/gtest_prod.h> +#endif + +#if ORTHANC_ENABLE_LUA == 1 +# include "../Lua/LuaFunctionCall.h" +#endif + +#if !defined(ORTHANC_ENABLE_DCMTK_JPEG) +# error The macro ORTHANC_ENABLE_DCMTK_JPEG must be defined +#endif + +#if !defined(ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS) +# error The macro ORTHANC_ENABLE_DCMTK_JPEG_LOSSLESS must be defined +#endif + + +namespace Orthanc +{ + class FromDcmtkBridge : public boost::noncopyable + { +#if ORTHANC_BUILD_UNIT_TESTS == 1 + FRIEND_TEST(FromDcmtkBridge, FromJson); +#endif + + friend class ParsedDicomFile; + + 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, + const std::set<DicomTag>& ignoreTagLength); + + static void ElementToJson(Json::Value& parent, + DcmElement& element, + DicomToJsonFormat format, + DicomToJsonFlags flags, + unsigned int maxStringLength, + Encoding dicomEncoding, + const std::set<DicomTag>& ignoreTagLength); + + static void ExtractDicomAsJson(Json::Value& target, + DcmDataset& dataset, + DicomToJsonFormat format, + DicomToJsonFlags flags, + unsigned int maxStringLength, + Encoding defaultEncoding, + const std::set<DicomTag>& ignoreTagLength); + + static void ChangeStringEncoding(DcmItem& dataset, + Encoding source, + Encoding target); + + public: + static void InitializeDictionary(bool loadPrivateDictionary); + + static void RegisterDictionaryTag(const DicomTag& tag, + ValueRepresentation vr, + const std::string& name, + unsigned int minMultiplicity, + unsigned int maxMultiplicity, + const std::string& privateCreator); + + static Encoding DetectEncoding(DcmItem& dataset, + Encoding defaultEncoding); + + static DicomTag Convert(const DcmTag& tag); + + static DicomTag GetTag(const DcmElement& element); + + static bool IsUnknownTag(const DicomTag& tag); + + static DicomValue* ConvertLeafElement(DcmElement& element, + DicomToJsonFlags flags, + unsigned int maxStringLength, + Encoding encoding, + const std::set<DicomTag>& ignoreTagLength); + + static void ExtractHeaderAsJson(Json::Value& target, + DcmMetaInfo& header, + DicomToJsonFormat format, + DicomToJsonFlags flags, + unsigned int maxStringLength); + + static std::string GetTagName(const DicomTag& tag, + const std::string& privateCreator); + + static std::string GetTagName(const DcmElement& element); + + static std::string GetTagName(const DicomElement& element) + { + return GetTagName(element.GetTag(), ""); + } + + static DicomTag ParseTag(const char* name); + + static DicomTag ParseTag(const std::string& name) + { + return ParseTag(name.c_str()); + } + + static bool HasTag(const DicomMap& fields, + const std::string& tagName) + { + return fields.HasTag(ParseTag(tagName)); + } + + static const DicomValue& GetValue(const DicomMap& fields, + const std::string& tagName) + { + return fields.GetValue(ParseTag(tagName)); + } + + static void SetValue(DicomMap& target, + const std::string& tagName, + DicomValue* value) + { + target.SetValue(ParseTag(tagName), value); + } + + static void ToJson(Json::Value& result, + const DicomMap& values, + bool simplify); + + static std::string GenerateUniqueIdentifier(ResourceType level); + + static bool SaveToMemoryBuffer(std::string& buffer, + DcmDataset& dataSet); + + static ValueRepresentation Convert(DcmEVR vr); + + static ValueRepresentation LookupValueRepresentation(const DicomTag& tag); + + static DcmElement* CreateElementForTag(const DicomTag& tag); + + static void FillElementWithString(DcmElement& element, + const DicomTag& tag, + const std::string& utf8alue, // Encoded using UTF-8 + bool decodeDataUriScheme, + Encoding dicomEncoding); + + static DcmElement* FromJson(const DicomTag& tag, + const Json::Value& element, // Encoded using UTF-8 + bool decodeDataUriScheme, + Encoding dicomEncoding); + + static DcmPixelSequence* GetPixelSequence(DcmDataset& dataset); + + static Encoding ExtractEncoding(const Json::Value& json, + Encoding defaultEncoding); + + static DcmDataset* FromJson(const Json::Value& json, // Encoded using UTF-8 + bool generateIdentifiers, + bool decodeDataUriScheme, + Encoding defaultEncoding); + + static DcmFileFormat* LoadFromMemoryBuffer(const void* buffer, + size_t size); + + static void FromJson(DicomMap& values, + const Json::Value& result); + + static bool LookupTransferSyntax(std::string& result, + DcmFileFormat& dicom); + +#if ORTHANC_ENABLE_LUA == 1 + static void ExecuteToDicom(DicomMap& target, + LuaFunctionCall& call); +#endif + + static void ExtractDicomSummary(DicomMap& target, + DcmItem& dataset); + + static void ExtractDicomAsJson(Json::Value& target, + DcmDataset& dataset, + const std::set<DicomTag>& ignoreTagLength); + + static void InitializeCodecs(); + + static void FinalizeCodecs(); + }; +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Orthanc/Core/DicomParsing/ToDcmtkBridge.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -0,0 +1,150 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 "ToDcmtkBridge.h" + +#include <memory> +#include <dcmtk/dcmnet/diutil.h> + +#include "../OrthancException.h" + + +namespace Orthanc +{ + DcmEVR ToDcmtkBridge::Convert(ValueRepresentation vr) + { + switch (vr) + { + case ValueRepresentation_ApplicationEntity: + return EVR_AE; + + case ValueRepresentation_AgeString: + return EVR_AS; + + case ValueRepresentation_AttributeTag: + return EVR_AT; + + case ValueRepresentation_CodeString: + return EVR_CS; + + case ValueRepresentation_Date: + return EVR_DA; + + case ValueRepresentation_DecimalString: + return EVR_DS; + + case ValueRepresentation_DateTime: + return EVR_DT; + + case ValueRepresentation_FloatingPointSingle: + return EVR_FL; + + case ValueRepresentation_FloatingPointDouble: + return EVR_FD; + + case ValueRepresentation_IntegerString: + return EVR_IS; + + case ValueRepresentation_LongString: + return EVR_LO; + + case ValueRepresentation_LongText: + return EVR_LT; + + case ValueRepresentation_OtherByte: + return EVR_OB; + + // Not supported as of DCMTK 3.6.0 + /*case ValueRepresentation_OtherDouble: + return EVR_OD;*/ + + case ValueRepresentation_OtherFloat: + return EVR_OF; + + // Not supported as of DCMTK 3.6.0 + /*case ValueRepresentation_OtherLong: + return EVR_OL;*/ + + case ValueRepresentation_OtherWord: + return EVR_OW; + + case ValueRepresentation_PersonName: + return EVR_PN; + + case ValueRepresentation_ShortString: + return EVR_SH; + + case ValueRepresentation_SignedLong: + return EVR_SL; + + case ValueRepresentation_Sequence: + return EVR_SQ; + + case ValueRepresentation_SignedShort: + return EVR_SS; + + case ValueRepresentation_ShortText: + return EVR_ST; + + case ValueRepresentation_Time: + return EVR_TM; + + // Not supported as of DCMTK 3.6.0 + /*case ValueRepresentation_UnlimitedCharacters: + return EVR_UC;*/ + + case ValueRepresentation_UniqueIdentifier: + return EVR_UI; + + case ValueRepresentation_UnsignedLong: + return EVR_UL; + + case ValueRepresentation_Unknown: + return EVR_UN; + + // Not supported as of DCMTK 3.6.0 + /*case ValueRepresentation_UniversalResource: + return EVR_UR;*/ + + case ValueRepresentation_UnsignedShort: + return EVR_US; + + case ValueRepresentation_UnlimitedText: + return EVR_UT; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } +}
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Orthanc/Core/DicomParsing/ToDcmtkBridge.h Thu Jan 04 10:49:34 2018 +0100 @@ -0,0 +1,55 @@ +/** + * Orthanc - A Lightweight, RESTful DICOM Store + * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics + * Department, University Hospital of Liege, Belgium + * Copyright (C) 2017-2018 Osimis S.A., 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 + +#if ORTHANC_ENABLE_DCMTK != 1 +# error The macro ORTHANC_ENABLE_DCMTK must be set to 1 +#endif + +#include "../DicomFormat/DicomMap.h" +#include <dcmtk/dcmdata/dcdatset.h> + +namespace Orthanc +{ + class ToDcmtkBridge + { + public: + static DcmTagKey Convert(const DicomTag& tag) + { + return DcmTagKey(tag.GetGroup(), tag.GetElement()); + } + + static DcmEVR Convert(ValueRepresentation vr); + }; +}
--- a/Resources/Orthanc/Core/Endianness.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Endianness.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -35,10 +35,15 @@ /******************************************************************** - ** LINUX ARCHITECTURES + ** LINUX-LIKE ARCHITECTURES ********************************************************************/ -#if defined(__linux__) +#if defined(__LSB_VERSION__) +// Linux Standard Base (LSB) does not come with be16toh, be32toh, and +// be64toh +# define ORTHANC_HAS_BUILTIN_BYTE_SWAP 0 +# include <endian.h> +#elif defined(__linux__) || defined(__EMSCRIPTEN__) # define ORTHANC_HAS_BUILTIN_BYTE_SWAP 1 # include <endian.h> #endif @@ -155,4 +160,38 @@ static_cast<uint64_t>(p[7])); } +#if defined(__BYTE_ORDER) && defined(__LITTLE_ENDIAN) && defined(__BIG_ENDIAN) +# if __BYTE_ORDER == __LITTLE_ENDIAN +# define be16toh(x) __orthanc_bswap16(x) +# define be32toh(x) __orthanc_bswap32(x) +# define be64toh(x) __orthanc_bswap64(x) +# define htobe16(x) __orthanc_bswap16(x) +# define htobe32(x) __orthanc_bswap32(x) +# define htobe64(x) __orthanc_bswap64(x) +# define htole16(x) x +# define htole32(x) x +# define htole64(x) x +# define le16toh(x) x +# define le32toh(x) x +# define le64toh(x) x +# elif __BYTE_ORDER == __BIG_ENDIAN +# define be16toh(x) x +# define be32toh(x) x +# define be64toh(x) x +# define htobe16(x) x +# define htobe32(x) x +# define htobe64(x) x +# define htole16(x) __orthanc_bswap16(x) +# define htole32(x) __orthanc_bswap32(x) +# define htole64(x) __orthanc_bswap64(x) +# define le16toh(x) __orthanc_bswap16(x) +# define le32toh(x) __orthanc_bswap32(x) +# define le64toh(x) __orthanc_bswap64(x) +# else +# error Please support your platform here +# endif +#else +# error Please support your platform here #endif + +#endif
--- a/Resources/Orthanc/Core/EnumerationDictionary.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/EnumerationDictionary.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Enumerations.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Enumerations.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -38,6 +38,7 @@ #include "Toolbox.h" #include "Logging.h" +#include <boost/thread/mutex.hpp> #include <string.h> #include <cassert> @@ -752,12 +753,128 @@ case PixelFormat_Float32: return "Grayscale (float 32bpp)"; + case PixelFormat_Grayscale32: + return "Grayscale (unsigned 32bpp)"; + + case PixelFormat_RGB48: + return "RGB48"; + default: throw OrthancException(ErrorCode_ParameterOutOfRange); } } + const char* EnumerationToString(ModalityManufacturer manufacturer) + { + switch (manufacturer) + { + case ModalityManufacturer_Generic: + return "Generic"; + + case ModalityManufacturer_GenericNoWildcardInDates: + return "GenericNoWildcardInDates"; + + case ModalityManufacturer_GenericNoUniversalWildcard: + return "GenericNoUniversalWildcard"; + + case ModalityManufacturer_StoreScp: + return "StoreScp"; + + case ModalityManufacturer_ClearCanvas: + return "ClearCanvas"; + + case ModalityManufacturer_Dcm4Chee: + return "Dcm4Chee"; + + case ModalityManufacturer_Vitrea: + return "Vitrea"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + const char* EnumerationToString(DicomRequestType type) + { + switch (type) + { + case DicomRequestType_Echo: + return "Echo"; + break; + + case DicomRequestType_Find: + return "Find"; + break; + + case DicomRequestType_Get: + return "Get"; + break; + + case DicomRequestType_Move: + return "Move"; + break; + + case DicomRequestType_Store: + return "Store"; + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + const char* EnumerationToString(TransferSyntax syntax) + { + switch (syntax) + { + case TransferSyntax_Deflated: + return "Deflated"; + + case TransferSyntax_Jpeg: + return "JPEG"; + + case TransferSyntax_Jpeg2000: + return "JPEG2000"; + + case TransferSyntax_JpegLossless: + return "JPEG Lossless"; + + case TransferSyntax_Jpip: + return "JPIP"; + + case TransferSyntax_Mpeg2: + return "MPEG2"; + + case TransferSyntax_Rle: + return "RLE"; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + + const char* EnumerationToString(DicomVersion version) + { + switch (version) + { + case DicomVersion_2008: + return "2008"; + break; + + case DicomVersion_2017c: + return "2017c"; + break; + + default: + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + Encoding StringToEncoding(const char* encoding) { std::string s(encoding); @@ -1127,6 +1244,86 @@ } + ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer) + { + ModalityManufacturer result; + bool obsolete = false; + + if (manufacturer == "Generic") + { + return ModalityManufacturer_Generic; + } + else if (manufacturer == "GenericNoWildcardInDates") + { + return ModalityManufacturer_GenericNoWildcardInDates; + } + else if (manufacturer == "GenericNoUniversalWildcard") + { + return ModalityManufacturer_GenericNoUniversalWildcard; + } + else if (manufacturer == "ClearCanvas") + { + return ModalityManufacturer_ClearCanvas; + } + else if (manufacturer == "StoreScp") + { + return ModalityManufacturer_StoreScp; + } + else if (manufacturer == "Dcm4Chee") + { + return ModalityManufacturer_Dcm4Chee; + } + else if (manufacturer == "Vitrea") + { + return ModalityManufacturer_Vitrea; + } + else if (manufacturer == "AgfaImpax" || + manufacturer == "SyngoVia") + { + result = ModalityManufacturer_GenericNoWildcardInDates; + obsolete = true; + } + else if (manufacturer == "EFilm2" || + manufacturer == "MedInria") + { + result = ModalityManufacturer_Generic; + obsolete = true; + } + else + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + + if (obsolete) + { + LOG(WARNING) << "The \"" << manufacturer << "\" manufacturer is obsolete since " + << "Orthanc 1.3.0. To guarantee compatibility with future Orthanc " + << "releases, you should replace it by \"" + << EnumerationToString(result) + << "\" in your configuration file."; + } + + return result; + } + + + DicomVersion StringToDicomVersion(const std::string& version) + { + if (version == "2008") + { + return DicomVersion_2008; + } + else if (version == "2017c") + { + return DicomVersion_2017c; + } + else + { + throw OrthancException(ErrorCode_ParameterOutOfRange); + } + } + + unsigned int GetBytesPerPixel(PixelFormat format) { switch (format) @@ -1143,12 +1340,16 @@ case PixelFormat_RGBA32: case PixelFormat_BGRA32: + case PixelFormat_Grayscale32: return 4; case PixelFormat_Float32: assert(sizeof(float) == 4); return 4; + case PixelFormat_RGB48: + return 6; + default: throw OrthancException(ErrorCode_ParameterOutOfRange); } @@ -1225,8 +1426,15 @@ { encoding = Encoding_Japanese; } - else if (s == "GB18030") + else if (s == "GB18030" || s == "GBK") { + /** + * According to tumashu@163.com, "In China, many dicom file's + * 0008,0005 tag is set as "GBK", instead of "GB18030", GBK is a + * subset of GB18030, and which is used frequently in China, + * suggest support it." + * https://groups.google.com/d/msg/orthanc-users/WMM8LMbjpUc/02-1f_yFCgAJ + **/ encoding = Encoding_Chinese; } /* @@ -1475,5 +1683,28 @@ default: throw OrthancException(ErrorCode_ParameterOutOfRange); } + } + + + static boost::mutex defaultEncodingMutex_; // Should not be necessary + static Encoding defaultEncoding_ = ORTHANC_DEFAULT_DICOM_ENCODING; + + Encoding GetDefaultDicomEncoding() + { + boost::mutex::scoped_lock lock(defaultEncodingMutex_); + return defaultEncoding_; } + + void SetDefaultDicomEncoding(Encoding encoding) + { + std::string name = EnumerationToString(encoding); + + { + boost::mutex::scoped_lock lock(defaultEncodingMutex_); + defaultEncoding_ = encoding; + } + + LOG(INFO) << "Default encoding for DICOM was changed to: " << name; + } + }
--- a/Resources/Orthanc/Core/Enumerations.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Enumerations.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -199,8 +199,21 @@ **/ PixelFormat_Float32 = 6, - // This is the memory layout for Cairo - PixelFormat_BGRA32 = 7 + // This is the memory layout for Cairo (for internal use in Stone of Orthanc) + PixelFormat_BGRA32 = 7, + + /** + * {summary}{Graylevel, unsigned 32bpp image.} + * {description}{The image is graylevel. Each pixel is unsigned and stored in 4 bytes.} + **/ + PixelFormat_Grayscale32 = 8, + + /** + * {summary}{Color image in RGB48 format.} + * {description}{This format describes a color image. The pixels are stored in 6 + * consecutive bytes. The memory layout is RGB.} + **/ + PixelFormat_RGB48 = 9 }; @@ -443,6 +456,81 @@ ValueRepresentation_NotSupported // Not supported by Orthanc, or tag not in dictionary }; + enum DicomReplaceMode + { + DicomReplaceMode_InsertIfAbsent, + DicomReplaceMode_ThrowIfAbsent, + DicomReplaceMode_IgnoreIfAbsent + }; + + enum DicomToJsonFormat + { + DicomToJsonFormat_Full, + DicomToJsonFormat_Short, + DicomToJsonFormat_Human + }; + + enum DicomToJsonFlags + { + DicomToJsonFlags_IncludeBinary = (1 << 0), + DicomToJsonFlags_IncludePrivateTags = (1 << 1), + DicomToJsonFlags_IncludeUnknownTags = (1 << 2), + DicomToJsonFlags_IncludePixelData = (1 << 3), + DicomToJsonFlags_ConvertBinaryToAscii = (1 << 4), + DicomToJsonFlags_ConvertBinaryToNull = (1 << 5), + + // Some predefined combinations + DicomToJsonFlags_None = 0, + DicomToJsonFlags_Default = (DicomToJsonFlags_IncludeBinary | + DicomToJsonFlags_IncludePixelData | + DicomToJsonFlags_IncludePrivateTags | + DicomToJsonFlags_IncludeUnknownTags | + DicomToJsonFlags_ConvertBinaryToNull) + }; + + enum DicomFromJsonFlags + { + DicomFromJsonFlags_DecodeDataUriScheme = (1 << 0), + DicomFromJsonFlags_GenerateIdentifiers = (1 << 1) + }; + + enum DicomVersion + { + DicomVersion_2008, + DicomVersion_2017c + }; + + enum ModalityManufacturer + { + ModalityManufacturer_Generic, + ModalityManufacturer_GenericNoWildcardInDates, + ModalityManufacturer_GenericNoUniversalWildcard, + ModalityManufacturer_StoreScp, + ModalityManufacturer_ClearCanvas, + ModalityManufacturer_Dcm4Chee, + ModalityManufacturer_Vitrea + }; + + enum DicomRequestType + { + DicomRequestType_Echo, + DicomRequestType_Find, + DicomRequestType_Get, + DicomRequestType_Move, + DicomRequestType_Store + }; + + enum TransferSyntax + { + TransferSyntax_Deflated, + TransferSyntax_Jpeg, + TransferSyntax_Jpeg2000, + TransferSyntax_JpegLossless, + TransferSyntax_Jpip, + TransferSyntax_Mpeg2, + TransferSyntax_Rle + }; + /** * WARNING: Do not change the explicit values in the enumerations @@ -513,6 +601,14 @@ const char* EnumerationToString(PixelFormat format); + const char* EnumerationToString(ModalityManufacturer manufacturer); + + const char* EnumerationToString(DicomRequestType type); + + const char* EnumerationToString(TransferSyntax syntax); + + const char* EnumerationToString(DicomVersion version); + Encoding StringToEncoding(const char* encoding); ResourceType StringToResourceType(const char* type); @@ -525,6 +621,10 @@ bool throwIfUnsupported); PhotometricInterpretation StringToPhotometricInterpretation(const char* value); + + ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer); + + DicomVersion StringToDicomVersion(const std::string& version); unsigned int GetBytesPerPixel(PixelFormat format); @@ -544,4 +644,8 @@ bool IsUserContentType(FileContentType type); bool IsBinaryValueRepresentation(ValueRepresentation vr); + + Encoding GetDefaultDicomEncoding(); + + void SetDefaultDicomEncoding(Encoding encoding); }
--- a/Resources/Orthanc/Core/HttpClient.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/HttpClient.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/HttpClient.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/HttpClient.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/ICommand.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/ICommand.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/IDynamicObject.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/IDynamicObject.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/IImageWriter.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/IImageWriter.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/IImageWriter.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/IImageWriter.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/Image.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/Image.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/Image.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/Image.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/ImageAccessor.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/ImageAccessor.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -218,6 +218,10 @@ ToMatlabStringInternal<uint16_t>(buffer, *this); break; + case PixelFormat_Grayscale32: + ToMatlabStringInternal<uint32_t>(buffer, *this); + break; + case PixelFormat_SignedGrayscale16: ToMatlabStringInternal<int16_t>(buffer, *this); break;
--- a/Resources/Orthanc/Core/Images/ImageAccessor.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/ImageAccessor.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/ImageBuffer.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/ImageBuffer.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/ImageBuffer.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/ImageBuffer.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/ImageProcessing.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/ImageProcessing.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -413,6 +413,13 @@ } if (target.GetFormat() == PixelFormat_Float32 && + source.GetFormat() == PixelFormat_Grayscale32) + { + ConvertGrayscaleToFloat<uint32_t>(target, source); + return; + } + + if (target.GetFormat() == PixelFormat_Float32 && source.GetFormat() == PixelFormat_SignedGrayscale16) { ConvertGrayscaleToFloat<int16_t>(target, source); @@ -561,6 +568,26 @@ return; } + if (target.GetFormat() == PixelFormat_RGB24 && + source.GetFormat() == PixelFormat_RGB48) + { + for (unsigned int y = 0; y < source.GetHeight(); y++) + { + const uint16_t* p = reinterpret_cast<const uint16_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[0] >> 8; + q[1] = p[1] >> 8; + q[2] = p[2] >> 8; + p += 3; + q += 3; + } + } + + return; + } + throw OrthancException(ErrorCode_NotImplemented); } @@ -579,6 +606,10 @@ SetInternal<uint16_t>(image, value); return; + case PixelFormat_Grayscale32: + SetInternal<uint32_t>(image, value); + return; + case PixelFormat_SignedGrayscale16: SetInternal<int16_t>(image, value); return; @@ -664,9 +695,9 @@ } - void ImageProcessing::GetMinMaxValue(int64_t& minValue, - int64_t& maxValue, - const ImageAccessor& image) + void ImageProcessing::GetMinMaxIntegerValue(int64_t& minValue, + int64_t& maxValue, + const ImageAccessor& image) { switch (image.GetFormat()) { @@ -688,6 +719,15 @@ break; } + case PixelFormat_Grayscale32: + { + uint32_t a, b; + GetMinMaxValueInternal<uint32_t>(a, b, image); + minValue = a; + maxValue = b; + break; + } + case PixelFormat_SignedGrayscale16: { int16_t a, b; @@ -703,6 +743,28 @@ } + void ImageProcessing::GetMinMaxFloatValue(float& minValue, + float& maxValue, + const ImageAccessor& image) + { + switch (image.GetFormat()) + { + case PixelFormat_Float32: + { + assert(sizeof(float) == 32); + float a, b; + GetMinMaxValueInternal<float>(a, b, image); + minValue = a; + maxValue = b; + break; + } + + default: + throw OrthancException(ErrorCode_NotImplemented); + } + } + + void ImageProcessing::AddConstant(ImageAccessor& image, int64_t value)
--- a/Resources/Orthanc/Core/Images/ImageProcessing.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/ImageProcessing.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -60,9 +60,13 @@ static void ShiftRight(ImageAccessor& target, unsigned int shift); - static void GetMinMaxValue(int64_t& minValue, - int64_t& maxValue, - const ImageAccessor& image); + static void GetMinMaxIntegerValue(int64_t& minValue, + int64_t& maxValue, + const ImageAccessor& image); + + static void GetMinMaxFloatValue(float& minValue, + float& maxValue, + const ImageAccessor& image); static void AddConstant(ImageAccessor& image, int64_t value);
--- a/Resources/Orthanc/Core/Images/JpegErrorManager.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/JpegErrorManager.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/JpegErrorManager.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/JpegErrorManager.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -32,6 +32,14 @@ #pragma once +#if !defined(ORTHANC_ENABLE_JPEG) +# error The macro ORTHANC_ENABLE_JPEG must be defined +#endif + +#if ORTHANC_ENABLE_JPEG != 1 +# error JPEG support must be enabled to include this file +#endif + #include <string.h> #include <stdio.h> #include <jpeglib.h>
--- a/Resources/Orthanc/Core/Images/JpegReader.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/JpegReader.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/JpegReader.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/JpegReader.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,15 +33,23 @@ #pragma once +#if !defined(ORTHANC_SANDBOXED) +# error The macro ORTHANC_SANDBOXED must be defined +#endif + +#if !defined(ORTHANC_ENABLE_JPEG) +# error The macro ORTHANC_ENABLE_JPEG must be defined +#endif + +#if ORTHANC_ENABLE_JPEG != 1 +# error JPEG support must be enabled to include this file +#endif + #include "ImageAccessor.h" #include <string> #include <boost/noncopyable.hpp> -#if !defined(ORTHANC_SANDBOXED) -# error The macro ORTHANC_SANDBOXED must be defined -#endif - namespace Orthanc { class JpegReader :
--- a/Resources/Orthanc/Core/Images/JpegWriter.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/JpegWriter.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -162,6 +162,7 @@ #endif +#if ORTHANC_SANDBOXED == 0 void JpegWriter::WriteToMemoryInternal(std::string& jpeg, unsigned int width, unsigned int height, @@ -206,4 +207,5 @@ jpeg.assign(reinterpret_cast<const char*>(data), size); free(data); } +#endif }
--- a/Resources/Orthanc/Core/Images/JpegWriter.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/JpegWriter.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +33,14 @@ #pragma once +#if !defined(ORTHANC_ENABLE_JPEG) +# error The macro ORTHANC_ENABLE_JPEG must be defined +#endif + +#if ORTHANC_ENABLE_JPEG != 1 +# error JPEG support must be enabled to include this file +#endif + #include "IImageWriter.h" namespace Orthanc
--- a/Resources/Orthanc/Core/Images/PngReader.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/PngReader.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Images/PngReader.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/PngReader.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +33,14 @@ #pragma once +#if !defined(ORTHANC_ENABLE_PNG) +# error The macro ORTHANC_ENABLE_PNG must be defined +#endif + +#if ORTHANC_ENABLE_PNG != 1 +# error PNG support must be enabled to include this file +#endif + #include "ImageAccessor.h" #include "../Enumerations.h"
--- a/Resources/Orthanc/Core/Images/PngWriter.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/PngWriter.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -248,6 +248,7 @@ +#if ORTHANC_SANDBOXED == 0 void PngWriter::WriteToMemoryInternal(std::string& png, unsigned int width, unsigned int height, @@ -271,4 +272,5 @@ chunks.Flatten(png); } +#endif }
--- a/Resources/Orthanc/Core/Images/PngWriter.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Images/PngWriter.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -33,6 +33,14 @@ #pragma once +#if !defined(ORTHANC_ENABLE_PNG) +# error The macro ORTHANC_ENABLE_PNG must be defined +#endif + +#if ORTHANC_ENABLE_PNG != 1 +# error PNG support must be enabled to include this file +#endif + #include "IImageWriter.h" #include <boost/shared_ptr.hpp>
--- a/Resources/Orthanc/Core/Logging.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Logging.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Logging.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Logging.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/BagOfTasks.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/MultiThreading/BagOfTasks.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/MultiThreading/BagOfTasksProcessor.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/Semaphore.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/MultiThreading/Semaphore.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/Semaphore.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/MultiThreading/Semaphore.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/MultiThreading/SharedMessageQueue.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/OrthancException.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/OrthancException.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/PrecompiledHeaders.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/PrecompiledHeaders.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/PrecompiledHeaders.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/PrecompiledHeaders.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -50,7 +50,7 @@ #include <json/value.h> #if ORTHANC_ENABLE_PUGIXML == 1 -#include <pugixml.hpp> +# include <pugixml.hpp> #endif #include "Enumerations.h" @@ -58,4 +58,21 @@ #include "OrthancException.h" #include "Toolbox.h" +#if ORTHANC_ENABLE_DCMTK == 1 +# include "DicomParsing/ParsedDicomFile.h" + +// Headers from DCMTK used in Orthanc headers +# include <dcmtk/dcmdata/dcdatset.h> +# include <dcmtk/dcmdata/dcfilefo.h> +# include <dcmtk/dcmdata/dcmetinf.h> +# include <dcmtk/dcmdata/dcpixseq.h> #endif + +#if ORTHANC_ENABLE_DCMTK_NETWORKING == 1 +# include "DicomNetworking/DicomServer.h" + +// Headers from DCMTK used in Orthanc headers +# include <dcmtk/dcmnet/dimse.h> +#endif + +#endif
--- a/Resources/Orthanc/Core/SystemToolbox.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/SystemToolbox.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/SystemToolbox.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/SystemToolbox.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/TemporaryFile.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/TemporaryFile.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/TemporaryFile.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/TemporaryFile.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/Toolbox.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Toolbox.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -397,6 +397,7 @@ #endif +#if ORTHANC_ENABLE_LOCALE == 1 static const char* GetBoostLocaleEncoding(const Encoding sourceEncoding) { switch (sourceEncoding) @@ -463,6 +464,7 @@ throw OrthancException(ErrorCode_NotImplemented); } } +#endif #if ORTHANC_ENABLE_LOCALE == 1 @@ -532,7 +534,7 @@ for (size_t i = 0; i < size; i++, p++) { - if (*p > 127 || (*p != 0 && iscntrl(*p))) + if (*p > 127 || *p == 0 || iscntrl(*p)) { return false; } @@ -542,6 +544,12 @@ } + bool Toolbox::IsAsciiString(const std::string& s) + { + return IsAsciiString(s.c_str(), s.size()); + } + + std::string Toolbox::ConvertToAscii(const std::string& source) { std::string result;
--- a/Resources/Orthanc/Core/Toolbox.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/Toolbox.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -152,6 +152,8 @@ bool IsAsciiString(const void* data, size_t size); + bool IsAsciiString(const std::string& s); + std::string ConvertToAscii(const std::string& source); std::string StripSpaces(const std::string& source);
--- a/Resources/Orthanc/Core/WebServiceParameters.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/WebServiceParameters.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Core/WebServiceParameters.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Core/WebServiceParameters.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/OrthancServer/FromDcmtkBridge.cpp Tue Jan 02 10:01:35 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,2020 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, 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 "PrecompiledHeadersServer.h" - -#ifndef NOMINMAX -#define NOMINMAX -#endif - -#include "FromDcmtkBridge.h" -#include "ToDcmtkBridge.h" -#include "../Core/Logging.h" -#include "../Core/SystemToolbox.h" -#include "../Core/Toolbox.h" -#include "../Core/TemporaryFile.h" -#include "../Core/OrthancException.h" - -#include <list> -#include <limits> - -#include <boost/lexical_cast.hpp> -#include <boost/filesystem.hpp> -#include <boost/algorithm/string/predicate.hpp> - -#include <dcmtk/dcmdata/dcdeftag.h> -#include <dcmtk/dcmdata/dcdicent.h> -#include <dcmtk/dcmdata/dcdict.h> -#include <dcmtk/dcmdata/dcfilefo.h> -#include <dcmtk/dcmdata/dcostrmb.h> -#include <dcmtk/dcmdata/dcpixel.h> -#include <dcmtk/dcmdata/dcuid.h> -#include <dcmtk/dcmdata/dcistrmb.h> - -#include <dcmtk/dcmdata/dcvrae.h> -#include <dcmtk/dcmdata/dcvras.h> -#include <dcmtk/dcmdata/dcvrat.h> -#include <dcmtk/dcmdata/dcvrcs.h> -#include <dcmtk/dcmdata/dcvrda.h> -#include <dcmtk/dcmdata/dcvrds.h> -#include <dcmtk/dcmdata/dcvrdt.h> -#include <dcmtk/dcmdata/dcvrfd.h> -#include <dcmtk/dcmdata/dcvrfl.h> -#include <dcmtk/dcmdata/dcvris.h> -#include <dcmtk/dcmdata/dcvrlo.h> -#include <dcmtk/dcmdata/dcvrlt.h> -#include <dcmtk/dcmdata/dcvrpn.h> -#include <dcmtk/dcmdata/dcvrsh.h> -#include <dcmtk/dcmdata/dcvrsl.h> -#include <dcmtk/dcmdata/dcvrss.h> -#include <dcmtk/dcmdata/dcvrst.h> -#include <dcmtk/dcmdata/dcvrtm.h> -#include <dcmtk/dcmdata/dcvrui.h> -#include <dcmtk/dcmdata/dcvrul.h> -#include <dcmtk/dcmdata/dcvrus.h> -#include <dcmtk/dcmdata/dcvrut.h> - - -#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 -#include <EmbeddedResources.h> -#endif - - -namespace Orthanc -{ - static inline uint16_t GetCharValue(char c) - { - if (c >= '0' && c <= '9') - return c - '0'; - else if (c >= 'a' && c <= 'f') - return c - 'a' + 10; - else if (c >= 'A' && c <= 'F') - return c - 'A' + 10; - else - return 0; - } - - static inline uint16_t GetTagValue(const char* c) - { - return ((GetCharValue(c[0]) << 12) + - (GetCharValue(c[1]) << 8) + - (GetCharValue(c[2]) << 4) + - GetCharValue(c[3])); - } - - -#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 - static void LoadEmbeddedDictionary(DcmDataDictionary& dictionary, - EmbeddedResources::FileResourceId resource) - { - std::string content; - EmbeddedResources::GetFileResource(content, resource); - - TemporaryFile tmp; - tmp.Write(content); - - if (!dictionary.loadDictionary(tmp.GetPath().c_str())) - { - LOG(ERROR) << "Cannot read embedded dictionary. Under Windows, make sure that " - << "your TEMP directory does not contain special characters."; - throw OrthancException(ErrorCode_InternalError); - } - } - -#else - static void LoadExternalDictionary(DcmDataDictionary& dictionary, - const std::string& directory, - const std::string& filename) - { - boost::filesystem::path p = directory; - p = p / filename; - - LOG(WARNING) << "Loading the external DICOM dictionary " << p; - - if (!dictionary.loadDictionary(p.string().c_str())) - { - throw OrthancException(ErrorCode_InternalError); - } - } -#endif - - - namespace - { - class DictionaryLocker - { - private: - DcmDataDictionary& dictionary_; - - public: - DictionaryLocker() : dictionary_(dcmDataDict.wrlock()) - { - } - - ~DictionaryLocker() - { - dcmDataDict.unlock(); - } - - DcmDataDictionary& operator*() - { - return dictionary_; - } - - DcmDataDictionary* operator->() - { - return &dictionary_; - } - }; - } - - - void FromDcmtkBridge::InitializeDictionary(bool loadPrivateDictionary) - { - LOG(INFO) << "Using DCTMK version: " << DCMTK_VERSION_NUMBER; - - { - DictionaryLocker locker; - - locker->clear(); - -#if DCMTK_USE_EMBEDDED_DICTIONARIES == 1 - LOG(WARNING) << "Loading the embedded dictionaries"; - /** - * Do not load DICONDE dictionary, it breaks the other tags. The - * command "strace storescu 2>&1 |grep dic" shows that DICONDE - * dictionary is not loaded by storescu. - **/ - //LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICONDE); - - LoadEmbeddedDictionary(*locker, EmbeddedResources::DICTIONARY_DICOM); - - 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__) || defined(__FreeBSD__) || defined(__OpenBSD__) - std::string path = DCMTK_DICTIONARY_DIR; - - const char* env = std::getenv(DCM_DICT_ENVIRONMENT_VARIABLE); - if (env != NULL) - { - path = std::string(env); - } - - LoadExternalDictionary(*locker, path, "dicom.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 -#endif - } - - /* make sure data dictionary is loaded */ - if (!dcmDataDict.isDictionaryLoaded()) - { - LOG(ERROR) << "No DICOM dictionary loaded, check environment variable: " << DCM_DICT_ENVIRONMENT_VARIABLE; - throw OrthancException(ErrorCode_InternalError); - } - - { - // Test the dictionary with a simple DICOM tag - DcmTag key(0x0010, 0x1030); // This is PatientWeight - if (key.getEVR() != EVR_DS) - { - LOG(ERROR) << "The DICOM dictionary has not been correctly read"; - throw OrthancException(ErrorCode_InternalError); - } - } - } - - - void FromDcmtkBridge::RegisterDictionaryTag(const DicomTag& tag, - ValueRepresentation vr, - const std::string& name, - unsigned int minMultiplicity, - unsigned int maxMultiplicity, - const std::string& privateCreator) - { - if (minMultiplicity < 1) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - bool arbitrary = false; - if (maxMultiplicity == 0) - { - maxMultiplicity = DcmVariableVM; - arbitrary = true; - } - else if (maxMultiplicity < minMultiplicity) - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - DcmEVR evr = ToDcmtkBridge::Convert(vr); - - LOG(INFO) << "Registering tag in dictionary: " << tag << " " << (DcmVR(evr).getValidVRName()) << " " - << name << " (multiplicity: " << minMultiplicity << "-" - << (arbitrary ? "n" : boost::lexical_cast<std::string>(maxMultiplicity)) << ")"; - - 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()); - } - } - - - Encoding FromDcmtkBridge::DetectEncoding(DcmItem& dataset, - Encoding defaultEncoding) - { - Encoding encoding = defaultEncoding; - - OFString tmp; - if (dataset.findAndGetOFString(DCM_SpecificCharacterSet, tmp).good()) - { - std::string characterSet = Toolbox::StripSpaces(std::string(tmp.c_str())); - - if (characterSet.empty()) - { - // Empty specific character set tag: Use the default encoding - } - else if (GetDicomEncoding(encoding, characterSet.c_str())) - { - // The specific character set is supported by the Orthanc core - } - else - { - LOG(WARNING) << "Value of Specific Character Set (0008,0005) is not supported: " << characterSet - << ", fallback to ASCII (remove all special characters)"; - encoding = Encoding_Ascii; - } - } - else - { - // No specific character set tag: Use the default encoding - } - - return encoding; - } - - - void FromDcmtkBridge::ExtractDicomSummary(DicomMap& target, - DcmItem& dataset, - unsigned int maxStringLength, - Encoding defaultEncoding) - { - Encoding encoding = DetectEncoding(dataset, defaultEncoding); - - target.Clear(); - for (unsigned long i = 0; i < dataset.card(); i++) - { - DcmElement* element = dataset.getElement(i); - if (element && element->isLeaf()) - { - target.SetValue(element->getTag().getGTag(), - element->getTag().getETag(), - ConvertLeafElement(*element, DicomToJsonFlags_Default, maxStringLength, encoding)); - } - } - } - - - DicomTag FromDcmtkBridge::Convert(const DcmTag& tag) - { - return DicomTag(tag.getGTag(), tag.getETag()); - } - - - DicomTag FromDcmtkBridge::GetTag(const DcmElement& element) - { - return DicomTag(element.getGTag(), element.getETag()); - } - - - DicomValue* FromDcmtkBridge::ConvertLeafElement(DcmElement& element, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding encoding) - { - if (!element.isLeaf()) - { - // This function is only applicable to leaf elements - throw OrthancException(ErrorCode_BadParameterType); - } - - char *c = NULL; - if (element.isaString() && - element.getString(c).good()) - { - if (c == NULL) // This case corresponds to the empty string - { - return new DicomValue("", false); - } - else - { - std::string s(c); - std::string utf8 = Toolbox::ConvertToUtf8(s, encoding); - - if (maxStringLength != 0 && - utf8.size() > maxStringLength) - { - return new DicomValue; // Too long, create a NULL value - } - else - { - return new DicomValue(utf8, false); - } - } - } - - - 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 - switch (element.getVR()) - { - - /** - * Deal with binary data (including PixelData). - **/ - - case EVR_OB: // other byte - case EVR_OF: // other float - case EVR_OW: // other word - case EVR_UN: // unknown value representation - case EVR_ox: // OB or OW depending on context - case EVR_DS: // decimal string - case EVR_IS: // integer string - case EVR_AS: // age string - case EVR_DA: // date string - case EVR_DT: // date time string - case EVR_TM: // time string - case EVR_AE: // application entity title - case EVR_CS: // code string - case EVR_SH: // short string - case EVR_LO: // long string - case EVR_ST: // short text - case EVR_LT: // long text - case EVR_UT: // unlimited text - case EVR_PN: // person name - case EVR_UI: // unique identifier - case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) - case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR - { - if (!(flags & DicomToJsonFlags_ConvertBinaryToNull)) - { - Uint8* data = NULL; - if (element.getUint8Array(data) == EC_Normal) - { - return new DicomValue(reinterpret_cast<const char*>(data), element.getLength(), true); - } - } - - return new DicomValue; - } - - /** - * Numeric types - **/ - - case EVR_SL: // signed long - { - Sint32 f; - if (dynamic_cast<DcmSignedLong&>(element).getSint32(f).good()) - return new DicomValue(boost::lexical_cast<std::string>(f), false); - else - return new DicomValue; - } - - case EVR_SS: // signed short - { - Sint16 f; - if (dynamic_cast<DcmSignedShort&>(element).getSint16(f).good()) - return new DicomValue(boost::lexical_cast<std::string>(f), false); - else - return new DicomValue; - } - - case EVR_UL: // unsigned long - { - Uint32 f; - if (dynamic_cast<DcmUnsignedLong&>(element).getUint32(f).good()) - return new DicomValue(boost::lexical_cast<std::string>(f), false); - else - return new DicomValue; - } - - case EVR_US: // unsigned short - { - Uint16 f; - if (dynamic_cast<DcmUnsignedShort&>(element).getUint16(f).good()) - return new DicomValue(boost::lexical_cast<std::string>(f), false); - else - return new DicomValue; - } - - case EVR_FL: // float single-precision - { - Float32 f; - if (dynamic_cast<DcmFloatingPointSingle&>(element).getFloat32(f).good()) - return new DicomValue(boost::lexical_cast<std::string>(f), false); - else - return new DicomValue; - } - - case EVR_FD: // float double-precision - { - Float64 f; - if (dynamic_cast<DcmFloatingPointDouble&>(element).getFloat64(f).good()) - return new DicomValue(boost::lexical_cast<std::string>(f), false); - else - return new DicomValue; - } - - - /** - * Attribute tag. - **/ - - case EVR_AT: - { - DcmTagKey tag; - if (dynamic_cast<DcmAttributeTag&>(element).getTagVal(tag, 0).good()) - { - DicomTag t(tag.getGroup(), tag.getElement()); - return new DicomValue(t.Format(), false); - } - else - { - return new DicomValue; - } - } - - - /** - * Sequence types, should never occur at this point because of - * "element.isLeaf()". - **/ - - case EVR_SQ: // sequence of items - return new DicomValue; - - - /** - * Internal to DCMTK. - **/ - - case EVR_xs: // SS or US depending on context - case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) - case EVR_na: // na="not applicable", for data which has no VR - case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor - case EVR_item: // used internally for items - case EVR_metainfo: // used internally for meta info datasets - case EVR_dataset: // used internally for datasets - case EVR_fileFormat: // used internally for DICOM files - case EVR_dicomDir: // used internally for DICOMDIR objects - case EVR_dirRecord: // used internally for DICOMDIR records - case EVR_pixelSQ: // used internally for pixel sequences in a compressed image - case EVR_pixelItem: // used internally for pixel items in a compressed image - case EVR_PixelData: // used internally for uncompressed pixeld data - case EVR_OverlayData: // used internally for overlay data - return new DicomValue; - - - /** - * Default case. - **/ - - default: - return new DicomValue; - } - } - catch (boost::bad_lexical_cast) - { - return new DicomValue; - } - catch (std::bad_cast) - { - return new DicomValue; - } - } - - - static Json::Value& PrepareNode(Json::Value& parent, - DcmElement& element, - DicomToJsonFormat format) - { - assert(parent.type() == Json::objectValue); - - DicomTag tag(FromDcmtkBridge::GetTag(element)); - const std::string formattedTag = tag.Format(); - - if (format == DicomToJsonFormat_Short) - { - parent[formattedTag] = Json::nullValue; - return parent[formattedTag]; - } - - // This code gives access to the name of the private tags - std::string tagName = FromDcmtkBridge::GetTagName(element); - - switch (format) - { - case DicomToJsonFormat_Human: - parent[tagName] = Json::nullValue; - return parent[tagName]; - - case DicomToJsonFormat_Full: - { - parent[formattedTag] = Json::objectValue; - Json::Value& node = parent[formattedTag]; - - if (element.isLeaf()) - { - node["Name"] = tagName; - - if (element.getTag().getPrivateCreator() != NULL) - { - node["PrivateCreator"] = element.getTag().getPrivateCreator(); - } - - return node; - } - else - { - node["Name"] = tagName; - node["Type"] = "Sequence"; - node["Value"] = Json::nullValue; - return node["Value"]; - } - } - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - static void LeafValueToJson(Json::Value& target, - const DicomValue& value, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength) - { - Json::Value* targetValue = NULL; - Json::Value* targetType = NULL; - - switch (format) - { - case DicomToJsonFormat_Short: - case DicomToJsonFormat_Human: - { - assert(target.type() == Json::nullValue); - targetValue = ⌖ - break; - } - - case DicomToJsonFormat_Full: - { - assert(target.type() == Json::objectValue); - target["Value"] = Json::nullValue; - target["Type"] = Json::nullValue; - targetType = &target["Type"]; - targetValue = &target["Value"]; - break; - } - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - assert(targetValue != NULL); - assert(targetValue->type() == Json::nullValue); - assert(targetType == NULL || targetType->type() == Json::nullValue); - - if (value.IsNull()) - { - if (targetType != NULL) - { - *targetType = "Null"; - } - } - else if (value.IsBinary()) - { - if (flags & DicomToJsonFlags_ConvertBinaryToAscii) - { - *targetValue = Toolbox::ConvertToAscii(value.GetContent()); - } - else - { - std::string s; - value.FormatDataUriScheme(s); - *targetValue = s; - } - - if (targetType != NULL) - { - *targetType = "Binary"; - } - } - else if (maxStringLength == 0 || - value.GetContent().size() <= maxStringLength) - { - *targetValue = value.GetContent(); - - if (targetType != NULL) - { - *targetType = "String"; - } - } - else - { - if (targetType != NULL) - { - *targetType = "TooLong"; - } - } - } - - - void FromDcmtkBridge::ElementToJson(Json::Value& parent, - DcmElement& element, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding encoding) - { - if (parent.type() == Json::nullValue) - { - parent = Json::objectValue; - } - - assert(parent.type() == Json::objectValue); - Json::Value& target = PrepareNode(parent, element, format); - - if (element.isLeaf()) - { - // 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 - { - assert(target.type() == Json::nullValue); - target = Json::arrayValue; - - // "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 i = 0; i < sequence.card(); i++) - { - DcmItem* child = sequence.getItem(i); - Json::Value& v = target.append(Json::objectValue); - DatasetToJson(v, *child, format, flags, maxStringLength, encoding); - } - } - } - - - void FromDcmtkBridge::DatasetToJson(Json::Value& parent, - DcmItem& item, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding encoding) - { - assert(parent.type() == Json::objectValue); - - for (unsigned long i = 0; i < item.card(); i++) - { - DcmElement* element = item.getElement(i); - if (element == NULL) - { - throw OrthancException(ErrorCode_InternalError); - } - - DicomTag tag(FromDcmtkBridge::Convert(element->getTag())); - - /*element->getTag().isPrivate()*/ - if (tag.IsPrivate() && - !(flags & DicomToJsonFlags_IncludePrivateTags)) - { - continue; - } - - if (!(flags & DicomToJsonFlags_IncludeUnknownTags)) - { - DictionaryLocker locker; - if (locker->findEntry(element->getTag(), NULL) == NULL) - { - continue; - } - } - - DcmEVR evr = element->getTag().getEVR(); - if (evr == EVR_OB || - evr == EVR_OF || - evr == EVR_OW || - evr == EVR_UN || - evr == EVR_ox) - { - // This is a binary tag - if ((tag == DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludePixelData)) || - (tag != DICOM_TAG_PIXEL_DATA && !(flags & DicomToJsonFlags_IncludeBinary))) - { - continue; - } - } - - FromDcmtkBridge::ElementToJson(parent, *element, format, flags, maxStringLength, encoding); - } - } - - - 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, encoding); - } - - - 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); - } - - - - static std::string GetTagNameInternal(DcmTag& tag) - { - { - // 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 - } - -#if 0 - // This version explicitly calls the dictionary - const DcmDataDictionary& dict = dcmDataDict.rdlock(); - const DcmDictEntry* entry = dict.findEntry(tag, NULL); - - std::string s(DcmTag_ERROR_TagName); - if (entry != NULL) - { - s = std::string(entry->getTagName()); - } - - dcmDataDict.unlock(); - return s; -#else - const char* name = tag.getTagName(); - if (name == NULL) - { - return DcmTag_ERROR_TagName; - } - else - { - return std::string(name); - } -#endif - } - - - 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 && - isxdigit(name[0]) && - isxdigit(name[1]) && - isxdigit(name[2]) && - isxdigit(name[3]) && - (name[4] == '-' || name[4] == ',') && - isxdigit(name[5]) && - isxdigit(name[6]) && - isxdigit(name[7]) && - isxdigit(name[8])) - { - uint16_t group = GetTagValue(name); - uint16_t element = GetTagValue(name + 5); - return DicomTag(group, element); - } - - if (strlen(name) == 8 && - isxdigit(name[0]) && - isxdigit(name[1]) && - isxdigit(name[2]) && - isxdigit(name[3]) && - isxdigit(name[4]) && - isxdigit(name[5]) && - isxdigit(name[6]) && - isxdigit(name[7])) - { - uint16_t group = GetTagValue(name); - uint16_t element = GetTagValue(name + 4); - return DicomTag(group, element); - } - -#if 0 - const DcmDataDictionary& dict = dcmDataDict.rdlock(); - const DcmDictEntry* entry = dict.findEntry(name); - - if (entry == NULL) - { - dcmDataDict.unlock(); - throw OrthancException(ErrorCode_UnknownDicomTag); - } - else - { - DcmTagKey key = entry->getKey(); - DicomTag tag(key.getGroup(), key.getElement()); - dcmDataDict.unlock(); - return tag; - } -#else - DcmTag tag; - if (DcmTag::findTagFromName(name, tag).good()) - { - return DicomTag(tag.getGTag(), tag.getETag()); - } - else - { - throw OrthancException(ErrorCode_UnknownDicomTag); - } -#endif - } - - - bool FromDcmtkBridge::IsUnknownTag(const DicomTag& tag) - { - DcmTag tmp(tag.GetGroup(), tag.GetElement()); - return tmp.isUnknownVR(); - } - - - void FromDcmtkBridge::ToJson(Json::Value& result, - const DicomMap& values, - bool simplify) - { - if (result.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - result.clear(); - - 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[tagName] = Json::nullValue; - } - else - { - // TODO IsBinary - result[tagName] = it->second->GetContent(); - } - } - else - { - Json::Value value = Json::objectValue; - - value["Name"] = tagName; - - if (it->second->IsNull()) - { - value["Type"] = "Null"; - value["Value"] = Json::nullValue; - } - else - { - // TODO IsBinary - value["Type"] = "String"; - value["Value"] = it->second->GetContent(); - } - - result[it->first.Format()] = value; - } - } - } - - - std::string FromDcmtkBridge::GenerateUniqueIdentifier(ResourceType level) - { - char uid[100]; - - switch (level) - { - case ResourceType_Patient: - // 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 SystemToolbox::GenerateUuid(); - - case ResourceType_Instance: - return dcmGenerateUniqueIdentifier(uid, SITE_INSTANCE_UID_ROOT); - - case ResourceType_Series: - return dcmGenerateUniqueIdentifier(uid, SITE_SERIES_UID_ROOT); - - case ResourceType_Study: - return dcmGenerateUniqueIdentifier(uid, SITE_STUDY_UID_ROOT); - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - bool FromDcmtkBridge::SaveToMemoryBuffer(std::string& buffer, - DcmDataset& dataSet) - { - // Determine the transfer syntax which shall be used to write the - // information to the file. We always switch to the Little Endian - // syntax, with explicit length. - - // http://support.dcmtk.org/docs/dcxfer_8h-source.html - - - /** - * Note that up to Orthanc 0.7.1 (inclusive), the - * "EXS_LittleEndianExplicit" was always used to save the DICOM - * dataset into memory. We now keep the original transfer syntax - * (if available). - **/ - E_TransferSyntax xfer = dataSet.getOriginalXfer(); - if (xfer == EXS_Unknown) - { - // No information about the original transfer syntax: This is - // most probably a DICOM dataset that was read from memory. - xfer = EXS_LittleEndianExplicit; - } - - E_EncodingType encodingType = /*opt_sequenceType*/ EET_ExplicitLength; - - // Create the meta-header information - DcmFileFormat ff(&dataSet); - ff.validateMetaInfo(xfer); - ff.removeInvalidGroups(); - - // Create a memory buffer with the proper size - { - const uint32_t estimatedSize = ff.calcElementLength(xfer, encodingType); // (*) - buffer.resize(estimatedSize); - } - - DcmOutputBufferStream ob(&buffer[0], buffer.size()); - - // Fill the memory buffer with the meta-header and the dataset - ff.transferInit(); - OFCondition c = ff.write(ob, xfer, encodingType, NULL, - /*opt_groupLength*/ EGL_recalcGL, - /*opt_paddingType*/ EPD_withoutPadding); - ff.transferEnd(); - - if (c.good()) - { - // The DICOM file is successfully written, truncate the target - // buffer if its size was overestimated by (*) - ob.flush(); - - size_t effectiveSize = static_cast<size_t>(ob.tell()); - if (effectiveSize < buffer.size()) - { - buffer.resize(effectiveSize); - } - - return true; - } - else - { - // Error - buffer.clear(); - return false; - } - } - - - ValueRepresentation FromDcmtkBridge::LookupValueRepresentation(const DicomTag& tag) - { - DcmTag t(tag.GetGroup(), tag.GetElement()); - return Convert(t.getEVR()); - } - - ValueRepresentation FromDcmtkBridge::Convert(const DcmEVR vr) - { - switch (vr) - { - case EVR_AE: - return ValueRepresentation_ApplicationEntity; - - case EVR_AS: - return ValueRepresentation_AgeString; - - case EVR_AT: - return ValueRepresentation_AttributeTag; - - case EVR_CS: - return ValueRepresentation_CodeString; - - case EVR_DA: - return ValueRepresentation_Date; - - case EVR_DS: - return ValueRepresentation_DecimalString; - - case EVR_DT: - return ValueRepresentation_DateTime; - - case EVR_FL: - return ValueRepresentation_FloatingPointSingle; - - case EVR_FD: - return ValueRepresentation_FloatingPointDouble; - - case EVR_IS: - return ValueRepresentation_IntegerString; - - case EVR_LO: - return ValueRepresentation_LongString; - - case EVR_LT: - return ValueRepresentation_LongText; - - case EVR_OB: - return ValueRepresentation_OtherByte; - - // Not supported as of DCMTK 3.6.0 - /*case EVR_OD: - return ValueRepresentation_OtherDouble;*/ - - case EVR_OF: - return ValueRepresentation_OtherFloat; - - // Not supported as of DCMTK 3.6.0 - /*case EVR_OL: - return ValueRepresentation_OtherLong;*/ - - case EVR_OW: - return ValueRepresentation_OtherWord; - - case EVR_PN: - return ValueRepresentation_PersonName; - - case EVR_SH: - return ValueRepresentation_ShortString; - - case EVR_SL: - return ValueRepresentation_SignedLong; - - case EVR_SQ: - return ValueRepresentation_Sequence; - - case EVR_SS: - return ValueRepresentation_SignedShort; - - case EVR_ST: - return ValueRepresentation_ShortText; - - case EVR_TM: - return ValueRepresentation_Time; - - // Not supported as of DCMTK 3.6.0 - /*case EVR_UC: - return ValueRepresentation_UnlimitedCharacters;*/ - - case EVR_UI: - return ValueRepresentation_UniqueIdentifier; - - case EVR_UL: - return ValueRepresentation_UnsignedLong; - - case EVR_UN: - return ValueRepresentation_Unknown; - - // Not supported as of DCMTK 3.6.0 - /*case EVR_UR: - return ValueRepresentation_UniversalResource;*/ - - case EVR_US: - return ValueRepresentation_UnsignedShort; - - case EVR_UT: - return ValueRepresentation_UnlimitedText; - - default: - return ValueRepresentation_NotSupported; - } - } - - - static bool IsBinaryTag(const DcmTag& key) - { - return (key.isUnknownVR() || - key.getEVR() == EVR_OB || - key.getEVR() == EVR_OF || - key.getEVR() == EVR_OW || - key.getEVR() == EVR_UN || - key.getEVR() == EVR_ox); - } - - - DcmElement* FromDcmtkBridge::CreateElementForTag(const DicomTag& tag) - { - DcmTag key(tag.GetGroup(), tag.GetElement()); - - if (tag.IsPrivate() || - IsBinaryTag(key)) - { - return new DcmOtherByteOtherWord(key); - } - - switch (key.getEVR()) - { - // http://support.dcmtk.org/docs/dcvr_8h-source.html - - /** - * Binary types, handled above - **/ - - case EVR_OB: // other byte - case EVR_OF: // other float - case EVR_OW: // other word - case EVR_UN: // unknown value representation - case EVR_ox: // OB or OW depending on context - throw OrthancException(ErrorCode_InternalError); - - - /** - * String types. - * http://support.dcmtk.org/docs/classDcmByteString.html - **/ - - case EVR_AS: // age string - return new DcmAgeString(key); - - case EVR_AE: // application entity title - return new DcmApplicationEntity(key); - - case EVR_CS: // code string - return new DcmCodeString(key); - - case EVR_DA: // date string - return new DcmDate(key); - - case EVR_DT: // date time string - return new DcmDateTime(key); - - case EVR_DS: // decimal string - return new DcmDecimalString(key); - - case EVR_IS: // integer string - return new DcmIntegerString(key); - - case EVR_TM: // time string - return new DcmTime(key); - - case EVR_UI: // unique identifier - return new DcmUniqueIdentifier(key); - - case EVR_ST: // short text - return new DcmShortText(key); - - case EVR_LO: // long string - return new DcmLongString(key); - - case EVR_LT: // long text - return new DcmLongText(key); - - case EVR_UT: // unlimited text - return new DcmUnlimitedText(key); - - case EVR_SH: // short string - return new DcmShortString(key); - - case EVR_PN: // person name - return new DcmPersonName(key); - - - /** - * Numerical types - **/ - - case EVR_SL: // signed long - return new DcmSignedLong(key); - - case EVR_SS: // signed short - return new DcmSignedShort(key); - - case EVR_UL: // unsigned long - return new DcmUnsignedLong(key); - - case EVR_US: // unsigned short - return new DcmUnsignedShort(key); - - case EVR_FL: // float single-precision - return new DcmFloatingPointSingle(key); - - case EVR_FD: // float double-precision - return new DcmFloatingPointDouble(key); - - - /** - * Sequence types, should never occur at this point. - **/ - - case EVR_SQ: // sequence of items - throw OrthancException(ErrorCode_ParameterOutOfRange); - - - /** - * TODO - **/ - - case EVR_AT: // attribute tag - throw OrthancException(ErrorCode_NotImplemented); - - - /** - * Internal to DCMTK. - **/ - - case EVR_xs: // SS or US depending on context - case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) - case EVR_na: // na="not applicable", for data which has no VR - case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor - case EVR_item: // used internally for items - case EVR_metainfo: // used internally for meta info datasets - case EVR_dataset: // used internally for datasets - case EVR_fileFormat: // used internally for DICOM files - case EVR_dicomDir: // used internally for DICOMDIR objects - case EVR_dirRecord: // used internally for DICOMDIR records - case EVR_pixelSQ: // used internally for pixel sequences in a compressed image - case EVR_pixelItem: // used internally for pixel items in a compressed image - case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) - case EVR_PixelData: // used internally for uncompressed pixeld data - case EVR_OverlayData: // used internally for overlay data - case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR - default: - break; - } - - throw OrthancException(ErrorCode_InternalError); - } - - - - void FromDcmtkBridge::FillElementWithString(DcmElement& element, - const DicomTag& tag, - const std::string& utf8Value, - bool decodeDataUriScheme, - Encoding dicomEncoding) - { - std::string binary; - const std::string* decoded = &utf8Value; - - if (decodeDataUriScheme && - boost::starts_with(utf8Value, "data:application/octet-stream;base64,")) - { - std::string mime; - if (!Toolbox::DecodeDataUriScheme(mime, binary, utf8Value)) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - decoded = &binary; - } - else if (dicomEncoding != Encoding_Utf8) - { - binary = Toolbox::ConvertFromUtf8(utf8Value, dicomEncoding); - decoded = &binary; - } - - DcmTag key(tag.GetGroup(), tag.GetElement()); - - if (tag.IsPrivate() || - IsBinaryTag(key)) - { - if (element.putUint8Array((const Uint8*) decoded->c_str(), decoded->size()).good()) - { - return; - } - else - { - throw OrthancException(ErrorCode_InternalError); - } - } - - bool ok = false; - - try - { - switch (key.getEVR()) - { - // http://support.dcmtk.org/docs/dcvr_8h-source.html - - /** - * TODO. - **/ - - case EVR_OB: // other byte - case EVR_OF: // other float - case EVR_OW: // other word - case EVR_AT: // attribute tag - throw OrthancException(ErrorCode_NotImplemented); - - case EVR_UN: // unknown value representation - throw OrthancException(ErrorCode_ParameterOutOfRange); - - - /** - * String types. - **/ - - case EVR_DS: // decimal string - case EVR_IS: // integer string - case EVR_AS: // age string - case EVR_DA: // date string - case EVR_DT: // date time string - case EVR_TM: // time string - case EVR_AE: // application entity title - case EVR_CS: // code string - case EVR_SH: // short string - case EVR_LO: // long string - case EVR_ST: // short text - case EVR_LT: // long text - case EVR_UT: // unlimited text - case EVR_PN: // person name - case EVR_UI: // unique identifier - { - ok = element.putString(decoded->c_str()).good(); - break; - } - - - /** - * Numerical types - **/ - - case EVR_SL: // signed long - { - ok = element.putSint32(boost::lexical_cast<Sint32>(*decoded)).good(); - break; - } - - case EVR_SS: // signed short - { - ok = element.putSint16(boost::lexical_cast<Sint16>(*decoded)).good(); - break; - } - - case EVR_UL: // unsigned long - { - ok = element.putUint32(boost::lexical_cast<Uint32>(*decoded)).good(); - break; - } - - case EVR_US: // unsigned short - { - ok = element.putUint16(boost::lexical_cast<Uint16>(*decoded)).good(); - break; - } - - case EVR_FL: // float single-precision - { - ok = element.putFloat32(boost::lexical_cast<float>(*decoded)).good(); - break; - } - - case EVR_FD: // float double-precision - { - ok = element.putFloat64(boost::lexical_cast<double>(*decoded)).good(); - break; - } - - - /** - * Sequence types, should never occur at this point. - **/ - - case EVR_SQ: // sequence of items - { - ok = false; - break; - } - - - /** - * Internal to DCMTK. - **/ - - case EVR_ox: // OB or OW depending on context - case EVR_xs: // SS or US depending on context - case EVR_lt: // US, SS or OW depending on context, used for LUT Data (thus the name) - case EVR_na: // na="not applicable", for data which has no VR - case EVR_up: // up="unsigned pointer", used internally for DICOMDIR suppor - case EVR_item: // used internally for items - case EVR_metainfo: // used internally for meta info datasets - case EVR_dataset: // used internally for datasets - case EVR_fileFormat: // used internally for DICOM files - case EVR_dicomDir: // used internally for DICOMDIR objects - case EVR_dirRecord: // used internally for DICOMDIR records - case EVR_pixelSQ: // used internally for pixel sequences in a compressed image - case EVR_pixelItem: // used internally for pixel items in a compressed image - case EVR_UNKNOWN: // used internally for elements with unknown VR (encoded with 4-byte length field in explicit VR) - case EVR_PixelData: // used internally for uncompressed pixeld data - case EVR_OverlayData: // used internally for overlay data - case EVR_UNKNOWN2B: // used internally for elements with unknown VR with 2-byte length field in explicit VR - default: - break; - } - } - catch (boost::bad_lexical_cast&) - { - ok = false; - } - - if (!ok) - { - LOG(ERROR) << "While creating a DICOM instance, tag (" << tag.Format() - << ") has out-of-range value: \"" << *decoded << "\""; - throw OrthancException(ErrorCode_BadFileFormat); - } - } - - - DcmElement* FromDcmtkBridge::FromJson(const DicomTag& tag, - const Json::Value& value, - bool decodeDataUriScheme, - Encoding dicomEncoding) - { - std::auto_ptr<DcmElement> element; - - switch (value.type()) - { - case Json::stringValue: - element.reset(CreateElementForTag(tag)); - 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()); - if (key.getEVR() != EVR_SQ) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - DcmSequenceOfItems* sequence = new DcmSequenceOfItems(key); - element.reset(sequence); - - for (Json::Value::ArrayIndex i = 0; i < value.size(); i++) - { - std::auto_ptr<DcmItem> item(new DcmItem); - - Json::Value::Members members = value[i].getMemberNames(); - for (Json::Value::ArrayIndex j = 0; j < members.size(); j++) - { - item->insert(FromJson(ParseTag(members[j]), value[i][members[j]], decodeDataUriScheme, dicomEncoding)); - } - - sequence->append(item.release()); - } - - break; - } - - default: - throw OrthancException(ErrorCode_BadParameterType); - } - - return element.release(); - } - - - DcmPixelSequence* FromDcmtkBridge::GetPixelSequence(DcmDataset& dataset) - { - DcmElement *element = NULL; - if (!dataset.findAndGetElement(DCM_PixelData, element).good()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - DcmPixelData& pixelData = dynamic_cast<DcmPixelData&>(*element); - DcmPixelSequence* pixelSequence = NULL; - if (!pixelData.getEncapsulatedRepresentation - (dataset.getOriginalXfer(), NULL, pixelSequence).good()) - { - return NULL; - } - else - { - return pixelSequence; - } - } - - - Encoding FromDcmtkBridge::ExtractEncoding(const Json::Value& json, - Encoding defaultEncoding) - { - if (json.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadParameterType); - } - - Encoding encoding = defaultEncoding; - - const Json::Value::Members tags = json.getMemberNames(); - - // Look for SpecificCharacterSet (0008,0005) in the JSON file - for (size_t i = 0; i < tags.size(); i++) - { - DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]); - if (tag == DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - const Json::Value& value = json[tags[i]]; - if (value.type() != Json::stringValue || - (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; - } - } - } - - return encoding; - } - - - static void SetString(DcmDataset& target, - const DcmTag& tag, - const std::string& value) - { - if (!target.putAndInsertString(tag, value.c_str()).good()) - { - throw OrthancException(ErrorCode_InternalError); - } - } - - - DcmDataset* FromDcmtkBridge::FromJson(const Json::Value& json, // Encoded using UTF-8 - bool generateIdentifiers, - bool decodeDataUriScheme, - Encoding defaultEncoding) - { - std::auto_ptr<DcmDataset> result(new DcmDataset); - Encoding encoding = ExtractEncoding(json, defaultEncoding); - - SetString(*result, DCM_SpecificCharacterSet, GetDicomSpecificCharacterSet(encoding)); - - const Json::Value::Members tags = json.getMemberNames(); - - bool hasPatientId = false; - bool hasStudyInstanceUid = false; - bool hasSeriesInstanceUid = false; - bool hasSopInstanceUid = false; - - for (size_t i = 0; i < tags.size(); i++) - { - DicomTag tag = FromDcmtkBridge::ParseTag(tags[i]); - const Json::Value& value = json[tags[i]]; - - if (tag == DICOM_TAG_PATIENT_ID) - { - hasPatientId = true; - } - else if (tag == DICOM_TAG_STUDY_INSTANCE_UID) - { - hasStudyInstanceUid = true; - } - else if (tag == DICOM_TAG_SERIES_INSTANCE_UID) - { - hasSeriesInstanceUid = true; - } - else if (tag == DICOM_TAG_SOP_INSTANCE_UID) - { - hasSopInstanceUid = true; - } - - if (tag != DICOM_TAG_SPECIFIC_CHARACTER_SET) - { - std::auto_ptr<DcmElement> element(FromDcmtkBridge::FromJson(tag, value, decodeDataUriScheme, encoding)); - const DcmTagKey& tag = element->getTag(); - - result->findAndDeleteElement(tag); - - DcmElement* tmp = element.release(); - if (!result->insert(tmp, false, false).good()) - { - delete tmp; - throw OrthancException(ErrorCode_InternalError); - } - } - } - - if (!hasPatientId && - generateIdentifiers) - { - SetString(*result, DCM_PatientID, GenerateUniqueIdentifier(ResourceType_Patient)); - } - - if (!hasStudyInstanceUid && - generateIdentifiers) - { - SetString(*result, DCM_StudyInstanceUID, GenerateUniqueIdentifier(ResourceType_Study)); - } - - if (!hasSeriesInstanceUid && - generateIdentifiers) - { - SetString(*result, DCM_SeriesInstanceUID, GenerateUniqueIdentifier(ResourceType_Series)); - } - - if (!hasSopInstanceUid && - generateIdentifiers) - { - SetString(*result, DCM_SOPInstanceUID, GenerateUniqueIdentifier(ResourceType_Instance)); - } - - return result.release(); - } - - - DcmFileFormat* FromDcmtkBridge::LoadFromMemoryBuffer(const void* buffer, - size_t size) - { - DcmInputBufferStream is; - if (size > 0) - { - is.setBuffer(buffer, size); - } - is.setEos(); - - std::auto_ptr<DcmFileFormat> result(new DcmFileFormat); - - result->transferInit(); - if (!result->read(is).good()) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - result->loadAllDataIntoMemory(); - result->transferEnd(); - - return result.release(); - } - - - void FromDcmtkBridge::FromJson(DicomMap& target, - const Json::Value& source) - { - if (source.type() != Json::objectValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - target.Clear(); - - Json::Value::Members members = source.getMemberNames(); - - for (size_t i = 0; i < members.size(); i++) - { - const Json::Value& value = source[members[i]]; - - if (value.type() != Json::stringValue) - { - throw OrthancException(ErrorCode_BadFileFormat); - } - - 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; - } - } - - -#if ORTHANC_ENABLE_LUA == 1 - 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); - } - } -#endif -}
--- a/Resources/Orthanc/OrthancServer/FromDcmtkBridge.h Tue Jan 02 10:01:35 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,224 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, 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 "ServerEnumerations.h" - -#include "../Core/DicomFormat/DicomElement.h" -#include "../Core/DicomFormat/DicomMap.h" - -#include <dcmtk/dcmdata/dcdatset.h> -#include <dcmtk/dcmdata/dcmetinf.h> -#include <dcmtk/dcmdata/dcpixseq.h> -#include <dcmtk/dcmdata/dcfilefo.h> -#include <json/json.h> - -#if !defined(ORTHANC_BUILD_UNIT_TESTS) -# error The macro ORTHANC_BUILD_UNIT_TESTS must be defined -#endif - -#if !defined(ORTHANC_ENABLE_LUA) -# error The macro ORTHANC_ENABLE_LUA must be defined -#endif - -#if ORTHANC_BUILD_UNIT_TESTS == 1 -# include <gtest/gtest_prod.h> -#endif - -#if ORTHANC_ENABLE_LUA == 1 -# include "../Core/Lua/LuaFunctionCall.h" -#endif - - -namespace Orthanc -{ - 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(bool loadPrivateDictionary); - - static void RegisterDictionaryTag(const DicomTag& tag, - ValueRepresentation vr, - const std::string& name, - unsigned int minMultiplicity, - unsigned int maxMultiplicity, - const std::string& privateCreator); - - static Encoding DetectEncoding(DcmItem& dataset, - Encoding defaultEncoding); - - static DicomTag Convert(const DcmTag& tag); - - static DicomTag GetTag(const DcmElement& element); - - static bool IsUnknownTag(const DicomTag& tag); - - static DicomValue* ConvertLeafElement(DcmElement& element, - DicomToJsonFlags flags, - unsigned int maxStringLength, - Encoding encoding); - - static void ExtractHeaderAsJson(Json::Value& target, - DcmMetaInfo& header, - DicomToJsonFormat format, - DicomToJsonFlags flags, - unsigned int maxStringLength); - - static std::string GetTagName(const DicomTag& tag, - const std::string& privateCreator); - - static std::string GetTagName(const DcmElement& element); - - static std::string GetTagName(const DicomElement& element) - { - return GetTagName(element.GetTag(), ""); - } - - static DicomTag ParseTag(const char* name); - - static DicomTag ParseTag(const std::string& name) - { - return ParseTag(name.c_str()); - } - - static bool HasTag(const DicomMap& fields, - const std::string& tagName) - { - return fields.HasTag(ParseTag(tagName)); - } - - static const DicomValue& GetValue(const DicomMap& fields, - const std::string& tagName) - { - return fields.GetValue(ParseTag(tagName)); - } - - static void SetValue(DicomMap& target, - const std::string& tagName, - DicomValue* value) - { - target.SetValue(ParseTag(tagName), value); - } - - static void ToJson(Json::Value& result, - const DicomMap& values, - bool simplify); - - static std::string GenerateUniqueIdentifier(ResourceType level); - - static bool SaveToMemoryBuffer(std::string& buffer, - DcmDataset& dataSet); - - static ValueRepresentation Convert(DcmEVR vr); - - static ValueRepresentation LookupValueRepresentation(const DicomTag& tag); - - static DcmElement* CreateElementForTag(const DicomTag& tag); - - static void FillElementWithString(DcmElement& element, - const DicomTag& tag, - const std::string& utf8alue, // Encoded using UTF-8 - bool decodeDataUriScheme, - Encoding dicomEncoding); - - static DcmElement* FromJson(const DicomTag& tag, - const Json::Value& element, // Encoded using UTF-8 - bool decodeDataUriScheme, - Encoding dicomEncoding); - - static DcmPixelSequence* GetPixelSequence(DcmDataset& dataset); - - static Encoding ExtractEncoding(const Json::Value& json, - Encoding defaultEncoding); - - static DcmDataset* FromJson(const Json::Value& json, // Encoded using UTF-8 - bool generateIdentifiers, - bool decodeDataUriScheme, - Encoding defaultEncoding); - - static DcmFileFormat* LoadFromMemoryBuffer(const void* buffer, - size_t size); - - static void FromJson(DicomMap& values, - const Json::Value& result); - - static bool LookupTransferSyntax(std::string& result, - DcmFileFormat& dicom); - -#if ORTHANC_ENABLE_LUA == 1 - static void ExecuteToDicom(DicomMap& target, - LuaFunctionCall& call); -#endif - }; -}
--- a/Resources/Orthanc/OrthancServer/PrecompiledHeadersServer.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/OrthancServer/PrecompiledHeadersServer.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -37,42 +37,6 @@ #if ORTHANC_USE_PRECOMPILED_HEADERS == 1 -// DCMTK -#include <dcmtk/dcmdata/dcchrstr.h> -#include <dcmtk/dcmdata/dcdeftag.h> -#include <dcmtk/dcmdata/dcdicent.h> -#include <dcmtk/dcmdata/dcdict.h> -#include <dcmtk/dcmdata/dcfilefo.h> -#include <dcmtk/dcmdata/dcistrmb.h> -#include <dcmtk/dcmdata/dcistrmf.h> -#include <dcmtk/dcmdata/dcmetinf.h> -#include <dcmtk/dcmdata/dcostrmb.h> -#include <dcmtk/dcmdata/dcpixel.h> -#include <dcmtk/dcmdata/dcpixseq.h> -#include <dcmtk/dcmdata/dcpxitem.h> -#include <dcmtk/dcmdata/dcuid.h> -#include <dcmtk/dcmdata/dcvrae.h> -#include <dcmtk/dcmdata/dcvras.h> -#include <dcmtk/dcmdata/dcvrcs.h> -#include <dcmtk/dcmdata/dcvrda.h> -#include <dcmtk/dcmdata/dcvrds.h> -#include <dcmtk/dcmdata/dcvrdt.h> -#include <dcmtk/dcmdata/dcvrfd.h> -#include <dcmtk/dcmdata/dcvrfl.h> -#include <dcmtk/dcmdata/dcvris.h> -#include <dcmtk/dcmdata/dcvrlo.h> -#include <dcmtk/dcmdata/dcvrlt.h> -#include <dcmtk/dcmdata/dcvrpn.h> -#include <dcmtk/dcmdata/dcvrsh.h> -#include <dcmtk/dcmdata/dcvrsl.h> -#include <dcmtk/dcmdata/dcvrss.h> -#include <dcmtk/dcmdata/dcvrst.h> -#include <dcmtk/dcmdata/dcvrtm.h> -#include <dcmtk/dcmdata/dcvrui.h> -#include <dcmtk/dcmdata/dcvrul.h> -#include <dcmtk/dcmdata/dcvrus.h> -#include <dcmtk/dcmdata/dcvrut.h> -#include <dcmtk/dcmnet/dcasccfg.h> -#include <dcmtk/dcmnet/diutil.h> +#include "ServerContext.h" #endif
--- a/Resources/Orthanc/OrthancServer/ServerEnumerations.cpp Tue Jan 02 10:01:35 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,517 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, 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 "PrecompiledHeadersServer.h" -#include "ServerEnumerations.h" - -#include "../Core/OrthancException.h" -#include "../Core/EnumerationDictionary.h" -#include "../Core/Logging.h" -#include "../Core/Toolbox.h" - -#include <boost/thread.hpp> - -namespace Orthanc -{ - typedef std::map<FileContentType, std::string> MimeTypes; - - static boost::mutex enumerationsMutex_; - static Toolbox::EnumerationDictionary<MetadataType> dictMetadataType_; - static Toolbox::EnumerationDictionary<FileContentType> dictContentType_; - static MimeTypes mimeTypes_; - - void InitializeServerEnumerations() - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - - dictMetadataType_.Clear(); - dictContentType_.Clear(); - - dictMetadataType_.Add(MetadataType_Instance_IndexInSeries, "IndexInSeries"); - dictMetadataType_.Add(MetadataType_Instance_ReceptionDate, "ReceptionDate"); - dictMetadataType_.Add(MetadataType_Instance_RemoteAet, "RemoteAET"); - dictMetadataType_.Add(MetadataType_Series_ExpectedNumberOfInstances, "ExpectedNumberOfInstances"); - dictMetadataType_.Add(MetadataType_ModifiedFrom, "ModifiedFrom"); - 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"); - } - - void RegisterUserMetadata(int metadata, - const std::string& name) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - - MetadataType type = static_cast<MetadataType>(metadata); - - if (metadata < 0 || - !IsUserMetadata(type)) - { - LOG(ERROR) << "A user content type must have index between " - << static_cast<int>(MetadataType_StartUser) << " and " - << static_cast<int>(MetadataType_EndUser) << ", but \"" - << name << "\" has index " << metadata; - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (dictMetadataType_.Contains(type)) - { - LOG(ERROR) << "Cannot associate user content type \"" - << name << "\" with index " << metadata - << ", as this index is already used"; - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - dictMetadataType_.Add(type, name); - } - - std::string EnumerationToString(MetadataType type) - { - // This function MUST return a "std::string" and not "const - // char*", as the result is not a static string - boost::mutex::scoped_lock lock(enumerationsMutex_); - return dictMetadataType_.Translate(type); - } - - MetadataType StringToMetadata(const std::string& str) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - return dictMetadataType_.Translate(str); - } - - void RegisterUserContentType(int contentType, - const std::string& name, - const std::string& mime) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - - FileContentType type = static_cast<FileContentType>(contentType); - - if (contentType < 0 || - !IsUserContentType(type)) - { - LOG(ERROR) << "A user content type must have index between " - << static_cast<int>(FileContentType_StartUser) << " and " - << static_cast<int>(FileContentType_EndUser) << ", but \"" - << name << "\" has index " << contentType; - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (dictContentType_.Contains(type)) - { - LOG(ERROR) << "Cannot associate user content type \"" - << name << "\" with index " << contentType - << ", as this index is already used"; - - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - dictContentType_.Add(type, name); - mimeTypes_[type] = mime; - } - - std::string EnumerationToString(FileContentType type) - { - // This function MUST return a "std::string" and not "const - // char*", as the result is not a static string - boost::mutex::scoped_lock lock(enumerationsMutex_); - return dictContentType_.Translate(type); - } - - std::string GetFileContentMime(FileContentType type) - { - if (type >= FileContentType_StartUser && - type <= FileContentType_EndUser) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - - MimeTypes::const_iterator it = mimeTypes_.find(type); - if (it != mimeTypes_.end()) - { - return it->second; - } - } - - switch (type) - { - case FileContentType_Dicom: - return "application/dicom"; - - case FileContentType_DicomAsJson: - return "application/json"; - - default: - return "application/octet-stream"; - } - } - - FileContentType StringToContentType(const std::string& str) - { - boost::mutex::scoped_lock lock(enumerationsMutex_); - return dictContentType_.Translate(str); - } - - std::string GetBasePath(ResourceType type, - const std::string& publicId) - { - switch (type) - { - case ResourceType_Patient: - return "/patients/" + publicId; - - case ResourceType_Study: - return "/studies/" + publicId; - - case ResourceType_Series: - return "/series/" + publicId; - - case ResourceType_Instance: - return "/instances/" + publicId; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - const char* EnumerationToString(SeriesStatus status) - { - switch (status) - { - case SeriesStatus_Complete: - return "Complete"; - - case SeriesStatus_Missing: - return "Missing"; - - case SeriesStatus_Inconsistent: - return "Inconsistent"; - - case SeriesStatus_Unknown: - return "Unknown"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - const char* EnumerationToString(StoreStatus status) - { - switch (status) - { - case StoreStatus_Success: - return "Success"; - - case StoreStatus_AlreadyStored: - return "AlreadyStored"; - - case StoreStatus_Failure: - return "Failure"; - - case StoreStatus_FilteredOut: - return "FilteredOut"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(ChangeType type) - { - switch (type) - { - case ChangeType_CompletedSeries: - return "CompletedSeries"; - - case ChangeType_NewInstance: - return "NewInstance"; - - case ChangeType_NewPatient: - return "NewPatient"; - - case ChangeType_NewSeries: - return "NewSeries"; - - case ChangeType_NewStudy: - return "NewStudy"; - - case ChangeType_AnonymizedStudy: - return "AnonymizedStudy"; - - case ChangeType_AnonymizedSeries: - return "AnonymizedSeries"; - - case ChangeType_ModifiedStudy: - return "ModifiedStudy"; - - case ChangeType_ModifiedSeries: - return "ModifiedSeries"; - - case ChangeType_AnonymizedPatient: - return "AnonymizedPatient"; - - case ChangeType_ModifiedPatient: - return "ModifiedPatient"; - - case ChangeType_StablePatient: - return "StablePatient"; - - case ChangeType_StableStudy: - return "StableStudy"; - - case ChangeType_StableSeries: - return "StableSeries"; - - case ChangeType_Deleted: - return "Deleted"; - - case ChangeType_NewChildInstance: - return "NewChildInstance"; - - case ChangeType_UpdatedAttachment: - return "UpdatedAttachment"; - - case ChangeType_UpdatedMetadata: - return "UpdatedMetadata"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(ModalityManufacturer manufacturer) - { - switch (manufacturer) - { - case ModalityManufacturer_Generic: - return "Generic"; - - case ModalityManufacturer_GenericNoWildcardInDates: - return "GenericNoWildcardInDates"; - - case ModalityManufacturer_GenericNoUniversalWildcard: - return "GenericNoUniversalWildcard"; - - case ModalityManufacturer_StoreScp: - return "StoreScp"; - - case ModalityManufacturer_ClearCanvas: - return "ClearCanvas"; - - case ModalityManufacturer_Dcm4Chee: - return "Dcm4Chee"; - - case ModalityManufacturer_Vitrea: - return "Vitrea"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(DicomRequestType type) - { - switch (type) - { - case DicomRequestType_Echo: - return "Echo"; - break; - - case DicomRequestType_Find: - return "Find"; - break; - - case DicomRequestType_Get: - return "Get"; - break; - - case DicomRequestType_Move: - return "Move"; - break; - - case DicomRequestType_Store: - return "Store"; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - - ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer) - { - ModalityManufacturer result; - bool obsolete = false; - - if (manufacturer == "Generic") - { - return ModalityManufacturer_Generic; - } - else if (manufacturer == "GenericNoWildcardInDates") - { - return ModalityManufacturer_GenericNoWildcardInDates; - } - else if (manufacturer == "GenericNoUniversalWildcard") - { - return ModalityManufacturer_GenericNoUniversalWildcard; - } - else if (manufacturer == "ClearCanvas") - { - return ModalityManufacturer_ClearCanvas; - } - else if (manufacturer == "StoreScp") - { - return ModalityManufacturer_StoreScp; - } - else if (manufacturer == "Dcm4Chee") - { - return ModalityManufacturer_Dcm4Chee; - } - else if (manufacturer == "Vitrea") - { - return ModalityManufacturer_Vitrea; - } - else if (manufacturer == "AgfaImpax" || - manufacturer == "SyngoVia") - { - result = ModalityManufacturer_GenericNoWildcardInDates; - obsolete = true; - } - else if (manufacturer == "EFilm2" || - manufacturer == "MedInria") - { - result = ModalityManufacturer_Generic; - obsolete = true; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - - if (obsolete) - { - LOG(WARNING) << "The \"" << manufacturer << "\" manufacturer is obsolete since " - << "Orthanc 1.3.0. To guarantee compatibility with future Orthanc " - << "releases, you should replace it by \"" - << EnumerationToString(result) - << "\" in your configuration file."; - } - - return result; - } - - - const char* EnumerationToString(TransferSyntax syntax) - { - switch (syntax) - { - case TransferSyntax_Deflated: - return "Deflated"; - - case TransferSyntax_Jpeg: - return "JPEG"; - - case TransferSyntax_Jpeg2000: - return "JPEG2000"; - - case TransferSyntax_JpegLossless: - return "JPEG Lossless"; - - case TransferSyntax_Jpip: - return "JPIP"; - - case TransferSyntax_Mpeg2: - return "MPEG2"; - - case TransferSyntax_Rle: - return "RLE"; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - const char* EnumerationToString(DicomVersion version) - { - switch (version) - { - case DicomVersion_2008: - return "2008"; - break; - - case DicomVersion_2017c: - return "2017c"; - break; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - DicomVersion StringToDicomVersion(const std::string& version) - { - if (version == "2008") - { - return DicomVersion_2008; - } - else if (version == "2017c") - { - return DicomVersion_2017c; - } - else - { - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } - - - bool IsUserMetadata(MetadataType metadata) - { - return (metadata >= MetadataType_StartUser && - metadata <= MetadataType_EndUser); - } -}
--- a/Resources/Orthanc/OrthancServer/ServerEnumerations.h Tue Jan 02 10:01:35 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,244 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, 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 <string> -#include <map> - -#include "../Core/Enumerations.h" -#include "../Core/DicomFormat/DicomTag.h" - -namespace Orthanc -{ - enum SeriesStatus - { - SeriesStatus_Complete, - SeriesStatus_Missing, - SeriesStatus_Inconsistent, - SeriesStatus_Unknown - }; - - enum StoreStatus - { - StoreStatus_Success, - StoreStatus_AlreadyStored, - StoreStatus_Failure, - StoreStatus_FilteredOut // Removed by NewInstanceFilter - }; - - enum ModalityManufacturer - { - ModalityManufacturer_Generic, - ModalityManufacturer_GenericNoWildcardInDates, - ModalityManufacturer_GenericNoUniversalWildcard, - ModalityManufacturer_StoreScp, - ModalityManufacturer_ClearCanvas, - ModalityManufacturer_Dcm4Chee, - ModalityManufacturer_Vitrea - }; - - enum DicomRequestType - { - DicomRequestType_Echo, - DicomRequestType_Find, - DicomRequestType_Get, - DicomRequestType_Move, - DicomRequestType_Store - }; - - enum DicomReplaceMode - { - DicomReplaceMode_InsertIfAbsent, - DicomReplaceMode_ThrowIfAbsent, - DicomReplaceMode_IgnoreIfAbsent - }; - - enum TransferSyntax - { - TransferSyntax_Deflated, - TransferSyntax_Jpeg, - TransferSyntax_Jpeg2000, - TransferSyntax_JpegLossless, - TransferSyntax_Jpip, - TransferSyntax_Mpeg2, - TransferSyntax_Rle - }; - - enum DicomToJsonFormat - { - DicomToJsonFormat_Full, - DicomToJsonFormat_Short, - DicomToJsonFormat_Human - }; - - enum DicomToJsonFlags - { - DicomToJsonFlags_IncludeBinary = (1 << 0), - DicomToJsonFlags_IncludePrivateTags = (1 << 1), - DicomToJsonFlags_IncludeUnknownTags = (1 << 2), - DicomToJsonFlags_IncludePixelData = (1 << 3), - DicomToJsonFlags_ConvertBinaryToAscii = (1 << 4), - DicomToJsonFlags_ConvertBinaryToNull = (1 << 5), - - // Some predefined combinations - DicomToJsonFlags_None = 0, - DicomToJsonFlags_Default = (DicomToJsonFlags_IncludeBinary | - DicomToJsonFlags_IncludePixelData | - DicomToJsonFlags_IncludePrivateTags | - DicomToJsonFlags_IncludeUnknownTags | - DicomToJsonFlags_ConvertBinaryToNull) - }; - - enum DicomFromJsonFlags - { - DicomFromJsonFlags_DecodeDataUriScheme = (1 << 0), - DicomFromJsonFlags_GenerateIdentifiers = (1 << 1) - }; - - enum IdentifierConstraintType - { - IdentifierConstraintType_Equal, - IdentifierConstraintType_SmallerOrEqual, - IdentifierConstraintType_GreaterOrEqual, - IdentifierConstraintType_Wildcard /* Case sensitive, "*" or "?" are the only allowed wildcards */ - }; - - enum DicomVersion - { - DicomVersion_2008, - DicomVersion_2017c - }; - - - /** - * WARNING: Do not change the explicit values in the enumerations - * below this point. This would result in incompatible databases - * between versions of Orthanc! - **/ - - enum GlobalProperty - { - GlobalProperty_DatabaseSchemaVersion = 1, // Unused in the Orthanc core as of Orthanc 0.9.5 - GlobalProperty_FlushSleep = 2, - GlobalProperty_AnonymizationSequence = 3, - GlobalProperty_DatabasePatchLevel = 4 // Reserved for internal use of the database plugins - }; - - enum MetadataType - { - MetadataType_Instance_IndexInSeries = 1, - MetadataType_Instance_ReceptionDate = 2, - MetadataType_Instance_RemoteAet = 3, - MetadataType_Series_ExpectedNumberOfInstances = 4, - MetadataType_ModifiedFrom = 5, - MetadataType_AnonymizedFrom = 6, - MetadataType_LastUpdate = 7, - 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, - MetadataType_EndUser = 65535 - }; - - enum ChangeType - { - ChangeType_CompletedSeries = 1, - ChangeType_NewInstance = 2, - ChangeType_NewPatient = 3, - ChangeType_NewSeries = 4, - ChangeType_NewStudy = 5, - ChangeType_AnonymizedStudy = 6, - ChangeType_AnonymizedSeries = 7, - ChangeType_ModifiedStudy = 8, - ChangeType_ModifiedSeries = 9, - ChangeType_AnonymizedPatient = 10, - ChangeType_ModifiedPatient = 11, - ChangeType_StablePatient = 12, - ChangeType_StableStudy = 13, - ChangeType_StableSeries = 14, - ChangeType_UpdatedAttachment = 15, - ChangeType_UpdatedMetadata = 16, - - ChangeType_INTERNAL_LastLogged = 4095, - - // The changes below this point are not logged into the database - ChangeType_Deleted = 4096, - ChangeType_NewChildInstance = 4097 - }; - - - - void InitializeServerEnumerations(); - - void RegisterUserMetadata(int metadata, - const std::string& name); - - MetadataType StringToMetadata(const std::string& str); - - std::string EnumerationToString(MetadataType type); - - void RegisterUserContentType(int contentType, - const std::string& name, - const std::string& mime); - - FileContentType StringToContentType(const std::string& str); - - std::string EnumerationToString(FileContentType type); - - std::string GetFileContentMime(FileContentType type); - - std::string GetBasePath(ResourceType type, - const std::string& publicId); - - const char* EnumerationToString(SeriesStatus status); - - const char* EnumerationToString(StoreStatus status); - - const char* EnumerationToString(ChangeType type); - - const char* EnumerationToString(ModalityManufacturer manufacturer); - - const char* EnumerationToString(DicomRequestType type); - - const char* EnumerationToString(TransferSyntax syntax); - - const char* EnumerationToString(DicomVersion version); - - ModalityManufacturer StringToModalityManufacturer(const std::string& manufacturer); - - DicomVersion StringToDicomVersion(const std::string& version); - - bool IsUserMetadata(MetadataType type); -}
--- a/Resources/Orthanc/OrthancServer/ToDcmtkBridge.cpp Tue Jan 02 10:01:35 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,150 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, 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 "PrecompiledHeadersServer.h" -#include "ToDcmtkBridge.h" - -#include <memory> -#include <dcmtk/dcmnet/diutil.h> - -#include "../Core/OrthancException.h" - - -namespace Orthanc -{ - DcmEVR ToDcmtkBridge::Convert(ValueRepresentation vr) - { - switch (vr) - { - case ValueRepresentation_ApplicationEntity: - return EVR_AE; - - case ValueRepresentation_AgeString: - return EVR_AS; - - case ValueRepresentation_AttributeTag: - return EVR_AT; - - case ValueRepresentation_CodeString: - return EVR_CS; - - case ValueRepresentation_Date: - return EVR_DA; - - case ValueRepresentation_DecimalString: - return EVR_DS; - - case ValueRepresentation_DateTime: - return EVR_DT; - - case ValueRepresentation_FloatingPointSingle: - return EVR_FL; - - case ValueRepresentation_FloatingPointDouble: - return EVR_FD; - - case ValueRepresentation_IntegerString: - return EVR_IS; - - case ValueRepresentation_LongString: - return EVR_LO; - - case ValueRepresentation_LongText: - return EVR_LT; - - case ValueRepresentation_OtherByte: - return EVR_OB; - - // Not supported as of DCMTK 3.6.0 - /*case ValueRepresentation_OtherDouble: - return EVR_OD;*/ - - case ValueRepresentation_OtherFloat: - return EVR_OF; - - // Not supported as of DCMTK 3.6.0 - /*case ValueRepresentation_OtherLong: - return EVR_OL;*/ - - case ValueRepresentation_OtherWord: - return EVR_OW; - - case ValueRepresentation_PersonName: - return EVR_PN; - - case ValueRepresentation_ShortString: - return EVR_SH; - - case ValueRepresentation_SignedLong: - return EVR_SL; - - case ValueRepresentation_Sequence: - return EVR_SQ; - - case ValueRepresentation_SignedShort: - return EVR_SS; - - case ValueRepresentation_ShortText: - return EVR_ST; - - case ValueRepresentation_Time: - return EVR_TM; - - // Not supported as of DCMTK 3.6.0 - /*case ValueRepresentation_UnlimitedCharacters: - return EVR_UC;*/ - - case ValueRepresentation_UniqueIdentifier: - return EVR_UI; - - case ValueRepresentation_UnsignedLong: - return EVR_UL; - - case ValueRepresentation_Unknown: - return EVR_UN; - - // Not supported as of DCMTK 3.6.0 - /*case ValueRepresentation_UniversalResource: - return EVR_UR;*/ - - case ValueRepresentation_UnsignedShort: - return EVR_US; - - case ValueRepresentation_UnlimitedText: - return EVR_UT; - - default: - throw OrthancException(ErrorCode_ParameterOutOfRange); - } - } -}
--- a/Resources/Orthanc/OrthancServer/ToDcmtkBridge.h Tue Jan 02 10:01:35 2018 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,51 +0,0 @@ -/** - * Orthanc - A Lightweight, RESTful DICOM Store - * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics - * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, 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 "../Core/DicomFormat/DicomMap.h" -#include <dcmtk/dcmdata/dcdatset.h> - -namespace Orthanc -{ - class ToDcmtkBridge - { - public: - static DcmTagKey Convert(const DicomTag& tag) - { - return DcmTagKey(tag.GetGroup(), tag.GetElement()); - } - - static DcmEVR Convert(ValueRepresentation vr); - }; -}
--- a/Resources/Orthanc/Plugins/Engine/SharedLibrary.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Engine/SharedLibrary.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Engine/SharedLibrary.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Engine/SharedLibrary.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomDatasetReader.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomPath.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomTag.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/DicomTag.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -94,8 +94,10 @@ static const DicomTag DICOM_TAG_ROWS(0x0028, 0x0010); static const DicomTag DICOM_TAG_ROW_POSITION_IN_TOTAL_IMAGE_PIXEL_MATRIX(0x0048, 0x021f); static const DicomTag DICOM_TAG_SAMPLES_PER_PIXEL(0x0028, 0x0002); + static const DicomTag DICOM_TAG_SERIES_INSTANCE_UID(0x0020, 0x000e); static const DicomTag DICOM_TAG_SLICE_THICKNESS(0x0018, 0x0050); static const DicomTag DICOM_TAG_SOP_CLASS_UID(0x0008, 0x0016); + static const DicomTag DICOM_TAG_SOP_INSTANCE_UID(0x0008, 0x0018); 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);
--- a/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/FullOrthancDataset.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/IDicomDataset.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/IOrthancConnection.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancHttpConnection.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginConnection.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginCppWrapper.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as @@ -44,13 +44,15 @@ +#if !defined(ORTHANC_PLUGINS_VERSION_IS_ABOVE) #define ORTHANC_PLUGINS_VERSION_IS_ABOVE(major, minor, revision) \ (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER > major || \ (ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER == major && \ (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER > minor || \ (ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER == minor && \ ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER >= revision)))) - +#endif + #if ORTHANC_PLUGINS_VERSION_IS_ABOVE(1, 2, 0) // The "OrthancPluginFindMatcher()" primitive was introduced in Orthanc 1.2.0
--- a/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/OrthancPluginException.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.cpp Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.h Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Plugins/Samples/Common/SimplifiedOrthancDataset.h Thu Jan 04 10:49:34 2018 +0100 @@ -2,7 +2,7 @@ * Orthanc - A Lightweight, RESTful DICOM Store * Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics * Department, University Hospital of Liege, Belgium - * Copyright (C) 2017 Osimis, Belgium + * Copyright (C) 2017-2018 Osimis S.A., Belgium * * This program is free software: you can redistribute it and/or * modify it under the terms of the GNU General Public License as
--- a/Resources/Orthanc/Resources/CMake/BoostConfiguration.cmake Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Resources/CMake/BoostConfiguration.cmake Thu Jan 04 10:49:34 2018 +0100 @@ -41,12 +41,18 @@ ## Parameters for static compilation of Boost ## - set(BOOST_NAME boost_1_64_0) - set(BOOST_BCP_SUFFIX bcpdigest-1.3.0) - set(BOOST_MD5 "ecb266cf46adcc7f695ad12685871174") + set(BOOST_NAME boost_1_65_1) + set(BOOST_BCP_SUFFIX bcpdigest-1.3.1) + set(BOOST_MD5 "92c9c603e56bbd7a450a305f08747d90") set(BOOST_URL "http://www.orthanc-server.com/downloads/third-party/${BOOST_NAME}_${BOOST_BCP_SUFFIX}.tar.gz") set(BOOST_SOURCES_DIR ${CMAKE_BINARY_DIR}/${BOOST_NAME}) + if (IS_DIRECTORY "${BOOST_SOURCES_DIR}") + set(FirstRun OFF) + else() + set(FirstRun ON) + endif() + DownloadPackage(${BOOST_MD5} ${BOOST_URL} "${BOOST_SOURCES_DIR}") @@ -78,7 +84,22 @@ ${BOOST_SOURCES_DIR}/libs/system/src/error_code.cpp ) + if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") + add_definitions(-DBOOST_SYSTEM_USE_STRERROR=1) + + execute_process( + COMMAND ${PATCH_EXECUTABLE} -p0 -N -i + ${ORTHANC_ROOT}/Resources/Patches/boost-1.65.1-linux-standard-base.patch + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + if (FirstRun AND Failure) + message(FATAL_ERROR "Error while patching a file") + endif() + endif() + + ## ## Configuration of boost::thread ## @@ -199,13 +220,29 @@ ${BOOST_SOURCES_DIR}/libs/locale/src/util/locale_data.cpp ) - if (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR - CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR - CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "kFreeBSD" OR - CMAKE_SYSTEM_NAME STREQUAL "PNaCl" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl32" OR - CMAKE_SYSTEM_NAME STREQUAL "NaCl64") + if (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD" OR + CMAKE_SYSTEM_VERSION STREQUAL "LinuxStandardBase") + list(APPEND BOOST_SOURCES + ${BOOST_SOURCES_DIR}/libs/locale/src/std/codecvt.cpp + ${BOOST_SOURCES_DIR}/libs/locale/src/std/collate.cpp + ${BOOST_SOURCES_DIR}/libs/locale/src/std/converter.cpp + ${BOOST_SOURCES_DIR}/libs/locale/src/std/numeric.cpp + ${BOOST_SOURCES_DIR}/libs/locale/src/std/std_backend.cpp + ) + + add_definitions( + -DBOOST_LOCALE_WITH_ICONV=1 + -DBOOST_LOCALE_NO_WINAPI_BACKEND=1 + -DBOOST_LOCALE_NO_POSIX_BACKEND=1 + ) + + elseif (CMAKE_SYSTEM_NAME STREQUAL "Linux" OR + CMAKE_SYSTEM_NAME STREQUAL "Darwin" OR + CMAKE_SYSTEM_NAME STREQUAL "FreeBSD" OR + 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 @@ -220,21 +257,6 @@ -DBOOST_LOCALE_NO_STD_BACKEND=1 ) - elseif (CMAKE_SYSTEM_NAME STREQUAL "OpenBSD") - list(APPEND BOOST_SOURCES - ${BOOST_SOURCES_DIR}/libs/locale/src/std/codecvt.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/std/collate.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/std/converter.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/std/numeric.cpp - ${BOOST_SOURCES_DIR}/libs/locale/src/std/std_backend.cpp - ) - - add_definitions( - -DBOOST_LOCALE_WITH_ICONV=1 - -DBOOST_LOCALE_NO_WINAPI_BACKEND=1 - -DBOOST_LOCALE_NO_POSIX_BACKEND=1 - ) - elseif (CMAKE_SYSTEM_NAME STREQUAL "Windows") list(APPEND BOOST_SOURCES ${BOOST_SOURCES_DIR}/libs/locale/src/win32/collate.cpp
--- a/Resources/Orthanc/Resources/CMake/Compiler.cmake Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Resources/CMake/Compiler.cmake Thu Jan 04 10:49:34 2018 +0100 @@ -1,6 +1,7 @@ # This file sets all the compiler-related flags -if (CMAKE_CROSSCOMPILING) +if (CMAKE_CROSSCOMPILING OR + "${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") # Cross-compilation necessarily implies standalone and static build SET(STATIC_BUILD ON) SET(STANDALONE_BUILD ON) @@ -87,7 +88,7 @@ # Remove the "-rdynamic" option # http://www.mail-archive.com/cmake@cmake.org/msg08837.html set(CMAKE_SHARED_LIBRARY_LINK_CXX_FLAGS "") - link_libraries(uuid pthread) + link_libraries(pthread) if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "OpenBSD") link_libraries(rt) @@ -117,11 +118,6 @@ ) endif() - CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H) - if (NOT HAVE_UUID_H) - message(FATAL_ERROR "Please install the uuid-dev package (or e2fsprogs if OpenBSD)") - endif() - elseif(${CMAKE_SYSTEM_NAME} STREQUAL "Windows") if (MSVC) message("MSVC compiler version = " ${MSVC_VERSION} "\n") @@ -174,23 +170,14 @@ ) link_libraries(iconv) - CHECK_INCLUDE_FILES(uuid/uuid.h HAVE_UUID_H) - if (NOT HAVE_UUID_H) - message(FATAL_ERROR "Please install the uuid-dev package") - endif() +elseif (CMAKE_SYSTEM_NAME STREQUAL "Emscripten") + message("Building using Emscripten (for WebAssembly or asm.js targets)") else() message(FATAL_ERROR "Support your platform here") endif() -if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - SET(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -I${LSB_PATH}/include") - SET(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -nostdinc++ -I${LSB_PATH}/include -I${LSB_PATH}/include/c++ -I${LSB_PATH}/include/c++/backward -fpermissive") - SET(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} --lsb-target-version=${LSB_TARGET_VERSION} -L${LSB_LIBPATH}") -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") @@ -208,6 +195,21 @@ endif() +if (CMAKE_COMPILER_IS_GNUCXX) + # "When creating a static library using binutils (ar) and there + # exist a duplicate object name (e.g. a/Foo.cpp.o, b/Foo.cpp.o), the + # resulting static library can end up having only one of the + # duplicate objects. [...] This bug only happens if there are many + # objects." The trick consists in replacing the "r" argument + # ("replace") provided to "ar" (as used in CMake < 3.1) by the "q" + # argument ("quick append"). This is because of the fact that CMake + # will invoke "ar" several times with several batches of ".o" + # objects, and using "r" would overwrite symbols defined in + # preceding batches. https://cmake.org/Bug/view.php?id=14874 + set(CMAKE_CXX_ARCHIVE_APPEND "<CMAKE_AR> <LINK_FLAGS> q <TARGET> <OBJECTS>") +endif() + + if (STATIC_BUILD) add_definitions(-DORTHANC_STATIC=1) else()
--- a/Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Resources/CMake/DcmtkConfiguration.cmake Thu Jan 04 10:49:34 2018 +0100 @@ -9,8 +9,6 @@ SET(DCMTK_SOURCES_DIR ${CMAKE_BINARY_DIR}/dcmtk-3.6.0) 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") else() SET(DCMTK_VERSION_NUMBER 362) SET(DCMTK_PACKAGE_VERSION "3.6.2") @@ -99,23 +97,28 @@ endif() ENDIF() + if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") + SET(DCMTK_ENABLE_CHARSET_CONVERSION "iconv" CACHE STRING "") + SET(HAVE_PROTOTYPE_STD__ISINF 1 CACHE INTERNAL "") + SET(HAVE_PROTOTYPE_STD__ISNAN 1 CACHE INTERNAL "") + SET(HAVE_SYS_GETTID 0 CACHE INTERNAL "") + + execute_process( + COMMAND ${PATCH_EXECUTABLE} -p0 -N -i + ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.2-linux-standard-base.patch + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + + if (FirstRun AND Failure) + message(FATAL_ERROR "Error while patching a file") + endif() + endif() + SET(DCMTK_SOURCE_DIR ${DCMTK_SOURCES_DIR}) include(${DCMTK_SOURCES_DIR}/CMake/CheckFunctionWithHeaderExists.cmake) include(${DCMTK_SOURCES_DIR}/CMake/GenerateDCMTKConfigure.cmake) - if ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - set(HAVE_SSTREAM 1) - set(HAVE_PROTOTYPE_BZERO 1) - set(HAVE_PROTOTYPE_GETHOSTNAME 1) - set(HAVE_PROTOTYPE_GETSOCKOPT 1) - set(HAVE_PROTOTYPE_SETSOCKOPT 1) - set(HAVE_PROTOTYPE_CONNECT 1) - set(HAVE_PROTOTYPE_BIND 1) - set(HAVE_PROTOTYPE_ACCEPT 1) - set(HAVE_PROTOTYPE_SETSOCKNAME 1) - set(HAVE_PROTOTYPE_GETSOCKNAME 1) - endif() - set(DCMTK_PACKAGE_VERSION_SUFFIX "") set(DCMTK_PACKAGE_VERSION_NUMBER ${DCMTK_VERSION_NUMBER}) @@ -151,7 +154,7 @@ ) endif() - if (ENABLE_JPEG) + if (ENABLE_DCMTK_JPEG) AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libsrc DCMTK_SOURCES) AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libijg8 DCMTK_SOURCES) AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpeg/libijg12 DCMTK_SOURCES) @@ -179,7 +182,7 @@ endif() - if (ENABLE_JPEG_LOSSLESS) + if (ENABLE_DCMTK_JPEG_LOSSLESS) AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpls/libsrc DCMTK_SOURCES) AUX_SOURCE_DIRECTORY(${DCMTK_SOURCES_DIR}/dcmjpls/libcharls DCMTK_SOURCES) include_directories( @@ -223,7 +226,8 @@ USE_DCMTK_360) # This is a patch for MinGW64 execute_process( - COMMAND ${PATCH_EXECUTABLE} -p0 -N -i ${DCMTK_PATCH_MINGW64} + COMMAND ${PATCH_EXECUTABLE} -p0 -N -i + ${ORTHANC_ROOT}/Resources/Patches/dcmtk-3.6.0-mingw64.patch WORKING_DIRECTORY ${CMAKE_BINARY_DIR} RESULT_VARIABLE Failure )
--- a/Resources/Orthanc/Resources/CMake/JsonCppConfiguration.cmake Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Resources/CMake/JsonCppConfiguration.cmake Thu Jan 04 10:49:34 2018 +0100 @@ -48,9 +48,10 @@ JSONCPP_VERSION_MAJOR ${JSONCPP_VERSION_MAJOR1}) message("JsonCpp major version: ${JSONCPP_VERSION_MAJOR}") - if (CMAKE_COMPILER_IS_GNUCXX AND + if ((CMAKE_COMPILER_IS_GNUCXX OR + "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang") AND JSONCPP_VERSION_MAJOR GREATER 0) - message("Switching to C++11 standard, as version of JsonCpp is >= 1.0.0") + message("Switching to C++11 standard in gcc/clang, as version of JsonCpp is >= 1.0.0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11 -Wno-deprecated-declarations") endif() else()
--- a/Resources/Orthanc/Resources/CMake/LibCurlConfiguration.cmake Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Resources/CMake/LibCurlConfiguration.cmake Thu Jan 04 10:49:34 2018 +0100 @@ -1,10 +1,29 @@ if (STATIC_BUILD OR NOT USE_SYSTEM_CURL) - 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") + SET(CURL_SOURCES_DIR ${CMAKE_BINARY_DIR}/curl-7.57.0) + SET(CURL_URL "http://www.orthanc-server.com/downloads/third-party/curl-7.57.0.tar.gz") + SET(CURL_MD5 "c7aab73aaf5e883ca1d7518f93649dc2") + if (IS_DIRECTORY "${CURL_SOURCES_DIR}") + set(FirstRun OFF) + else() + set(FirstRun ON) + endif() + DownloadPackage(${CURL_MD5} ${CURL_URL} "${CURL_SOURCES_DIR}") + if (FirstRun) + execute_process( + COMMAND ${PATCH_EXECUTABLE} -p0 -N -i + ${ORTHANC_ROOT}/Resources/Patches/curl-7.57.0-cmake.patch + WORKING_DIRECTORY ${CMAKE_BINARY_DIR} + RESULT_VARIABLE Failure + ) + + if (Failure) + message(FATAL_ERROR "Error while patching a file") + endif() + endif() + include_directories( ${CURL_SOURCES_DIR}/include ) @@ -42,7 +61,7 @@ endif() if (NOT EXISTS "${CURL_SOURCES_DIR}/lib/curl_config.h") - file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "") + #file(WRITE ${CURL_SOURCES_DIR}/lib/curl_config.h "") 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") @@ -70,48 +89,234 @@ set_property( SOURCE ${CURL_SOURCES} - PROPERTY COMPILE_DEFINITIONS "HAVE_TIME_H;HAVE_STRUCT_TIMEVAL;HAVE_SYS_STAT_H;HAVE_SOCKET;HAVE_STRUCT_SOCKADDR_STORAGE;HAVE_SYS_SOCKET_H;HAVE_SOCKET;HAVE_SYS_SOCKET_H;HAVE_NETINET_IN_H;HAVE_NETDB_H;HAVE_FCNTL_O_NONBLOCK;HAVE_FCNTL_H;HAVE_SELECT;HAVE_ERRNO_H;HAVE_SEND;HAVE_RECV;HAVE_LONGLONG;OS=\"${TMP_OS}\"" + PROPERTY COMPILE_DEFINITIONS "HAVE_CONFIG_H=1;OS=\"${TMP_OS}\"" ) + + include(${CURL_SOURCES_DIR}/CMake/Macros.cmake) + + check_include_file_concat("alloca.h" HAVE_ALLOCA_H) + check_include_file_concat("arpa/inet.h" HAVE_ARPA_INET_H) + check_include_file_concat("arpa/tftp.h" HAVE_ARPA_TFTP_H) + check_include_file_concat("assert.h" HAVE_ASSERT_H) + check_include_file_concat("crypto.h" HAVE_CRYPTO_H) + check_include_file_concat("des.h" HAVE_DES_H) + check_include_file_concat("dlfcn.h" HAVE_DLFCN_H) + check_include_file_concat("err.h" HAVE_ERR_H) + check_include_file_concat("errno.h" HAVE_ERRNO_H) + check_include_file_concat("fcntl.h" HAVE_FCNTL_H) + check_include_file_concat("idn2.h" HAVE_IDN2_H) + check_include_file_concat("ifaddrs.h" HAVE_IFADDRS_H) + check_include_file_concat("inttypes.h" HAVE_INTTYPES_H) + check_include_file_concat("io.h" HAVE_IO_H) + check_include_file_concat("krb.h" HAVE_KRB_H) + check_include_file_concat("libgen.h" HAVE_LIBGEN_H) + check_include_file_concat("limits.h" HAVE_LIMITS_H) + check_include_file_concat("locale.h" HAVE_LOCALE_H) + check_include_file_concat("malloc.h" HAVE_MALLOC_H) + check_include_file_concat("memory.h" HAVE_MEMORY_H) + check_include_file_concat("net/if.h" HAVE_NET_IF_H) + check_include_file_concat("netdb.h" HAVE_NETDB_H) + check_include_file_concat("netinet/if_ether.h" HAVE_NETINET_IF_ETHER_H) + check_include_file_concat("netinet/in.h" HAVE_NETINET_IN_H) + check_include_file_concat("netinet/tcp.h" HAVE_NETINET_TCP_H) + check_include_file_concat("openssl/crypto.h" HAVE_OPENSSL_CRYPTO_H) + check_include_file_concat("openssl/engine.h" HAVE_OPENSSL_ENGINE_H) + check_include_file_concat("openssl/err.h" HAVE_OPENSSL_ERR_H) + check_include_file_concat("openssl/pem.h" HAVE_OPENSSL_PEM_H) + check_include_file_concat("openssl/rand.h" HAVE_OPENSSL_RAND_H) + check_include_file_concat("openssl/rsa.h" HAVE_OPENSSL_RSA_H) + check_include_file_concat("openssl/ssl.h" HAVE_OPENSSL_SSL_H) + check_include_file_concat("openssl/x509.h" HAVE_OPENSSL_X509_H) + check_include_file_concat("pem.h" HAVE_PEM_H) + check_include_file_concat("poll.h" HAVE_POLL_H) + check_include_file_concat("process.h" HAVE_PROCESS_H) + check_include_file_concat("pwd.h" HAVE_PWD_H) + check_include_file_concat("rsa.h" HAVE_RSA_H) + check_include_file_concat("setjmp.h" HAVE_SETJMP_H) + check_include_file_concat("sgtty.h" HAVE_SGTTY_H) + check_include_file_concat("signal.h" HAVE_SIGNAL_H) + check_include_file_concat("sockio.h" HAVE_SOCKIO_H) + check_include_file_concat("ssl.h" HAVE_SSL_H) + check_include_file_concat("stdbool.h" HAVE_STDBOOL_H) + check_include_file_concat("stddef.h" HAVE_STDDEF_H) + check_include_file_concat("stdint.h" HAVE_STDINT_H) + check_include_file_concat("stdint.h" HAVE_STDINT_H) + check_include_file_concat("stdio.h" HAVE_STDIO_H) + check_include_file_concat("stdio.h" HAVE_STDIO_H) + check_include_file_concat("stdlib.h" HAVE_STDLIB_H) + check_include_file_concat("string.h" HAVE_STRING_H) + check_include_file_concat("strings.h" HAVE_STRINGS_H) + check_include_file_concat("stropts.h" HAVE_STROPTS_H) + check_include_file_concat("sys/filio.h" HAVE_SYS_FILIO_H) + check_include_file_concat("sys/ioctl.h" HAVE_SYS_IOCTL_H) + check_include_file_concat("sys/param.h" HAVE_SYS_PARAM_H) + check_include_file_concat("sys/poll.h" HAVE_SYS_POLL_H) + check_include_file_concat("sys/resource.h" HAVE_SYS_RESOURCE_H) + check_include_file_concat("sys/select.h" HAVE_SYS_SELECT_H) + check_include_file_concat("sys/socket.h" HAVE_SYS_SOCKET_H) + check_include_file_concat("sys/sockio.h" HAVE_SYS_SOCKIO_H) + check_include_file_concat("sys/stat.h" HAVE_SYS_STAT_H) + check_include_file_concat("sys/time.h" HAVE_SYS_TIME_H) + check_include_file_concat("sys/types.h" HAVE_SYS_TYPES_H) + check_include_file_concat("sys/uio.h" HAVE_SYS_UIO_H) + check_include_file_concat("sys/un.h" HAVE_SYS_UN_H) + check_include_file_concat("sys/utime.h" HAVE_SYS_UTIME_H) + check_include_file_concat("sys/utsname.h" HAVE_SYS_UTSNAME_H) + check_include_file_concat("sys/xattr.h" HAVE_SYS_XATTR_H) + check_include_file_concat("termio.h" HAVE_TERMIO_H) + check_include_file_concat("termios.h" HAVE_TERMIOS_H) + check_include_file_concat("time.h" HAVE_TIME_H) + check_include_file_concat("unistd.h" HAVE_UNISTD_H) + check_include_file_concat("utime.h" HAVE_UTIME_H) + check_include_file_concat("x509.h" HAVE_X509_H) + + check_type_size("size_t" SIZEOF_SIZE_T) + check_type_size("ssize_t" SIZEOF_SSIZE_T) + check_type_size("long long" SIZEOF_LONG_LONG) + check_type_size("long" SIZEOF_LONG) + check_type_size("short" SIZEOF_SHORT) + check_type_size("int" SIZEOF_INT) + check_type_size("__int64" SIZEOF___INT64) + check_type_size("long double" SIZEOF_LONG_DOUBLE) + check_type_size("time_t" SIZEOF_TIME_T) + check_type_size("off_t" SIZEOF_OFF_T) + check_type_size("socklen_t" CURL_SIZEOF_CURL_SOCKLEN_T) - if ("${CMAKE_SIZEOF_VOID_P}" EQUAL "8") - add_definitions( - -DRECV_TYPE_ARG1=int - -DRECV_TYPE_ARG2=void* - -DRECV_TYPE_ARG3=size_t - -DRECV_TYPE_ARG4=int - -DRECV_TYPE_RETV=ssize_t - -DSEND_TYPE_ARG1=int - -DSEND_TYPE_ARG2=void* - -DSEND_QUAL_ARG2=const - -DSEND_TYPE_ARG3=size_t - -DSEND_TYPE_ARG4=int - -DSEND_TYPE_RETV=ssize_t - -DSIZEOF_SHORT=2 - -DSIZEOF_INT=4 - -DSIZEOF_SIZE_T=8 + check_symbol_exists(basename "${CURL_INCLUDES}" HAVE_BASENAME) + check_symbol_exists(socket "${CURL_INCLUDES}" HAVE_SOCKET) + # poll on macOS is unreliable, it first did not exist, then was broken until + # fixed in 10.9 only to break again in 10.12. + if(NOT APPLE) + check_symbol_exists(poll "${CURL_INCLUDES}" HAVE_POLL) + endif() + check_symbol_exists(select "${CURL_INCLUDES}" HAVE_SELECT) + check_symbol_exists(strdup "${CURL_INCLUDES}" HAVE_STRDUP) + check_symbol_exists(strstr "${CURL_INCLUDES}" HAVE_STRSTR) + check_symbol_exists(strtok_r "${CURL_INCLUDES}" HAVE_STRTOK_R) + check_symbol_exists(strftime "${CURL_INCLUDES}" HAVE_STRFTIME) + check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) + check_symbol_exists(strcasecmp "${CURL_INCLUDES}" HAVE_STRCASECMP) + check_symbol_exists(stricmp "${CURL_INCLUDES}" HAVE_STRICMP) + check_symbol_exists(strcmpi "${CURL_INCLUDES}" HAVE_STRCMPI) + check_symbol_exists(strncmpi "${CURL_INCLUDES}" HAVE_STRNCMPI) + check_symbol_exists(alarm "${CURL_INCLUDES}" HAVE_ALARM) + if(NOT HAVE_STRNCMPI) + set(HAVE_STRCMPI) + endif(NOT HAVE_STRNCMPI) + + check_symbol_exists(gethostbyaddr "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR) + check_symbol_exists(gethostbyaddr_r "${CURL_INCLUDES}" HAVE_GETHOSTBYADDR_R) + check_symbol_exists(gettimeofday "${CURL_INCLUDES}" HAVE_GETTIMEOFDAY) + check_symbol_exists(inet_addr "${CURL_INCLUDES}" HAVE_INET_ADDR) + check_symbol_exists(inet_ntoa "${CURL_INCLUDES}" HAVE_INET_NTOA) + check_symbol_exists(inet_ntoa_r "${CURL_INCLUDES}" HAVE_INET_NTOA_R) + check_symbol_exists(tcsetattr "${CURL_INCLUDES}" HAVE_TCSETATTR) + check_symbol_exists(tcgetattr "${CURL_INCLUDES}" HAVE_TCGETATTR) + check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) + check_symbol_exists(closesocket "${CURL_INCLUDES}" HAVE_CLOSESOCKET) + check_symbol_exists(setvbuf "${CURL_INCLUDES}" HAVE_SETVBUF) + check_symbol_exists(sigsetjmp "${CURL_INCLUDES}" HAVE_SIGSETJMP) + check_symbol_exists(getpass_r "${CURL_INCLUDES}" HAVE_GETPASS_R) + check_symbol_exists(strlcat "${CURL_INCLUDES}" HAVE_STRLCAT) + check_symbol_exists(getpwuid "${CURL_INCLUDES}" HAVE_GETPWUID) + check_symbol_exists(geteuid "${CURL_INCLUDES}" HAVE_GETEUID) + check_symbol_exists(utime "${CURL_INCLUDES}" HAVE_UTIME) + check_symbol_exists(gmtime_r "${CURL_INCLUDES}" HAVE_GMTIME_R) + check_symbol_exists(localtime_r "${CURL_INCLUDES}" HAVE_LOCALTIME_R) + + check_symbol_exists(gethostbyname "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME) + check_symbol_exists(gethostbyname_r "${CURL_INCLUDES}" HAVE_GETHOSTBYNAME_R) + + check_symbol_exists(signal "${CURL_INCLUDES}" HAVE_SIGNAL_FUNC) + check_symbol_exists(SIGALRM "${CURL_INCLUDES}" HAVE_SIGNAL_MACRO) + if(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO) + set(HAVE_SIGNAL 1) + endif(HAVE_SIGNAL_FUNC AND HAVE_SIGNAL_MACRO) + check_symbol_exists(uname "${CURL_INCLUDES}" HAVE_UNAME) + check_symbol_exists(strtoll "${CURL_INCLUDES}" HAVE_STRTOLL) + check_symbol_exists(_strtoi64 "${CURL_INCLUDES}" HAVE__STRTOI64) + check_symbol_exists(strerror_r "${CURL_INCLUDES}" HAVE_STRERROR_R) + check_symbol_exists(siginterrupt "${CURL_INCLUDES}" HAVE_SIGINTERRUPT) + check_symbol_exists(perror "${CURL_INCLUDES}" HAVE_PERROR) + check_symbol_exists(fork "${CURL_INCLUDES}" HAVE_FORK) + check_symbol_exists(getaddrinfo "${CURL_INCLUDES}" HAVE_GETADDRINFO) + check_symbol_exists(freeaddrinfo "${CURL_INCLUDES}" HAVE_FREEADDRINFO) + check_symbol_exists(freeifaddrs "${CURL_INCLUDES}" HAVE_FREEIFADDRS) + check_symbol_exists(pipe "${CURL_INCLUDES}" HAVE_PIPE) + check_symbol_exists(ftruncate "${CURL_INCLUDES}" HAVE_FTRUNCATE) + check_symbol_exists(getprotobyname "${CURL_INCLUDES}" HAVE_GETPROTOBYNAME) + check_symbol_exists(getrlimit "${CURL_INCLUDES}" HAVE_GETRLIMIT) + check_symbol_exists(setlocale "${CURL_INCLUDES}" HAVE_SETLOCALE) + check_symbol_exists(setmode "${CURL_INCLUDES}" HAVE_SETMODE) + check_symbol_exists(setrlimit "${CURL_INCLUDES}" HAVE_SETRLIMIT) + check_symbol_exists(fcntl "${CURL_INCLUDES}" HAVE_FCNTL) + check_symbol_exists(ioctl "${CURL_INCLUDES}" HAVE_IOCTL) + check_symbol_exists(setsockopt "${CURL_INCLUDES}" HAVE_SETSOCKOPT) + + if(HAVE_SIZEOF_LONG_LONG) + set(HAVE_LONGLONG 1) + set(HAVE_LL 1) + endif(HAVE_SIZEOF_LONG_LONG) + + check_function_exists(mach_absolute_time HAVE_MACH_ABSOLUTE_TIME) + check_function_exists(gethostname HAVE_GETHOSTNAME) + + check_include_file_concat("pthread.h" HAVE_PTHREAD_H) + check_symbol_exists(recv "sys/socket.h" HAVE_RECV) + check_symbol_exists(send "sys/socket.h" HAVE_SEND) + + check_struct_has_member("struct sockaddr_un" sun_path "sys/un.h" USE_UNIX_SOCKETS) + + set(CMAKE_REQUIRED_INCLUDES "${CURL_SOURCES_DIR}/include") + set(CMAKE_EXTRA_INCLUDE_FILES "curl/system.h") + check_type_size("curl_off_t" SIZEOF_CURL_OFF_T) + + add_definitions(-DHAVE_GLIBC_STRERROR_R=1) + + include(${CURL_SOURCES_DIR}/CMake/OtherTests.cmake) + + foreach(CURL_TEST + HAVE_FCNTL_O_NONBLOCK + HAVE_IOCTLSOCKET + HAVE_IOCTLSOCKET_CAMEL + HAVE_IOCTLSOCKET_CAMEL_FIONBIO + HAVE_IOCTLSOCKET_FIONBIO + HAVE_IOCTL_FIONBIO + HAVE_IOCTL_SIOCGIFADDR + HAVE_SETSOCKOPT_SO_NONBLOCK + HAVE_SOCKADDR_IN6_SIN6_SCOPE_ID + TIME_WITH_SYS_TIME + HAVE_O_NONBLOCK + HAVE_GETHOSTBYADDR_R_5 + HAVE_GETHOSTBYADDR_R_7 + HAVE_GETHOSTBYADDR_R_8 + HAVE_GETHOSTBYADDR_R_5_REENTRANT + HAVE_GETHOSTBYADDR_R_7_REENTRANT + HAVE_GETHOSTBYADDR_R_8_REENTRANT + HAVE_GETHOSTBYNAME_R_3 + HAVE_GETHOSTBYNAME_R_5 + HAVE_GETHOSTBYNAME_R_6 + HAVE_GETHOSTBYNAME_R_3_REENTRANT + HAVE_GETHOSTBYNAME_R_5_REENTRANT + HAVE_GETHOSTBYNAME_R_6_REENTRANT + HAVE_SOCKLEN_T + HAVE_IN_ADDR_T + HAVE_BOOL_T + STDC_HEADERS + RETSIGTYPE_TEST + HAVE_INET_NTOA_R_DECL + HAVE_INET_NTOA_R_DECL_REENTRANT + HAVE_GETADDRINFO + HAVE_FILE_OFFSET_BITS ) - elseif ("${CMAKE_SIZEOF_VOID_P}" EQUAL "4") - add_definitions( - -DRECV_TYPE_ARG1=int - -DRECV_TYPE_ARG2=void* - -DRECV_TYPE_ARG3=size_t - -DRECV_TYPE_ARG4=int - -DRECV_TYPE_RETV=int - -DSEND_TYPE_ARG1=int - -DSEND_TYPE_ARG2=void* - -DSEND_QUAL_ARG2=const - -DSEND_TYPE_ARG3=size_t - -DSEND_TYPE_ARG4=int - -DSEND_TYPE_RETV=int - -DSIZEOF_SHORT=2 - -DSIZEOF_INT=4 - -DSIZEOF_SIZE_T=4 - ) - else() - message(FATAL_ERROR "Support your platform here") - endif() + curl_internal_test(${CURL_TEST}) + endforeach(CURL_TEST) + + configure_file( + ${CURL_SOURCES_DIR}/lib/curl_config.h.cmake + ${CURL_SOURCES_DIR}/lib/curl_config.h + ) endif() - else() include(FindCURL) include_directories(${CURL_INCLUDE_DIRS})
--- a/Resources/Orthanc/Resources/CMake/OpenSslConfiguration.cmake Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Resources/CMake/OpenSslConfiguration.cmake Thu Jan 04 10:49:34 2018 +0100 @@ -1,232 +1,219 @@ -if (ENABLE_SSL) - if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL) - # WARNING - We had to repack the upstream ".tar.gz" file to a ZIP - # file, as the upstream distribution ships symbolic links that are - # not always properly handled when uncompressing on Windows. +if (STATIC_BUILD OR NOT USE_SYSTEM_OPENSSL) + # WARNING - We had to repack the upstream ".tar.gz" file to a ZIP + # file, as the upstream distribution ships symbolic links that are + # not always properly handled when uncompressing on Windows. + + SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-1.0.2d) + SET(OPENSSL_URL "http://www.orthanc-server.com/downloads/third-party/openssl-1.0.2d.zip") + SET(OPENSSL_MD5 "4b2ac15fc6db17f3dadc54482d3eee85") - SET(OPENSSL_SOURCES_DIR ${CMAKE_BINARY_DIR}/openssl-1.0.2d) - 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}") + set(FirstRun OFF) + else() + set(FirstRun ON) + endif() - if (IS_DIRECTORY "${OPENSSL_SOURCES_DIR}") - set(FirstRun OFF) - else() - set(FirstRun ON) - endif() + DownloadPackage(${OPENSSL_MD5} ${OPENSSL_URL} "${OPENSSL_SOURCES_DIR}") - DownloadPackage(${OPENSSL_MD5} ${OPENSSL_URL} "${OPENSSL_SOURCES_DIR}") + add_definitions( + -DOPENSSL_THREADS + -DOPENSSL_IA32_SSE2 + -DOPENSSL_NO_ASM + -DOPENSSL_NO_DYNAMIC_ENGINE + -DNO_WINDOWS_BRAINDEATH - add_definitions( - -DOPENSSL_THREADS - -DOPENSSL_IA32_SSE2 - -DOPENSSL_NO_ASM - -DOPENSSL_NO_DYNAMIC_ENGINE - -DNO_WINDOWS_BRAINDEATH - - -DOPENSSL_NO_BF - -DOPENSSL_NO_CAMELLIA - -DOPENSSL_NO_CAST - -DOPENSSL_NO_EC_NISTP_64_GCC_128 - -DOPENSSL_NO_GMP - -DOPENSSL_NO_GOST - -DOPENSSL_NO_HW - -DOPENSSL_NO_JPAKE - -DOPENSSL_NO_IDEA - -DOPENSSL_NO_KRB5 - -DOPENSSL_NO_MD2 - -DOPENSSL_NO_MDC2 - -DOPENSSL_NO_MD4 - -DOPENSSL_NO_RC2 - -DOPENSSL_NO_RC4 - -DOPENSSL_NO_RC5 - -DOPENSSL_NO_RFC3779 - -DOPENSSL_NO_SCTP - -DOPENSSL_NO_STORE - -DOPENSSL_NO_SEED - -DOPENSSL_NO_WHIRLPOOL - -DOPENSSL_NO_RIPEMD - ) + -DOPENSSL_NO_BF + -DOPENSSL_NO_CAMELLIA + -DOPENSSL_NO_CAST + -DOPENSSL_NO_EC_NISTP_64_GCC_128 + -DOPENSSL_NO_GMP + -DOPENSSL_NO_GOST + -DOPENSSL_NO_HW + -DOPENSSL_NO_JPAKE + -DOPENSSL_NO_IDEA + -DOPENSSL_NO_KRB5 + -DOPENSSL_NO_MD2 + -DOPENSSL_NO_MDC2 + -DOPENSSL_NO_MD4 + -DOPENSSL_NO_RC2 + -DOPENSSL_NO_RC4 + -DOPENSSL_NO_RC5 + -DOPENSSL_NO_RFC3779 + -DOPENSSL_NO_SCTP + -DOPENSSL_NO_STORE + -DOPENSSL_NO_SEED + -DOPENSSL_NO_WHIRLPOOL + -DOPENSSL_NO_RIPEMD + ) - include_directories( - ${OPENSSL_SOURCES_DIR} - ${OPENSSL_SOURCES_DIR}/crypto - ${OPENSSL_SOURCES_DIR}/crypto/asn1 - ${OPENSSL_SOURCES_DIR}/crypto/modes - ${OPENSSL_SOURCES_DIR}/crypto/evp - ${OPENSSL_SOURCES_DIR}/include - ) + include_directories( + ${OPENSSL_SOURCES_DIR} + ${OPENSSL_SOURCES_DIR}/crypto + ${OPENSSL_SOURCES_DIR}/crypto/asn1 + ${OPENSSL_SOURCES_DIR}/crypto/modes + ${OPENSSL_SOURCES_DIR}/crypto/evp + ${OPENSSL_SOURCES_DIR}/include + ) - set(OPENSSL_SOURCES_SUBDIRS - ${OPENSSL_SOURCES_DIR}/crypto - ${OPENSSL_SOURCES_DIR}/crypto/aes - ${OPENSSL_SOURCES_DIR}/crypto/asn1 - ${OPENSSL_SOURCES_DIR}/crypto/bio - ${OPENSSL_SOURCES_DIR}/crypto/bn - ${OPENSSL_SOURCES_DIR}/crypto/buffer - ${OPENSSL_SOURCES_DIR}/crypto/cmac - ${OPENSSL_SOURCES_DIR}/crypto/cms - ${OPENSSL_SOURCES_DIR}/crypto/comp - ${OPENSSL_SOURCES_DIR}/crypto/conf - ${OPENSSL_SOURCES_DIR}/crypto/des - ${OPENSSL_SOURCES_DIR}/crypto/dh - ${OPENSSL_SOURCES_DIR}/crypto/dsa - ${OPENSSL_SOURCES_DIR}/crypto/dso - ${OPENSSL_SOURCES_DIR}/crypto/engine - ${OPENSSL_SOURCES_DIR}/crypto/err - ${OPENSSL_SOURCES_DIR}/crypto/evp - ${OPENSSL_SOURCES_DIR}/crypto/hmac - ${OPENSSL_SOURCES_DIR}/crypto/lhash - ${OPENSSL_SOURCES_DIR}/crypto/md5 - ${OPENSSL_SOURCES_DIR}/crypto/modes - ${OPENSSL_SOURCES_DIR}/crypto/objects - ${OPENSSL_SOURCES_DIR}/crypto/ocsp - ${OPENSSL_SOURCES_DIR}/crypto/pem - ${OPENSSL_SOURCES_DIR}/crypto/pkcs12 - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7 - ${OPENSSL_SOURCES_DIR}/crypto/pqueue - ${OPENSSL_SOURCES_DIR}/crypto/rand - ${OPENSSL_SOURCES_DIR}/crypto/rsa - ${OPENSSL_SOURCES_DIR}/crypto/sha - ${OPENSSL_SOURCES_DIR}/crypto/srp - ${OPENSSL_SOURCES_DIR}/crypto/stack - ${OPENSSL_SOURCES_DIR}/crypto/ts - ${OPENSSL_SOURCES_DIR}/crypto/txt_db - ${OPENSSL_SOURCES_DIR}/crypto/ui - ${OPENSSL_SOURCES_DIR}/crypto/x509 - ${OPENSSL_SOURCES_DIR}/crypto/x509v3 - ${OPENSSL_SOURCES_DIR}/ssl - ) + set(OPENSSL_SOURCES_SUBDIRS + ${OPENSSL_SOURCES_DIR}/crypto + ${OPENSSL_SOURCES_DIR}/crypto/aes + ${OPENSSL_SOURCES_DIR}/crypto/asn1 + ${OPENSSL_SOURCES_DIR}/crypto/bio + ${OPENSSL_SOURCES_DIR}/crypto/bn + ${OPENSSL_SOURCES_DIR}/crypto/buffer + ${OPENSSL_SOURCES_DIR}/crypto/cmac + ${OPENSSL_SOURCES_DIR}/crypto/cms + ${OPENSSL_SOURCES_DIR}/crypto/comp + ${OPENSSL_SOURCES_DIR}/crypto/conf + ${OPENSSL_SOURCES_DIR}/crypto/des + ${OPENSSL_SOURCES_DIR}/crypto/dh + ${OPENSSL_SOURCES_DIR}/crypto/dsa + ${OPENSSL_SOURCES_DIR}/crypto/dso + ${OPENSSL_SOURCES_DIR}/crypto/engine + ${OPENSSL_SOURCES_DIR}/crypto/err + ${OPENSSL_SOURCES_DIR}/crypto/evp + ${OPENSSL_SOURCES_DIR}/crypto/hmac + ${OPENSSL_SOURCES_DIR}/crypto/lhash + ${OPENSSL_SOURCES_DIR}/crypto/md5 + ${OPENSSL_SOURCES_DIR}/crypto/modes + ${OPENSSL_SOURCES_DIR}/crypto/objects + ${OPENSSL_SOURCES_DIR}/crypto/ocsp + ${OPENSSL_SOURCES_DIR}/crypto/pem + ${OPENSSL_SOURCES_DIR}/crypto/pkcs12 + ${OPENSSL_SOURCES_DIR}/crypto/pkcs7 + ${OPENSSL_SOURCES_DIR}/crypto/pqueue + ${OPENSSL_SOURCES_DIR}/crypto/rand + ${OPENSSL_SOURCES_DIR}/crypto/rsa + ${OPENSSL_SOURCES_DIR}/crypto/sha + ${OPENSSL_SOURCES_DIR}/crypto/srp + ${OPENSSL_SOURCES_DIR}/crypto/stack + ${OPENSSL_SOURCES_DIR}/crypto/ts + ${OPENSSL_SOURCES_DIR}/crypto/txt_db + ${OPENSSL_SOURCES_DIR}/crypto/ui + ${OPENSSL_SOURCES_DIR}/crypto/x509 + ${OPENSSL_SOURCES_DIR}/crypto/x509v3 + ${OPENSSL_SOURCES_DIR}/ssl + ) - if (ENABLE_PKCS11) - list(APPEND OPENSSL_SOURCES_SUBDIRS - # EC, ECDH and ECDSA are necessary for PKCS11 - ${OPENSSL_SOURCES_DIR}/crypto/ec - ${OPENSSL_SOURCES_DIR}/crypto/ecdh - ${OPENSSL_SOURCES_DIR}/crypto/ecdsa - ) - else() - add_definitions( - -DOPENSSL_NO_EC - -DOPENSSL_NO_ECDH - -DOPENSSL_NO_ECDSA - ) - endif() + if (ENABLE_PKCS11) + list(APPEND OPENSSL_SOURCES_SUBDIRS + # EC, ECDH and ECDSA are necessary for PKCS11 + ${OPENSSL_SOURCES_DIR}/crypto/ec + ${OPENSSL_SOURCES_DIR}/crypto/ecdh + ${OPENSSL_SOURCES_DIR}/crypto/ecdsa + ) + else() + add_definitions( + -DOPENSSL_NO_EC + -DOPENSSL_NO_ECDH + -DOPENSSL_NO_ECDSA + ) + endif() - foreach(d ${OPENSSL_SOURCES_SUBDIRS}) - AUX_SOURCE_DIRECTORY(${d} OPENSSL_SOURCES) - endforeach() + foreach(d ${OPENSSL_SOURCES_SUBDIRS}) + AUX_SOURCE_DIRECTORY(${d} OPENSSL_SOURCES) + endforeach() - list(REMOVE_ITEM OPENSSL_SOURCES - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_unix.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_vms.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win32.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_wince.c - ${OPENSSL_SOURCES_DIR}/crypto/armcap.c - ${OPENSSL_SOURCES_DIR}/crypto/bf/bfs.cpp - ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_rtcp.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/exp.c - ${OPENSSL_SOURCES_DIR}/crypto/conf/cnf_save.c - ${OPENSSL_SOURCES_DIR}/crypto/conf/test.c - ${OPENSSL_SOURCES_DIR}/crypto/des/des.c - ${OPENSSL_SOURCES_DIR}/crypto/des/des3s.cpp - ${OPENSSL_SOURCES_DIR}/crypto/des/des_opts.c - ${OPENSSL_SOURCES_DIR}/crypto/des/dess.cpp - ${OPENSSL_SOURCES_DIR}/crypto/des/read_pwd.c - ${OPENSSL_SOURCES_DIR}/crypto/des/speed.c - ${OPENSSL_SOURCES_DIR}/crypto/evp/e_dsa.c - ${OPENSSL_SOURCES_DIR}/crypto/evp/m_ripemd.c - ${OPENSSL_SOURCES_DIR}/crypto/lhash/lh_test.c - ${OPENSSL_SOURCES_DIR}/crypto/md5/md5s.cpp - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/bio_ber.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/pk7_enc.c - ${OPENSSL_SOURCES_DIR}/crypto/ppccap.c - ${OPENSSL_SOURCES_DIR}/crypto/rand/randtest.c - ${OPENSSL_SOURCES_DIR}/crypto/s390xcap.c - ${OPENSSL_SOURCES_DIR}/crypto/sparcv9cap.c - ${OPENSSL_SOURCES_DIR}/crypto/x509v3/tabtest.c - ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3conf.c - ${OPENSSL_SOURCES_DIR}/ssl/ssl_task.c - ${OPENSSL_SOURCES_DIR}/crypto/LPdir_nyi.c - ${OPENSSL_SOURCES_DIR}/crypto/aes/aes_x86core.c - ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_dgram.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/bntest.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/expspeed.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/exptest.c - ${OPENSSL_SOURCES_DIR}/crypto/engine/enginetest.c - ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_test.c - ${OPENSSL_SOURCES_DIR}/crypto/hmac/hmactest.c - ${OPENSSL_SOURCES_DIR}/crypto/md5/md5.c - ${OPENSSL_SOURCES_DIR}/crypto/md5/md5test.c - ${OPENSSL_SOURCES_DIR}/crypto/o_dir_test.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/dec.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/enc.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/sign.c - ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/verify.c - ${OPENSSL_SOURCES_DIR}/crypto/rsa/rsa_test.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1t.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1test.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha256t.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/sha512t.c - ${OPENSSL_SOURCES_DIR}/crypto/sha/shatest.c - ${OPENSSL_SOURCES_DIR}/crypto/srp/srptest.c + list(REMOVE_ITEM OPENSSL_SOURCES + ${OPENSSL_SOURCES_DIR}/crypto/LPdir_unix.c + ${OPENSSL_SOURCES_DIR}/crypto/LPdir_vms.c + ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win.c + ${OPENSSL_SOURCES_DIR}/crypto/LPdir_win32.c + ${OPENSSL_SOURCES_DIR}/crypto/LPdir_wince.c + ${OPENSSL_SOURCES_DIR}/crypto/armcap.c + ${OPENSSL_SOURCES_DIR}/crypto/bf/bfs.cpp + ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_rtcp.c + ${OPENSSL_SOURCES_DIR}/crypto/bn/exp.c + ${OPENSSL_SOURCES_DIR}/crypto/conf/cnf_save.c + ${OPENSSL_SOURCES_DIR}/crypto/conf/test.c + ${OPENSSL_SOURCES_DIR}/crypto/des/des.c + ${OPENSSL_SOURCES_DIR}/crypto/des/des3s.cpp + ${OPENSSL_SOURCES_DIR}/crypto/des/des_opts.c + ${OPENSSL_SOURCES_DIR}/crypto/des/dess.cpp + ${OPENSSL_SOURCES_DIR}/crypto/des/read_pwd.c + ${OPENSSL_SOURCES_DIR}/crypto/des/speed.c + ${OPENSSL_SOURCES_DIR}/crypto/evp/e_dsa.c + ${OPENSSL_SOURCES_DIR}/crypto/evp/m_ripemd.c + ${OPENSSL_SOURCES_DIR}/crypto/lhash/lh_test.c + ${OPENSSL_SOURCES_DIR}/crypto/md5/md5s.cpp + ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/bio_ber.c + ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/pk7_enc.c + ${OPENSSL_SOURCES_DIR}/crypto/ppccap.c + ${OPENSSL_SOURCES_DIR}/crypto/rand/randtest.c + ${OPENSSL_SOURCES_DIR}/crypto/s390xcap.c + ${OPENSSL_SOURCES_DIR}/crypto/sparcv9cap.c + ${OPENSSL_SOURCES_DIR}/crypto/x509v3/tabtest.c + ${OPENSSL_SOURCES_DIR}/crypto/x509v3/v3conf.c + ${OPENSSL_SOURCES_DIR}/ssl/ssl_task.c + ${OPENSSL_SOURCES_DIR}/crypto/LPdir_nyi.c + ${OPENSSL_SOURCES_DIR}/crypto/aes/aes_x86core.c + ${OPENSSL_SOURCES_DIR}/crypto/bio/bss_dgram.c + ${OPENSSL_SOURCES_DIR}/crypto/bn/bntest.c + ${OPENSSL_SOURCES_DIR}/crypto/bn/expspeed.c + ${OPENSSL_SOURCES_DIR}/crypto/bn/exptest.c + ${OPENSSL_SOURCES_DIR}/crypto/engine/enginetest.c + ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_test.c + ${OPENSSL_SOURCES_DIR}/crypto/hmac/hmactest.c + ${OPENSSL_SOURCES_DIR}/crypto/md5/md5.c + ${OPENSSL_SOURCES_DIR}/crypto/md5/md5test.c + ${OPENSSL_SOURCES_DIR}/crypto/o_dir_test.c + ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/dec.c + ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/enc.c + ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/sign.c + ${OPENSSL_SOURCES_DIR}/crypto/pkcs7/verify.c + ${OPENSSL_SOURCES_DIR}/crypto/rsa/rsa_test.c + ${OPENSSL_SOURCES_DIR}/crypto/sha/sha.c + ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1.c + ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1t.c + ${OPENSSL_SOURCES_DIR}/crypto/sha/sha1test.c + ${OPENSSL_SOURCES_DIR}/crypto/sha/sha256t.c + ${OPENSSL_SOURCES_DIR}/crypto/sha/sha512t.c + ${OPENSSL_SOURCES_DIR}/crypto/sha/shatest.c + ${OPENSSL_SOURCES_DIR}/crypto/srp/srptest.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/divtest.c - ${OPENSSL_SOURCES_DIR}/crypto/bn/bnspeed.c - ${OPENSSL_SOURCES_DIR}/crypto/des/destest.c - ${OPENSSL_SOURCES_DIR}/crypto/dh/p192.c - ${OPENSSL_SOURCES_DIR}/crypto/dh/p512.c - ${OPENSSL_SOURCES_DIR}/crypto/dh/p1024.c - ${OPENSSL_SOURCES_DIR}/crypto/des/rpw.c - ${OPENSSL_SOURCES_DIR}/ssl/ssltest.c - ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsagen.c - ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsatest.c - ${OPENSSL_SOURCES_DIR}/crypto/dh/dhtest.c - ${OPENSSL_SOURCES_DIR}/crypto/pqueue/pq_test.c - ${OPENSSL_SOURCES_DIR}/crypto/des/ncbc_enc.c + ${OPENSSL_SOURCES_DIR}/crypto/bn/divtest.c + ${OPENSSL_SOURCES_DIR}/crypto/bn/bnspeed.c + ${OPENSSL_SOURCES_DIR}/crypto/des/destest.c + ${OPENSSL_SOURCES_DIR}/crypto/dh/p192.c + ${OPENSSL_SOURCES_DIR}/crypto/dh/p512.c + ${OPENSSL_SOURCES_DIR}/crypto/dh/p1024.c + ${OPENSSL_SOURCES_DIR}/crypto/des/rpw.c + ${OPENSSL_SOURCES_DIR}/ssl/ssltest.c + ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsagen.c + ${OPENSSL_SOURCES_DIR}/crypto/dsa/dsatest.c + ${OPENSSL_SOURCES_DIR}/crypto/dh/dhtest.c + ${OPENSSL_SOURCES_DIR}/crypto/pqueue/pq_test.c + ${OPENSSL_SOURCES_DIR}/crypto/des/ncbc_enc.c - ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_extra_test.c - ${OPENSSL_SOURCES_DIR}/crypto/evp/verify_extra_test.c - ${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/constant_time_test.c - ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256_table.c + ${OPENSSL_SOURCES_DIR}/crypto/evp/evp_extra_test.c + ${OPENSSL_SOURCES_DIR}/crypto/evp/verify_extra_test.c + ${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/constant_time_test.c + ${OPENSSL_SOURCES_DIR}/crypto/ec/ecp_nistz256_table.c - ${OPENSSL_SOURCES_DIR}/ssl/heartbeat_test.c - ) + ${OPENSSL_SOURCES_DIR}/ssl/heartbeat_test.c + ) - if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") - set_source_files_properties( - ${OPENSSL_SOURCES} - PROPERTIES COMPILE_DEFINITIONS - "OPENSSL_SYSNAME_WIN32;SO_WIN32;WIN32_LEAN_AND_MEAN;L_ENDIAN") + if ("${CMAKE_SYSTEM_NAME}" STREQUAL "Windows") + set_source_files_properties( + ${OPENSSL_SOURCES} + PROPERTIES COMPILE_DEFINITIONS + "OPENSSL_SYSNAME_WIN32;SO_WIN32;WIN32_LEAN_AND_MEAN;L_ENDIAN") + endif() - elseif ("${CMAKE_SYSTEM_VERSION}" STREQUAL "LinuxStandardBase") - execute_process( - COMMAND ${PATCH_EXECUTABLE} -N ui_openssl.c -i ${ORTHANC_ROOT}/Resources/Patches/openssl-lsb.diff - WORKING_DIRECTORY ${OPENSSL_SOURCES_DIR}/crypto/ui - RESULT_VARIABLE Failure - ) + source_group(ThirdParty\\OpenSSL REGULAR_EXPRESSION ${OPENSSL_SOURCES_DIR}/.*) - if (Failure AND FirstRun) - message(FATAL_ERROR "Error while patching a file") - endif() - endif() - - source_group(ThirdParty\\OpenSSL REGULAR_EXPRESSION ${OPENSSL_SOURCES_DIR}/.*) +else() + include(FindOpenSSL) - else() - include(FindOpenSSL) + if (NOT ${OPENSSL_FOUND}) + message(FATAL_ERROR "Unable to find OpenSSL") + endif() - if (NOT ${OPENSSL_FOUND}) - message(FATAL_ERROR "Unable to find OpenSSL") - endif() - - include_directories(${OPENSSL_INCLUDE_DIR}) - link_libraries(${OPENSSL_LIBRARIES}) - endif() + include_directories(${OPENSSL_INCLUDE_DIR}) + link_libraries(${OPENSSL_LIBRARIES}) endif()
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Orthanc/Resources/CMake/UuidConfiguration.cmake Thu Jan 04 10:49:34 2018 +0100 @@ -0,0 +1,94 @@ +if (NOT ${CMAKE_SYSTEM_NAME} STREQUAL "Windows") + + if (STATIC_BUILD OR NOT USE_SYSTEM_UUID) + SET(E2FSPROGS_SOURCES_DIR ${CMAKE_BINARY_DIR}/e2fsprogs-1.43.8) + SET(E2FSPROGS_URL "http://www.orthanc-server.com/downloads/third-party/e2fsprogs-1.43.8.tar.gz") + SET(E2FSPROGS_MD5 "670b7a74a8ead5333acf21b9afc92b3c") + + DownloadPackage(${E2FSPROGS_MD5} ${E2FSPROGS_URL} "${E2FSPROGS_SOURCES_DIR}") + + include_directories( + ${E2FSPROGS_SOURCES_DIR}/lib + ) + + set(UUID_SOURCES + #${E2FSPROGS_SOURCES_DIR}/lib/uuid/tst_uuid.c + #${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_time.c + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/clear.c + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/compare.c + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/copy.c + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/gen_uuid.c + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/isnull.c + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/pack.c + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/parse.c + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/unpack.c + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/unparse.c + ) + + check_include_file("net/if.h" HAVE_NET_IF_H) + check_include_file("net/if_dl.h" HAVE_NET_IF_DL_H) + check_include_file("netinet/in.h" HAVE_NETINET_IN_H) + check_include_file("stdlib.h" HAVE_STDLIB_H) + check_include_file("sys/file.h" HAVE_SYS_FILE_H) + check_include_file("sys/ioctl.h" HAVE_SYS_IOCTL_H) + check_include_file("sys/resource.h" HAVE_SYS_RESOURCE_H) + check_include_file("sys/socket.h" HAVE_SYS_SOCKET_H) + check_include_file("sys/sockio.h" HAVE_SYS_SOCKIO_H) + check_include_file("sys/syscall.h" HAVE_SYS_SYSCALL_H) + check_include_file("sys/time.h" HAVE_SYS_TIME_H) + check_include_file("sys/un.h" HAVE_SYS_UN_H) + check_include_file("unistd.h" HAVE_UNISTD_H) + + file(WRITE ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h.cmake " +#cmakedefine HAVE_NET_IF_H \@HAVE_NET_IF_H\@ +#cmakedefine HAVE_NET_IF_DL_H \@HAVE_NET_IF_DL_H\@ +#cmakedefine HAVE_NETINET_IN_H \@HAVE_NETINET_IN_H\@ +#cmakedefine HAVE_STDLIB_H \@HAVE_STDLIB_H \@ +#cmakedefine HAVE_SYS_FILE_H \@HAVE_SYS_FILE_H\@ +#cmakedefine HAVE_SYS_IOCTL_H \@HAVE_SYS_IOCTL_H\@ +#cmakedefine HAVE_SYS_RESOURCE_H \@HAVE_SYS_RESOURCE_H\@ +#cmakedefine HAVE_SYS_SOCKET_H \@HAVE_SYS_SOCKET_H\@ +#cmakedefine HAVE_SYS_SOCKIO_H \@HAVE_SYS_SOCKIO_H\@ +#cmakedefine HAVE_SYS_SYSCALL_H \@HAVE_SYS_SYSCALL_H\@ +#cmakedefine HAVE_SYS_TIME_H \@HAVE_SYS_TIME_H\@ +#cmakedefine HAVE_SYS_UN_H \@HAVE_SYS_UN_H\@ +#cmakedefine HAVE_UNISTD_H \@HAVE_UNISTD_H\@ +") + + configure_file( + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h.cmake + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/config.h + ) + + + configure_file( + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid.h.in + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid.h + ) + + file(WRITE + ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h + "#include <stdint.h>\n") + + #configure_file( + # ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h.in + # ${E2FSPROGS_SOURCES_DIR}/lib/uuid/uuid_types.h + # ) + + source_group(ThirdParty\\uuid REGULAR_EXPRESSION ${E2FSPROGS_SOURCES_DIR}/.*) + + else() + CHECK_INCLUDE_FILE(uuid/uuid.h HAVE_UUID_H) + if (NOT HAVE_UUID_H) + message(FATAL_ERROR "Please install uuid-dev, e2fsprogs (OpenBSD) or e2fsprogs-libuuid (FreeBSD)") + endif() + + check_library_exists(uuid uuid_generate_random "" HAVE_UUID_LIB) + if (NOT HAVE_UUID_LIB) + message(FATAL_ERROR "Unable to find the uuid library") + endif() + + link_libraries(uuid) + endif() + +endif()
--- a/Resources/Orthanc/Resources/CMake/VisualStudioPrecompiledHeaders.cmake Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Resources/CMake/VisualStudioPrecompiledHeaders.cmake Thu Jan 04 10:49:34 2018 +0100 @@ -1,4 +1,4 @@ -macro(ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS PrecompiledHeaders PrecompiledSource Sources) +macro(ADD_VISUAL_STUDIO_PRECOMPILED_HEADERS PrecompiledHeaders PrecompiledSource Sources Target) get_filename_component(PrecompiledBasename ${PrecompiledHeaders} NAME_WE) set(PrecompiledBinary "${PrecompiledBasename}_$(ConfigurationName).pch") @@ -10,5 +10,5 @@ PROPERTIES COMPILE_FLAGS "/Yu\"${PrecompiledHeaders}\" /FI\"${PrecompiledHeaders}\" /Fp\"${PrecompiledBinary}\"" OBJECT_DEPENDS "${PrecompiledBinary}") - list(APPEND ${Sources} ${PrecompiledSource}) + set(${Target} ${PrecompiledSource}) endmacro()
--- a/Resources/Orthanc/Resources/EmbedResources.py Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Resources/EmbedResources.py Thu Jan 04 10:49:34 2018 +0100 @@ -3,7 +3,7 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017 Osimis, Belgium +# Copyright (C) 2017-2018 Osimis S.A., Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Orthanc/Resources/Patches/boost-1.65.1-linux-standard-base.patch Thu Jan 04 10:49:34 2018 +0100 @@ -0,0 +1,12 @@ +diff -urEb boost_1_65_1.orig/boost/move/adl_move_swap.hpp boost_1_65_1/boost/move/adl_move_swap.hpp +--- boost_1_65_1.orig/boost/move/adl_move_swap.hpp 2017-11-08 17:43:20.000000000 +0100 ++++ boost_1_65_1/boost/move/adl_move_swap.hpp 2018-01-02 15:34:48.829052917 +0100 +@@ -28,6 +28,8 @@ + //Try to avoid including <algorithm>, as it's quite big + #if defined(_MSC_VER) && defined(BOOST_DINKUMWARE_STDLIB) + #include <utility> //Dinkum libraries define std::swap in utility which is lighter than algorithm ++#elif defined(__LSB_VERSION__) ++# include <utility> + #elif defined(BOOST_GNU_STDLIB) + //For non-GCC compilers, where GNUC version is not very reliable, or old GCC versions + //use the good old stl_algobase header, which is quite lightweight
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Resources/Orthanc/Resources/Patches/curl-7.57.0-cmake.patch Thu Jan 04 10:49:34 2018 +0100 @@ -0,0 +1,12 @@ +diff -urEb curl-7.57.0.orig/CMake/Macros.cmake curl-7.57.0/CMake/Macros.cmake +--- curl-7.57.0.orig/CMake/Macros.cmake 2017-11-09 23:40:36.000000000 +0100 ++++ curl-7.57.0/CMake/Macros.cmake 2018-01-03 10:39:15.589520034 +0100 +@@ -38,7 +38,7 @@ + message(STATUS "Performing Curl Test ${CURL_TEST}") + try_compile(${CURL_TEST} + ${CMAKE_BINARY_DIR} +- ${CMAKE_CURRENT_SOURCE_DIR}/CMake/CurlTests.c ++ ${CURL_SOURCES_DIR}/CMake/CurlTests.c + CMAKE_FLAGS -DCOMPILE_DEFINITIONS:STRING=${MACRO_CHECK_FUNCTION_DEFINITIONS} + "${CURL_TEST_ADD_LIBRARIES}" + OUTPUT_VARIABLE OUTPUT)
--- a/Resources/Orthanc/Resources/WindowsResources.py Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/Orthanc/Resources/WindowsResources.py Thu Jan 04 10:49:34 2018 +0100 @@ -3,7 +3,7 @@ # Orthanc - A Lightweight, RESTful DICOM Store # Copyright (C) 2012-2016 Sebastien Jodogne, Medical Physics # Department, University Hospital of Liege, Belgium -# Copyright (C) 2017 Osimis, Belgium +# Copyright (C) 2017-2018 Osimis S.A., Belgium # # This program is free software: you can redistribute it and/or # modify it under the terms of the GNU General Public License as
--- a/Resources/SyncOrthancFolder.py Tue Jan 02 10:01:35 2018 +0100 +++ b/Resources/SyncOrthancFolder.py Thu Jan 04 10:49:34 2018 +0100 @@ -27,6 +27,10 @@ 'Core/DicomFormat/DicomTag.h', 'Core/DicomFormat/DicomValue.cpp', 'Core/DicomFormat/DicomValue.h', + 'Core/DicomParsing/FromDcmtkBridge.cpp', + 'Core/DicomParsing/FromDcmtkBridge.h', + 'Core/DicomParsing/ToDcmtkBridge.cpp', + 'Core/DicomParsing/ToDcmtkBridge.h', 'Core/Endianness.h', 'Core/EnumerationDictionary.h', 'Core/Enumerations.cpp', @@ -75,26 +79,16 @@ 'Core/Toolbox.h', 'Core/WebServiceParameters.cpp', 'Core/WebServiceParameters.h', - 'OrthancServer/FromDcmtkBridge.cpp', - 'OrthancServer/FromDcmtkBridge.h', 'OrthancServer/PrecompiledHeadersServer.h', - 'OrthancServer/ServerEnumerations.cpp', - 'OrthancServer/ServerEnumerations.h', - 'OrthancServer/ToDcmtkBridge.cpp', - 'OrthancServer/ToDcmtkBridge.h', 'Plugins/Engine/SharedLibrary.cpp', 'Plugins/Engine/SharedLibrary.h', - 'Plugins/Samples/Common/ExportedSymbols.list', - 'Plugins/Samples/Common/OrthancPluginCppWrapper.cpp', - 'Plugins/Samples/Common/OrthancPluginCppWrapper.h', - 'Plugins/Samples/Common/OrthancPluginException.h', - 'Plugins/Samples/Common/VersionScript.map', 'Plugins/Samples/Common/DicomDatasetReader.cpp', 'Plugins/Samples/Common/DicomDatasetReader.h', 'Plugins/Samples/Common/DicomPath.cpp', 'Plugins/Samples/Common/DicomPath.h', 'Plugins/Samples/Common/DicomTag.cpp', 'Plugins/Samples/Common/DicomTag.h', + 'Plugins/Samples/Common/ExportedSymbols.list', 'Plugins/Samples/Common/FullOrthancDataset.cpp', 'Plugins/Samples/Common/FullOrthancDataset.h', 'Plugins/Samples/Common/IDicomDataset.h', @@ -104,8 +98,12 @@ 'Plugins/Samples/Common/OrthancHttpConnection.h', 'Plugins/Samples/Common/OrthancPluginConnection.cpp', 'Plugins/Samples/Common/OrthancPluginConnection.h', + 'Plugins/Samples/Common/OrthancPluginCppWrapper.cpp', + 'Plugins/Samples/Common/OrthancPluginCppWrapper.h', + 'Plugins/Samples/Common/OrthancPluginException.h', 'Plugins/Samples/Common/SimplifiedOrthancDataset.cpp', 'Plugins/Samples/Common/SimplifiedOrthancDataset.h', + 'Plugins/Samples/Common/VersionScript.map', 'Resources/CMake/AutoGeneratedCode.cmake', 'Resources/CMake/BoostConfiguration.cmake', 'Resources/CMake/Compiler.cmake', @@ -117,12 +115,15 @@ 'Resources/CMake/LibJpegConfiguration.cmake', 'Resources/CMake/LibPngConfiguration.cmake', 'Resources/CMake/OpenSslConfiguration.cmake', + 'Resources/CMake/UuidConfiguration.cmake', 'Resources/CMake/VisualStudioPrecompiledHeaders.cmake', 'Resources/CMake/ZlibConfiguration.cmake', 'Resources/EmbedResources.py', 'Resources/MinGW-W64-Toolchain32.cmake', 'Resources/MinGW-W64-Toolchain64.cmake', 'Resources/MinGWToolchain.cmake', + 'Resources/Patches/boost-1.65.1-linux-standard-base.patch', + 'Resources/Patches/curl-7.57.0-cmake.patch', 'Resources/Patches/dcmtk-3.6.0-dulparse-vulnerability.patch', 'Resources/Patches/dcmtk-3.6.0-mingw64.patch', 'Resources/Patches/dcmtk-3.6.0-speed.patch',
--- a/ViewerPlugin/CMakeLists.txt Tue Jan 02 10:01:35 2018 +0100 +++ b/ViewerPlugin/CMakeLists.txt Thu Jan 04 10:49:34 2018 +0100 @@ -16,8 +16,9 @@ SET(USE_SYSTEM_LIBJPEG ON CACHE BOOL "Use the system version of libjpeg") SET(USE_SYSTEM_LIBPNG ON CACHE BOOL "Use the system version of libpng") SET(USE_SYSTEM_OPENJPEG ON CACHE BOOL "Use the system version of OpenJpeg") +SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK") SET(USE_SYSTEM_ZLIB ON CACHE BOOL "Use the system version of ZLib") -SET(USE_SYSTEM_ORTHANC_SDK ON CACHE BOOL "Use the system version of the Orthanc plugin SDK") +set(USE_SYSTEM_UUID ON CACHE BOOL "Use the system version of the uuid library from e2fsprogs") # Parameters related to OpenLayers SET(USE_SYSTEM_OPENLAYERS OFF CACHE BOOL "Use the system version of OpenLayers") @@ -35,12 +36,13 @@ SET(USE_OPENJPEG_JP2 ON) SET(ENABLE_LOCALE OFF) # Disable support for locales (notably in Boost) +include(CheckIncludeFile) +include(CheckIncludeFileCXX) include(CheckIncludeFiles) -include(CheckIncludeFileCXX) include(CheckLibraryExists) -include(FindPythonInterp) +include(CheckSymbolExists) include(FindPkgConfig) -include(CheckSymbolExists) +include(FindPythonInterp) include(${ORTHANC_ROOT}/Resources/CMake/Compiler.cmake) include(${ORTHANC_ROOT}/Resources/CMake/AutoGeneratedCode.cmake) @@ -52,6 +54,7 @@ include(${ORTHANC_ROOT}/Resources/CMake/JsonCppConfiguration.cmake) include(${ORTHANC_ROOT}/Resources/CMake/LibJpegConfiguration.cmake) include(${ORTHANC_ROOT}/Resources/CMake/LibPngConfiguration.cmake) +include(${ORTHANC_ROOT}/Resources/CMake/UuidConfiguration.cmake) include(${ORTHANC_ROOT}/Resources/CMake/ZlibConfiguration.cmake) # Include components specific to WSI @@ -59,16 +62,19 @@ include(${ORTHANC_WSI_DIR}/Resources/CMake/OpenJpegConfiguration.cmake) add_definitions( + -DHAS_ORTHANC_EXCEPTION=1 + -DORTHANC_DEFAULT_DICOM_ENCODING=Encoding_Latin1 -DORTHANC_ENABLE_BASE64=0 -DORTHANC_ENABLE_CURL=0 -DORTHANC_ENABLE_DCMTK=0 + -DORTHANC_ENABLE_JPEG=1 -DORTHANC_ENABLE_LOCALE=0 -DORTHANC_ENABLE_LOGGING=1 -DORTHANC_ENABLE_LOGGING_PLUGIN=1 -DORTHANC_ENABLE_MD5=0 + -DORTHANC_ENABLE_PNG=1 -DORTHANC_ENABLE_PUGIXML=0 -DORTHANC_SANDBOXED=0 - -DHAS_ORTHANC_EXCEPTION=1 ) @@ -229,10 +235,11 @@ # Mandatory components ${BOOST_SOURCES} ${JSONCPP_SOURCES} - ${ZLIB_SOURCES} + ${LIBJPEG_SOURCES} ${LIBPNG_SOURCES} - ${LIBJPEG_SOURCES} ${OPENJPEG_SOURCES} + ${UUID_SOURCES} + ${ZLIB_SOURCES} ) message("Setting the version of the library to ${ORTHANC_WSI_VERSION}")