changeset 1884:7bef560b9782 dcmtk-3.6.1

integration mainline->dcmtk-3.6.1
author Sebastien Jodogne <s.jodogne@gmail.com>
date Fri, 11 Dec 2015 09:45:07 +0100
parents 950745f3f48b (current diff) 71356f41ec2f (diff)
children fb6dd1570d4d
files Resources/CMake/DcmtkConfiguration.cmake
diffstat 8 files changed, 189 insertions(+), 40 deletions(-) [+]
line wrap: on
line diff
--- a/Core/HttpServer/HttpOutput.cpp	Mon Dec 07 10:39:23 2015 +0100
+++ b/Core/HttpServer/HttpOutput.cpp	Fri Dec 11 09:45:07 2015 +0100
@@ -449,12 +449,59 @@
   }
 
 
-  void HttpOutput::StateMachine::SendMultipartItem(const void* item, size_t length)
+  void HttpOutput::StateMachine::SendMultipartItem(const void* item, 
+                                                   size_t length,
+                                                   const std::map<std::string, std::string>& headers)
   {
+    if (state_ != State_WritingMultipart)
+    {
+      throw OrthancException(ErrorCode_BadSequenceOfCalls);
+    }
+
     std::string header = "--" + multipartBoundary_ + "\r\n";
-    header += "Content-Type: " + multipartContentType_ + "\r\n";
-    header += "Content-Length: " + boost::lexical_cast<std::string>(length) + "\r\n";
-    header += "MIME-Version: 1.0\r\n\r\n";
+
+    bool hasContentType = false;
+    bool hasContentLength = false;
+    bool hasMimeVersion = false;
+
+    for (std::map<std::string, std::string>::const_iterator
+           it = headers.begin(); it != headers.end(); ++it)
+    {
+      header += it->first + ": " + it->second + "\r\n";
+
+      std::string tmp;
+      Toolbox::ToLowerCase(tmp, it->first);
+
+      if (tmp == "content-type")
+      {
+        hasContentType = true;
+      }
+
+      if (tmp == "content-length")
+      {
+        hasContentLength = true;
+      }
+
+      if (tmp == "mime-version")
+      {
+        hasMimeVersion = true;
+      }
+    }
+
+    if (!hasContentType)
+    {
+      header += "Content-Type: " + multipartContentType_ + "\r\n";
+    }
+
+    if (!hasContentLength)
+    {
+      header += "Content-Length: " + boost::lexical_cast<std::string>(length) + "\r\n";
+    }
+
+    if (!hasMimeVersion)
+    {
+      header += "MIME-Version: 1.0\r\n\r\n";
+    }
 
     stream_.Send(false, header.c_str(), header.size());
 
@@ -463,7 +510,7 @@
       stream_.Send(false, item, length);
     }
 
-    stream_.Send(false, "\r\n", 1);
+    stream_.Send(false, "\r\n", 2);    
   }
 
 
@@ -489,19 +536,6 @@
   }
 
 
-  void HttpOutput::SendMultipartItem(const std::string& item)
-  {
-    if (item.size() > 0)
-    {
-      stateMachine_.SendMultipartItem(item.c_str(), item.size());
-    }
-    else
-    {
-      stateMachine_.SendMultipartItem(NULL, 0);
-    }
-  }
-
-
   void HttpOutput::Answer(IHttpStreamAnswer& stream)
   {
     HttpCompression compression = stream.SetupHttpCompression(isGzipAllowed_, isDeflateAllowed_);
--- a/Core/HttpServer/HttpOutput.h	Mon Dec 07 10:39:23 2015 +0100
+++ b/Core/HttpServer/HttpOutput.h	Fri Dec 11 09:45:07 2015 +0100
@@ -99,7 +99,9 @@
       void StartMultipart(const std::string& subType,
                           const std::string& contentType);
 
-      void SendMultipartItem(const void* item, size_t length);
+      void SendMultipartItem(const void* item, 
+                             size_t length,
+                             const std::map<std::string, std::string>& headers);
 
       void CloseMultipart();
 
@@ -202,11 +204,11 @@
       stateMachine_.StartMultipart(subType, contentType);
     }
 
-    void SendMultipartItem(const std::string& item);
-
-    void SendMultipartItem(const void* item, size_t size)
+    void SendMultipartItem(const void* item, 
+                           size_t size,
+                           const std::map<std::string, std::string>& headers)
     {
-      stateMachine_.SendMultipartItem(item, size);
+      stateMachine_.SendMultipartItem(item, size, headers);
     }
 
     void CloseMultipart()
--- a/NEWS	Mon Dec 07 10:39:23 2015 +0100
+++ b/NEWS	Fri Dec 11 09:45:07 2015 +0100
@@ -1,10 +1,19 @@
 Pending changes in the mainline
 ===============================
 
