changeset 7023:cb751bdccb15

support of big endian architectures in DICOMweb
author Sebastien Jodogne <s.jodogne@gmail.com>
date Wed, 08 Jul 2026 10:17:35 +0200
parents 91b3be9a243a
children a412fcd67ae6
files OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp OrthancFramework/Sources/Toolbox.cpp OrthancFramework/Sources/Toolbox.h OrthancFramework/UnitTestsSources/DicomMapTests.cpp OrthancFramework/UnitTestsSources/ToolboxTests.cpp
diffstat 5 files changed, 133 insertions(+), 2 deletions(-) [+]
line wrap: on
line diff
--- a/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp	Tue Jul 07 15:51:59 2026 +0200
+++ b/OrthancFramework/Sources/DicomParsing/DicomWebJsonVisitor.cpp	Wed Jul 08 10:17:35 2026 +0200
@@ -417,6 +417,8 @@
                                           const std::string& bulkDataUri,
                                           const std::vector<SourceType>& values)
   {
+    static const Endianness endianness = Toolbox::DetectEndianness();
+
     switch (mode)
     {
       case DicomWebJsonVisitor::BinaryMode_Ignore:
@@ -438,14 +440,17 @@
 
           if (!raw.empty())
           {
-            assert(Toolbox::DetectEndianness() == Endianness_Little);  // TODO - Add support for big endian
-
             MemoryType *p = reinterpret_cast<MemoryType*>(&raw[0]);
 
             for (size_t i = 0; i < values.size(); i++, p++)
             {
               *p = static_cast<MemoryType>(values[i]);
             }
+
+            if (endianness == Endianness_Big)
+            {
+              Toolbox::SwapEndianness(raw, sizeof(MemoryType));
+            }
           }
 
           std::string base64;
--- a/OrthancFramework/Sources/Toolbox.cpp	Tue Jul 07 15:51:59 2026 +0200
+++ b/OrthancFramework/Sources/Toolbox.cpp	Wed Jul 08 10:17:35 2026 +0200
@@ -313,6 +313,8 @@
     pimpl_->md5_.get_digest(digest);
 
     target.resize(32);
+
+#      if BOOST_ENDIAN_LITTLE_BYTE
     sprintf(&target[0], "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
             (digest[0] >> 0) & 0xFF, 
             (digest[0] >> 8) & 0xFF,
@@ -330,6 +332,25 @@
             (digest[3] >> 8) & 0xFF,
             (digest[3] >> 16) & 0xFF,
             (digest[3] >> 24) & 0xFF);
+#      else
+    sprintf(&target[0], "%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x",
+            (digest[0] >> 24) & 0xFF,
+            (digest[0] >> 16) & 0xFF,
+            (digest[0] >> 8) & 0xFF,
+            (digest[0] >> 0) & 0xFF,
+            (digest[1] >> 24) & 0xFF,
+            (digest[1] >> 16) & 0xFF,
+            (digest[1] >> 8) & 0xFF,
+            (digest[1] >> 0) & 0xFF,
+            (digest[2] >> 24) & 0xFF,
+            (digest[2] >> 16) & 0xFF,
+            (digest[2] >> 8) & 0xFF,
+            (digest[2] >> 0) & 0xFF,
+            (digest[3] >> 24) & 0xFF,
+            (digest[3] >> 16) & 0xFF,
+            (digest[3] >> 8) & 0xFF,
+            (digest[3] >> 0) & 0xFF);
+#      endif
 
 #    endif //BOOST_VERSION >= 108600
   }
@@ -3315,6 +3336,47 @@
       throw OrthancException(ErrorCode_ParameterOutOfRange, "Not a valid version: " + std::string(version));
     }
   }
+
+
+  void Toolbox::SwapEndianness(void* data,
+                               size_t dataSize,
+                               size_t itemSize)
+  {
+    if (itemSize == 0 ||
+        dataSize % itemSize != 0)
+    {
+      throw OrthancException(ErrorCode_ParameterOutOfRange);
+    }
+
+    if (itemSize != 1)
+    {
+      uint8_t* p = reinterpret_cast<uint8_t*>(data);
+      const size_t count = dataSize / itemSize;
+
+      for (size_t i = 0; i < count; i++)
+      {
+        for (size_t b1 = 0; b1 < itemSize / 2; b1++)
+        {
+          size_t b2 = itemSize - 1 - b1;
+          uint8_t tmp = p[b1];
+          p[b1] = p[b2];
+          p[b2] = tmp;
+        }
+
+        p += itemSize;
+      }
+    }
+  }
+
+
+  void Toolbox::SwapEndianness(std::string& buffer,
+                               size_t itemSize)
+  {
+    if (!buffer.empty())
+    {
+      SwapEndianness(&buffer[0], buffer.size(), itemSize);
+    }
+  }
 }
 
 
--- a/OrthancFramework/Sources/Toolbox.h	Tue Jul 07 15:51:59 2026 +0200
+++ b/OrthancFramework/Sources/Toolbox.h	Wed Jul 08 10:17:35 2026 +0200
@@ -432,6 +432,13 @@
                                unsigned int major,
                                unsigned int minor,
                                unsigned int revision);