+
+* New function in plugin SDK: "OrthancPluginSendMultipartItem2()"
+
+
+Version 0.9.6 (2015/12/08)
+==========================
+
+* Promiscuous mode (accept unknown SOP class UID) is now turned off by default
+* Fix serialization of DICOM buffers that might contain garbage trailing
 * Fix modality worklists server if some fields are null
 * More tolerant "/series/.../ordered-slices" with broken series
-* Promiscuous mode is now turned off by default
 * Improved logging information if upgrade fails
+* Fix formatting of multipart HTTP answers (bis)
 
 
 Version 0.9.5 (2015/12/02)
--- a/OrthancServer/FromDcmtkBridge.cpp	Mon Dec 07 10:39:23 2015 +0100
+++ b/OrthancServer/FromDcmtkBridge.cpp	Fri Dec 11 09:45:07 2015 +0100
@@ -1040,9 +1040,12 @@
     ff.removeInvalidGroups();
 
     // Create a memory buffer with the proper size
-    uint32_t s = ff.calcElementLength(xfer, encodingType);
-    buffer.resize(s);
-    DcmOutputBufferStream ob(&buffer[0], s);
+    {
+      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();
@@ -1051,13 +1054,23 @@
                              /*opt_paddingType*/ EPD_withoutPadding);
     ff.transferEnd();
 
-    // Handle errors
     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;
     }
--- a/Plugins/Engine/OrthancPlugins.cpp	Mon Dec 07 10:39:23 2015 +0100
+++ b/Plugins/Engine/OrthancPlugins.cpp	Fri Dec 11 09:45:07 2015 +0100
@@ -1574,7 +1574,39 @@
 
     *(p.target) = ReturnImage(result);
   }
-        
+
+
+  void OrthancPlugins::ApplySendMultipartItem(const void* parameters)
+  {
+    // An exception might be raised in this function if the
+    // connection was closed by the HTTP client.
+    const _OrthancPluginAnswerBuffer& p =
+      *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters);
+
+    HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output);
+
+    std::map<std::string, std::string> headers;  // No custom headers
+    output->SendMultipartItem(p.answer, p.answerSize, headers);
+  }
+
+
+  void OrthancPlugins::ApplySendMultipartItem2(const void* parameters)
+  {
+    // An exception might be raised in this function if the
+    // connection was closed by the HTTP client.
+    const _OrthancPluginSendMultipartItem2& p =
+      *reinterpret_cast<const _OrthancPluginSendMultipartItem2*>(parameters);
+    HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output);
+    
+    std::map<std::string, std::string> headers;
+    for (uint32_t i = 0; i < p.headersCount; i++)
+    {
+      headers[p.headersKeys[i]] = p.headersValues[i];
+    }
+    
+    output->SendMultipartItem(p.answer, p.answerSize, headers);
+  }
+      
 
   void OrthancPlugins::DatabaseAnswer(const void* parameters)
   {
@@ -1969,15 +2001,12 @@
       }
 
       case _OrthancPluginService_SendMultipartItem:
-      {
-        // An exception might be raised in this function if the
-        // connection was closed by the HTTP client.
-        const _OrthancPluginAnswerBuffer& p =
-          *reinterpret_cast<const _OrthancPluginAnswerBuffer*>(parameters);
-        HttpOutput* output = reinterpret_cast<HttpOutput*>(p.output);
-        output->SendMultipartItem(p.answer, p.answerSize);
+        ApplySendMultipartItem(parameters);
         return true;
-      }
+
+      case _OrthancPluginService_SendMultipartItem2:
+        ApplySendMultipartItem2(parameters);
+        return true;
 
       case _OrthancPluginService_ReadFile:
       {
--- a/Plugins/Engine/OrthancPlugins.h	Mon Dec 07 10:39:23 2015 +0100
+++ b/Plugins/Engine/OrthancPlugins.h	Fri Dec 11 09:45:07 2015 +0100
@@ -152,6 +152,10 @@
 
     void ApplyLookupDictionary(const void* parameters);
 
+    void ApplySendMultipartItem(const void* parameters);
+
+    void ApplySendMultipartItem2(const void* parameters);
+
     void ComputeHash(_OrthancPluginService service,
                      const void* parameters);
 
--- a/Plugins/Include/orthanc/OrthancCPlugin.h	Mon Dec 07 10:39:23 2015 +0100
+++ b/Plugins/Include/orthanc/OrthancCPlugin.h	Fri Dec 11 09:45:07 2015 +0100
@@ -114,7 +114,7 @@
 
 #define ORTHANC_PLUGINS_MINIMAL_MAJOR_NUMBER     0
 #define ORTHANC_PLUGINS_MINIMAL_MINOR_NUMBER     9
-#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  5
+#define ORTHANC_PLUGINS_MINIMAL_REVISION_NUMBER  7
 
 
 
@@ -424,6 +424,7 @@
     _OrthancPluginService_SendMultipartItem = 2009,
     _OrthancPluginService_SendHttpStatus = 2010,
     _OrthancPluginService_CompressAndAnswerImage = 2011,
+    _OrthancPluginService_SendMultipartItem2 = 2012,
 
     /* Access to the Orthanc database and API */
     _OrthancPluginService_GetDicomForInstance = 3000,
@@ -2719,7 +2720,7 @@
    * @param subType The sub-type of the multipart answer ("mixed" or "related").
    * @param contentType The MIME type of the items in the multipart answer.
    * @return 0 if success, or the error code if failure.
-   * @see OrthancPluginSendMultipartItem()
+   * @see OrthancPluginSendMultipartItem(), OrthancPluginSendMultipartItem2()
    * @ingroup REST
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginStartMultipartAnswer(
@@ -2748,6 +2749,7 @@
    * @param answerSize Number of bytes of the item.
    * @return 0 if success, or the error code if failure (this notably happens
    * if the connection is closed by the client).
+   * @see OrthancPluginSendMultipartItem2()
    * @ingroup REST
    **/
   ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendMultipartItem(
@@ -4677,6 +4679,58 @@
   }
 
 
+
+  typedef struct
+  {
+    OrthancPluginRestOutput* output;
+    const char*              answer;
+    uint32_t                 answerSize;
+    uint32_t                 headersCount;
+    const char* const*       headersKeys;
+    const char* const*       headersValues;
+  } _OrthancPluginSendMultipartItem2;
+
+  /**
+   * @brief Send an item as a part of some HTTP multipart answer, with custom headers.
+   *
+   * This function sends an item as a part of some HTTP multipart
+   * answer that was initiated by OrthancPluginStartMultipartAnswer(). In addition to
+   * OrthancPluginSendMultipartItem(), this function will set HTTP header associated
+   * with the item.
+   * 
+   * @param context The Orthanc plugin context, as received by OrthancPluginInitialize().
+   * @param output The HTTP connection to the client application.
+   * @param answer Pointer to the memory buffer containing the item.
+   * @param answerSize Number of bytes of the item.
+   * @param headersCount The number of HTTP headers.
+   * @param headersKeys Array containing the keys of the HTTP headers.
+   * @param headersValues Array containing the values of the HTTP headers.
+   * @return 0 if success, or the error code if failure (this notably happens
+   * if the connection is closed by the client).
+   * @see OrthancPluginSendMultipartItem()
+   * @ingroup REST
+   **/
+  ORTHANC_PLUGIN_INLINE OrthancPluginErrorCode OrthancPluginSendMultipartItem2(
+    OrthancPluginContext*    context,
+    OrthancPluginRestOutput* output,
+    const char*              answer,
+    uint32_t                 answerSize,
+    uint32_t                 headersCount,
+    const char* const*       headersKeys,
+    const char* const*       headersValues)
+  {
+    _OrthancPluginSendMultipartItem2 params;
+    params.output = output;
+    params.answer = answer;
+    params.answerSize = answerSize;
+    params.headersCount = headersCount;
+    params.headersKeys = headersKeys;
+    params.headersValues = headersValues;    
+
+    return context->InvokeService(context, _OrthancPluginService_SendMultipartItem2, &params);
+  }
+
+
 #ifdef  __cplusplus
 }
 #endif
--- a/Resources/CMake/DcmtkConfiguration.cmake	Mon Dec 07 10:39:23 2015 +0100
+++ b/Resources/CMake/DcmtkConfiguration.cmake	Fri Dec 11 09:45:07 2015 +0100
@@ -179,7 +179,7 @@
   elseif (EXISTS "${DCMTK_DIR}/config/osconfig.h")  # This is for Arch Linux
     set(DCMTK_CONFIGURATION_FILE "${DCMTK_DIR}/config/osconfig.h")
   else()
-    message(FATAL_ERROR "Please install libdcmtk1-dev")
+    message(FATAL_ERROR "Please install libdcmtk*-dev")
   endif()
 
   # Autodetection of the version of DCMTK
@@ -208,8 +208,12 @@
   if (DCMTK_DICTIONARY_DIR STREQUAL "")
     find_path(DCMTK_DICTIONARY_DIR_AUTO dicom.dic
       /usr/share/dcmtk
+      /usr/share/libdcmtk1
       /usr/share/libdcmtk2
+      /usr/share/libdcmtk3
       /usr/share/libdcmtk4
+      /usr/share/libdcmtk5
+      /usr/share/libdcmtk6
       /usr/local/share/dcmtk
       )