+
+    static void SwapEndianness(void* data,
+                               size_t dataSize,
+                               size_t itemSize);
+
+    static void SwapEndianness(std::string& buffer,
+                               size_t itemSize);
   };
 }
 
--- a/OrthancFramework/UnitTestsSources/DicomMapTests.cpp	Tue Jul 07 15:51:59 2026 +0200
+++ b/OrthancFramework/UnitTestsSources/DicomMapTests.cpp	Wed Jul 08 10:17:35 2026 +0200
@@ -1372,6 +1372,13 @@
     Toolbox::DecodeBase64(decoded, result["00660041"]["InlineBinary"].asString());
     ASSERT_EQ(3 * sizeof(uint16_t), decoded.size());
 
+    if (Toolbox::DetectEndianness() == Endianness_Big)
+    {
+      std::swap(decoded[0], decoded[1]);
+      std::swap(decoded[2], decoded[3]);
+      std::swap(decoded[4], decoded[5]);
+    }
+
     uint16_t f0, f1, f2;
     memcpy(&f0, decoded.c_str(), sizeof(uint16_t));
     memcpy(&f1, decoded.c_str() + sizeof(uint16_t), sizeof(uint16_t));
@@ -1400,6 +1407,11 @@
     Toolbox::DecodeBase64(decoded, result["00660041"]["InlineBinary"].asString());
     ASSERT_EQ(3 * sizeof(uint32_t), decoded.size());
 
+    if (Toolbox::DetectEndianness() == Endianness_Big)
+    {
+      Toolbox::SwapEndianness(decoded, sizeof(uint32_t));
+    }
+
     uint32_t f0, f1, f2;
     memcpy(&f0, decoded.c_str(), sizeof(uint32_t));
     memcpy(&f1, decoded.c_str() + sizeof(uint32_t), sizeof(uint32_t));
@@ -1429,6 +1441,11 @@
     Toolbox::DecodeBase64(decoded, result["00660041"]["InlineBinary"].asString());
     ASSERT_EQ(3 * sizeof(uint64_t), decoded.size());
 
+    if (Toolbox::DetectEndianness() == Endianness_Big)
+    {
+      Toolbox::SwapEndianness(decoded, sizeof(uint64_t));
+    }
+
     uint64_t f0, f1, f2;
     memcpy(&f0, decoded.c_str(), sizeof(uint64_t));
     memcpy(&f1, decoded.c_str() + sizeof(uint64_t), sizeof(uint64_t));
@@ -1584,6 +1601,11 @@
     Toolbox::DecodeBase64(decoded, result["00660027"]["InlineBinary"].asString());
     ASSERT_EQ(2 * sizeof(float), decoded.size());
 
+    if (Toolbox::DetectEndianness() == Endianness_Big)
+    {
+      Toolbox::SwapEndianness(decoded, sizeof(float));
+    }
+
     float f0, f1;
     memcpy(&f0, decoded.c_str(), sizeof(float));
     memcpy(&f1, decoded.c_str() + sizeof(float), sizeof(float));
@@ -1610,6 +1632,11 @@
     Toolbox::DecodeBase64(decoded, result["00660027"]["InlineBinary"].asString());
     ASSERT_EQ(2 * sizeof(double), decoded.size());
 
+    if (Toolbox::DetectEndianness() == Endianness_Big)
+    {
+      Toolbox::SwapEndianness(decoded, sizeof(double));
+    }
+
     double f0, f1;
     memcpy(&f0, decoded.c_str(), sizeof(double));
     memcpy(&f1, decoded.c_str() + sizeof(double), sizeof(double));
--- a/OrthancFramework/UnitTestsSources/ToolboxTests.cpp	Tue Jul 07 15:51:59 2026 +0200
+++ b/OrthancFramework/UnitTestsSources/ToolboxTests.cpp	Wed Jul 08 10:17:35 2026 +0200
@@ -499,3 +499,33 @@
   ASSERT_EQ(8, sizeof(static_cast<int32_t>(16 * 1024 * 1024) * KILOBYTE));
   ASSERT_EQ(8, sizeof(KILOBYTE * static_cast<int32_t>(16 * 1024 * 1024)));
 }
+
+
+TEST(Toolbox, SwapEndianness)
+{
+  const std::string s = "abcdefgh";
+
+  {
+    std::string t = s;
+    Toolbox::SwapEndianness(t, 1);
+    ASSERT_EQ("abcdefgh", t);
+  }
+
+  {
+    std::string t = s;
+    Toolbox::SwapEndianness(t, 2);
+    ASSERT_EQ("badcfehg", t);
+  }
+
+  {
+    std::string t = s;
+    Toolbox::SwapEndianness(t, 4);
+    ASSERT_EQ("dcbahgfe", t);
+  }
+
+  {
+    std::string t = s;
+    Toolbox::SwapEndianness(t, 8);
+    ASSERT_EQ("hgfedcba", t);
+  }
+}