Sophie

Sophie

distrib > Mageia > 9 > x86_64 > by-pkgid > 47341169aa70776ef5d2d5f8f6e86b73 > files > 4

dcmtk-3.6.7-4.1.mga9.src.rpm

From af4672659ef883f19c60dd16eedc8875b3bad93a Mon Sep 17 00:00:00 2001
From: Marco Eichelberg <dicom@offis.de>
Date: Mon, 15 Apr 2024 12:19:33 +0200
Subject: Fixed unchecked typecasts and fixed LUT handling.
Bug-Debian: https://bugs.debian.org/1070207
Forwarded: not-needed

This commit adds further fixes for unchecked typecasts of DcmItem::search()
results (see description of previous commit). Furthermore, this commit
specifically addresses the handling of look-up tables (LUTs) in module
dcmpstat, where attribute (0028,3006) LUTData may use either US or OW
value representation, and (0028,3002) LUTDescriptor may be either US or SS.
The code should now properly handle all permitted value representations.
LUTData is now always written as OW in order to avoid the 64k size limit
for US in explicit VR encoding.

Thanks to Martin Zeiser from the Cisco Talos team
<vulndiscovery@external.cisco.com> for the bug report (TALOS-2024-1957).

Together with the previous commit, this closes DCMTK issue #1120.
---
 dcmpstat/libsrc/dcmpstat.cc | 40 ++++++++++++++++-------
 dcmpstat/libsrc/dvpspl.cc   | 34 ++++++++++++++------
 dcmpstat/libsrc/dvpssv.cc   | 34 ++++++++++++++------
 dcmpstat/libsrc/dvpssvl.cc  | 29 ++++++++++-------
 dcmpstat/libsrc/dvpstat.cc  | 63 +++++++++++++++++--------------------
 dcmpstat/libsrc/dvpsvl.cc   | 19 +++++++++--
 6 files changed, 140 insertions(+), 79 deletions(-)

--- a/dcmpstat/libsrc/dcmpstat.cc
+++ b/dcmpstat/libsrc/dcmpstat.cc
@@ -384,12 +384,16 @@
       {
          item = seq->getItem(0);
          stack.clear();
-         // LUTDescriptor can be US or SS. For now we only handle US.
+
+         // LUTDescriptor can be US or SS
          if ((EC_Normal == item->search((DcmTagKey &)modalityLUTDescriptor.getTag(),
-           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US))
+           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
          {
-           modalityLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+           // We explicitly use DcmElement::operator=(), which works for US and SS
+           DcmElement *mLUTDescriptor = &modalityLUTDescriptor;
+           mLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
          }
+
          stack.clear();
          if ((EC_Normal == item->search((DcmTagKey &)modalityLUTExplanation.getTag(),
            stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_LO))
@@ -400,9 +404,11 @@
 
          // LUTData can be OW, US or SS. For now we only handle US.
          if ((EC_Normal == item->search((DcmTagKey &)modalityLUTData.getTag(),
-           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US))
+           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
          {
-           modalityLUTData = *((DcmUnsignedShort *)(stack.top()));
+           // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+           DcmElement *mdata = &modalityLUTData;
+           mdata->operator=(*(DcmElement *)(stack.top()));
          }
          stack.clear();
          if ((EC_Normal == item->search((DcmTagKey &)modalityLUTType.getTag(),
@@ -879,11 +885,13 @@
       {
          item = seq->getItem(0);
          stack.clear();
-         // LUTDescriptor can be US or SS. For now we only handle US.
+         // LUTDescriptor can be US or SS
          if ((EC_Normal == item->search((DcmTagKey &)modalityLUTDescriptor.getTag(),
-           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US))
+           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
          {
-           modalityLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+           // We explicitly use DcmElement::operator=(), which works for US and SS
+           DcmElement *mLUTDescriptor = &modalityLUTDescriptor;
+           mLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
          }
          stack.clear();
          if ((EC_Normal == item->search((DcmTagKey &)modalityLUTExplanation.getTag(),
@@ -895,9 +903,11 @@
 
          // LUTData can be OW, US or SS. For now we only handle US.
          if ((EC_Normal == item->search((DcmTagKey &)modalityLUTData.getTag(),
-           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US))
+           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
          {
-           modalityLUTData = *((DcmUnsignedShort *)(stack.top()));
+           // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+           DcmElement *mdata = &modalityLUTData;
+           mdata->operator=(*(DcmElement *)(stack.top()));
          }
          stack.clear();
          if ((EC_Normal == item->search((DcmTagKey &)modalityLUTType.getTag(),
@@ -1247,10 +1257,16 @@
         dseq = new DcmSequenceOfItems(DCM_ModalityLUTSequence);
         if (dseq)
         {
-          delem = new DcmUnsignedShort(modalityLUTDescriptor);
+          // we clone modalityLUTDescriptor in order to retain the VR (US or SS)
+          delem = OFstatic_cast(DcmElement *, modalityLUTDescriptor.clone());
           if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
-          delem = new DcmUnsignedShort(modalityLUTData);
+
+          // we write LUTData as OW in order to avoid the 64 kByte limit for US
+          delem = new DcmOtherByteOtherWord(DCM_LUTData);
+          delem->operator=(modalityLUTData);
+          OFstatic_cast(DcmOtherByteOtherWord *, delem)->setVR(EVR_OW);
           if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
+
           delem = new DcmLongString(modalityLUTType);
           if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
           if (modalityLUTExplanation.getLength() >0)
--- a/dcmpstat/libsrc/dvpspl.cc
+++ b/dcmpstat/libsrc/dvpspl.cc
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1999-2018, OFFIS e.V.
+ *  Copyright (C) 1999-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -24,6 +24,7 @@
 #include "dcmtk/dcmdata/dcdeftag.h"
 #include "dcmtk/dcmdata/dcsequen.h"
 #include "dcmtk/dcmdata/dcvrcs.h"
+#include "dcmtk/dcmdata/dcvrobow.h"
 #include "dcmtk/dcmpstat/dvpspl.h"
 #include "dcmtk/dcmpstat/dvpsdef.h"     /* for constants and macros */
 #include "dcmtk/dcmnet/dimse.h"
@@ -79,29 +80,36 @@
   if (result==EC_Normal)
   {
     stack.clear();
-    if (EC_Normal == dset.search(DCM_PresentationLUTSequence, stack, ESM_fromHere, OFFalse))
+    if (EC_Normal == dset.search(DCM_PresentationLUTSequence, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_SQ))
     {
       seq=(DcmSequenceOfItems *)stack.top();
       if (seq->card() ==1)
       {
          item = seq->getItem(0);
          stack.clear();
-         if (EC_Normal == item->search((DcmTagKey &)presentationLUTDescriptor.getTag(), 
-           stack, ESM_fromHere, OFFalse))
+
+         // LUTDescriptor can be US or SS
+         if ((EC_Normal == item->search((DcmTagKey &)presentationLUTDescriptor.getTag(),
+           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
          {
-           presentationLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+           // We explicitly use DcmElement::operator=(), which works for US and SS
+           DcmElement *pLUTDescriptor = &presentationLUTDescriptor;
+           pLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
          }
+
          stack.clear();
          if (EC_Normal == item->search((DcmTagKey &)presentationLUTExplanation.getTag(), 
-           stack, ESM_fromHere, OFFalse))
+           stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_LO))
          {
            presentationLUTExplanation = *((DcmLongString *)(stack.top()));
          }
          stack.clear();
          if (EC_Normal == item->search((DcmTagKey &)presentationLUTData.getTag(), 
-           stack, ESM_fromHere, OFFalse))
+           stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
          {
-           presentationLUTData = *((DcmUnsignedShort *)(stack.top()));
+           // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+           DcmElement *pldata = &presentationLUTData;
+           pldata->operator=(*(DcmElement *)(stack.top()));
          }
       } else {
         result=EC_TagNotFound;
@@ -187,10 +195,16 @@
         dseq = new DcmSequenceOfItems(DCM_PresentationLUTSequence);
         if (dseq)
         {
-          delem = new DcmUnsignedShort(presentationLUTDescriptor);
+          // we clone presentationLUTDescriptor in order to retain the VR (US or SS)
+          delem = OFstatic_cast(DcmElement *, presentationLUTDescriptor.clone());
           if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
-          delem = new DcmUnsignedShort(presentationLUTData);
+
+          // we write LUTData as OW in order to avoid the 64 kByte limit for US
+          delem = new DcmOtherByteOtherWord(DCM_LUTData);
+          delem->operator=(presentationLUTData);
+          OFstatic_cast(DcmOtherByteOtherWord *, delem)->setVR(EVR_OW);
           if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
+
           if (presentationLUTExplanation.getLength() >0)
           {
             delem = new DcmLongString(presentationLUTExplanation);
--- a/dcmpstat/libsrc/dvpssv.cc
+++ b/dcmpstat/libsrc/dvpssv.cc
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2018, OFFIS e.V.
+ *  Copyright (C) 1998-2024, OFFIS e.V.
  *  All rights reserved.  See COPYRIGHT file for details.
  *
  *  This software and supporting documentation were developed by
@@ -23,6 +23,7 @@
 #include "dcmtk/config/osconfig.h"    /* make sure OS specific configuration is included first */
 #include "dcmtk/dcmdata/dcdeftag.h"
 #include "dcmtk/dcmdata/dcsequen.h"
+#include "dcmtk/dcmdata/dcvrobow.h"
 #include "dcmtk/dcmpstat/dvpssv.h"
 #include "dcmtk/dcmpstat/dvpsri.h"      /* for DVPSReferencedImage */
 #include "dcmtk/dcmpstat/dvpsrsl.h"     /* DVPSReferencedSeries_PList */
@@ -75,29 +76,36 @@
   if (result==EC_Normal)
   {
     stack.clear();
-    if (EC_Normal == dset.search(DCM_VOILUTSequence, stack, ESM_fromHere, OFFalse))
+    if (EC_Normal == dset.search(DCM_VOILUTSequence, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_SQ))
     {
       seq=(DcmSequenceOfItems *)stack.top();
       if (seq->card() ==1)
       {
          item = seq->getItem(0);
          stack.clear();
-         if (EC_Normal == item->search((DcmTagKey &)voiLUTDescriptor.getTag(), 
-           stack, ESM_fromHere, OFFalse))
+
+         // LUTDescriptor can be US or SS
+         if ((EC_Normal == item->search((DcmTagKey &)voiLUTDescriptor.getTag(),
+           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
          {
-           voiLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+           // We explicitly use DcmElement::operator=(), which works for US and SS
+           DcmElement *vLUTDescriptor = &voiLUTDescriptor;
+           vLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
          }
+
          stack.clear();
          if (EC_Normal == item->search((DcmTagKey &)voiLUTExplanation.getTag(), 
-           stack, ESM_fromHere, OFFalse))
+           stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_LO))
          {
            voiLUTExplanation = *((DcmLongString *)(stack.top()));
          }
          stack.clear();
          if (EC_Normal == item->search((DcmTagKey &)voiLUTData.getTag(), 
-           stack, ESM_fromHere, OFFalse))
+           stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
          {
-           voiLUTData = *((DcmUnsignedShort *)(stack.top()));
+           // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+           DcmElement *vldata = &voiLUTData;
+           vldata->operator=(*(DcmElement *)(stack.top()));
          }
       } else {
         result=EC_TagNotFound;
@@ -177,10 +185,16 @@
       dseq = new DcmSequenceOfItems(DCM_VOILUTSequence);
       if (dseq)
       {
-        delem = new DcmUnsignedShort(voiLUTDescriptor);
+        // we clone voiLUTDescriptor in order to retain the VR (US or SS)
+        delem = OFstatic_cast(DcmElement *, voiLUTDescriptor.clone());
         if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
-        delem = new DcmUnsignedShort(voiLUTData);
+
+        // we write LUTData as OW in order to avoid the 64 kByte limit for US
+        delem = new DcmOtherByteOtherWord(DCM_LUTData);
+        delem->operator=(voiLUTData);
+        OFstatic_cast(DcmOtherByteOtherWord *, delem)->setVR(EVR_OW);
         if (delem) ditem->insert(delem, OFTrue /*replaceOld*/); else result=EC_MemoryExhausted;
+
         if (voiLUTExplanation.getLength() >0)
         {
           delem = new DcmLongString(voiLUTExplanation);
--- a/dcmpstat/libsrc/dvpssvl.cc
+++ b/dcmpstat/libsrc/dvpssvl.cc
@@ -71,8 +71,8 @@
   DVPSSoftcopyVOI *newImage = NULL;
   DcmSequenceOfItems *dseq=NULL;
   DcmItem *ditem=NULL;
-  
-  if (EC_Normal == dset.search(DCM_SoftcopyVOILUTSequence, stack, ESM_fromHere, OFFalse))
+
+  if (EC_Normal == dset.search(DCM_SoftcopyVOILUTSequence, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_SQ))
   {
     dseq=(DcmSequenceOfItems *)stack.top();
     if (dseq)
@@ -248,29 +248,36 @@
   if (result==EC_Normal)
   {
     stack.clear();
-    if (EC_Normal == dset.search(DCM_VOILUTSequence, stack, ESM_fromHere, OFFalse))
+    if (EC_Normal == dset.search(DCM_VOILUTSequence, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_SQ))
     {
       seq=(DcmSequenceOfItems *)stack.top();
       if (seq->card() > 0)
       {
          item = seq->getItem(0);
          stack.clear();
-         if (EC_Normal == item->search((DcmTagKey &)voiLUTDescriptor.getTag(), 
-           stack, ESM_fromHere, OFFalse))
+
+         // LUTDescriptor can be US or SS
+         if ((EC_Normal == item->search((DcmTagKey &)voiLUTDescriptor.getTag(),
+           stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
          {
-           voiLUTDescriptor = *((DcmUnsignedShort *)(stack.top()));
+           // We explicitly use DcmElement::operator=(), which works for US and SS
+           DcmElement *vLUTDescriptor = &voiLUTDescriptor;
+           vLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
          }
+
          stack.clear();
-         if (EC_Normal == item->search((DcmTagKey &)voiLUTExplanation.getTag(), 
-           stack, ESM_fromHere, OFFalse))
+         if (EC_Normal == item->search((DcmTagKey &)voiLUTExplanation.getTag(),
+           stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_LO))
          {
            voiLUTExplanation = *((DcmLongString *)(stack.top()));
          }
          stack.clear();
-         if (EC_Normal == item->search((DcmTagKey &)voiLUTData.getTag(), 
-           stack, ESM_fromHere, OFFalse))
+         if (EC_Normal == item->search((DcmTagKey &)voiLUTData.getTag(),
+           stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
          {
-           voiLUTData = *((DcmUnsignedShort *)(stack.top()));
+           // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+           DcmElement *vldata = &voiLUTData;
+           vldata->operator=(*(DcmElement *)(stack.top()));
          }
       } else result=EC_TagNotFound;
     }
--- a/dcmpstat/libsrc/dvpstat.cc
+++ b/dcmpstat/libsrc/dvpstat.cc
@@ -578,14 +578,14 @@
       currentImageSelectedFrame = 1; // default: first frame
 
       // get Modality
-      if (EC_Normal == dataset->search(DCM_Modality, stack, ESM_fromHere, OFFalse))
+      if (EC_Normal == dataset->search(DCM_Modality, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_CS))
       {
         currentImageModality = *((DcmCodeString *)(stack.top()));
       }
       stack.clear();
 
       // determine default Presentation LUT Shape
-      if (EC_Normal == dataset->search(DCM_PhotometricInterpretation, stack, ESM_fromHere, OFFalse))
+      if (EC_Normal == dataset->search(DCM_PhotometricInterpretation, stack, ESM_fromHere, OFFalse) && (stack.top()->ident() == EVR_CS))
       {
          DcmCodeString *photometricInterpretation = (DcmCodeString *)(stack.top());
          if (photometricInterpretation->getVM() == 1)
@@ -598,12 +598,12 @@
       stack.clear();
 
       // get SOP class UID and SOP instance UID.
-      if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPClassUID, stack, ESM_fromHere, OFFalse)))
+      if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPClassUID, stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_UI))
       {
         result = ((DcmUniqueIdentifier *)(stack.top()))->getString(currentImageSOPClassUID);
       }
       stack.clear();
-      if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPInstanceUID, stack, ESM_fromHere, OFFalse)))
+      if ((EC_Normal == result)&&(EC_Normal == dataset->search(DCM_SOPInstanceUID, stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_UI))
       {
         result = ((DcmUniqueIdentifier *)(stack.top()))->getString(currentImageSOPInstanceUID);
       }
@@ -1124,40 +1124,36 @@
         numEntries16 = (Uint16)numberOfEntries;
 
       /* LUT Descriptor */
-      DcmElement *lutDescriptor = NULL;
-      if (firstMapped < 0)
+      DcmUnsignedShort *lutDescriptor = new DcmUnsignedShort(DcmTag(DCM_LUTDescriptor, EVR_US));
+      if (lutDescriptor == NULL) status = EC_MemoryExhausted;
+      else
       {
-        // LUT Descriptor is SS
-        lutDescriptor = new DcmSignedShort(DcmTag(DCM_LUTDescriptor, EVR_SS));
-        if (lutDescriptor != NULL)
+        if (firstMapped < 0)
         {
-            status = lutDescriptor->putSint16((Sint16)numEntries16, 0);
-            if (EC_Normal == status)
-              status = lutDescriptor->putSint16((Sint16)firstMapped, 1);
-            if (EC_Normal == status)
-              status = lutDescriptor->putSint16((Sint16)numberOfBits, 2);
-        } else
-          status = EC_MemoryExhausted;
-      } else {
-        // LUT Descriptor is US
-        lutDescriptor = new DcmUnsignedShort(DcmTag(DCM_LUTDescriptor, EVR_US));
-        if (lutDescriptor != NULL)
-        {
-            status = lutDescriptor->putUint16(numEntries16, 0);
-            if (EC_Normal == status)
-              status = lutDescriptor->putUint16((Uint16)firstMapped, 1);
-            if (EC_Normal == status)
-              status = lutDescriptor->putUint16((Uint16)numberOfBits, 2);
-        } else
-            status = EC_MemoryExhausted;
+          // LUT Descriptor is SS
+          DcmSignedShort ldesc(DcmTag(DCM_LUTDescriptor, EVR_SS));
+          status = ldesc.putSint16((Sint16)numEntries16, 0);
+          if (EC_Normal == status) status = ldesc.putSint16((Sint16)firstMapped, 1);
+          if (EC_Normal == status) status = ldesc.putSint16((Sint16)numberOfBits, 2);
+          if (EC_Normal == status)
+          {
+            // copy content of SS element into DcmUnsignedShort using DcmElement::operator=
+            DcmElement *ld = lutDescriptor;
+            ld->operator=(ldesc);
+          }
+        } else {
+          // LUT Descriptor is US
+          status = lutDescriptor->putUint16(numEntries16, 0);
+          if (EC_Normal == status) status = lutDescriptor->putUint16((Uint16)firstMapped, 1);
+          if (EC_Normal == status) status = lutDescriptor->putUint16((Uint16)numberOfBits, 2);
+        }
       }
 
       /* LUT Data */
-      DcmElement *lutData = NULL;
+      DcmUnsignedShort *lutData = NULL;
       if (status == EC_Normal)
       {
-        // LUT Data as OW, because of max size = 64K
-        lutData = new DcmOtherByteOtherWord(DcmTag(DCM_LUTData, EVR_OW));
+        lutData = new DcmUnsignedShort(DcmTag(DCM_LUTData, EVR_US));
         if (lutData != NULL)
           status = lutData->putUint16Array(data, numberOfEntries);
         else
@@ -1186,15 +1182,14 @@
       if (status == EC_Normal)
       {
         if ((lutDescriptor != NULL) && (lutData != NULL) && (lutExplanation !=  NULL))
-          status = setVOILUT(*(DcmUnsignedShort *)lutDescriptor, *(DcmUnsignedShort *)lutData, *lutExplanation, applicability);
+          status = setVOILUT(*lutDescriptor, *lutData, *lutExplanation, applicability);
       }
 
       /* delete temporary dcmtk structures */
       delete lutDescriptor;
       delete lutData;
       delete lutExplanation;
-    } else
-      status = EC_MemoryExhausted;
+    } else status = EC_MemoryExhausted;
     delete[] data;
   }
   return status;
--- a/dcmpstat/libsrc/dvpsvl.cc
+++ b/dcmpstat/libsrc/dvpsvl.cc
@@ -59,9 +59,24 @@
   OFCondition result = EC_Normal;
   DcmStack stack;
 
-  READ_FROM_DATASET(DcmUnsignedShort, EVR_US, voiLUTDescriptor)
+  // LUTDescriptor can be US or SS
+  if ((EC_Normal == dset.search((DcmTagKey &)voiLUTDescriptor.getTag(),
+    stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_SS))
+  {
+    // We explicitly use DcmElement::operator=(), which works for US and SS
+    DcmElement *vLUTDescriptor = &voiLUTDescriptor;
+    vLUTDescriptor->operator=(* OFstatic_cast(DcmElement *, stack.top()));
+  }
+
   READ_FROM_DATASET(DcmLongString, EVR_LO, voiLUTExplanation)
-  READ_FROM_DATASET(DcmUnsignedShort, EVR_US, voiLUTData)
+
+  stack.clear();
+  if ((EC_Normal == dset.search((DcmTagKey &)voiLUTData.getTag(), stack, ESM_fromHere, OFFalse)) && (stack.top()->ident() == EVR_US || stack.top()->ident() == EVR_OW))
+  {
+    // we deliberately call DcmElement::operator=() here, which will work for both DcmUnsignedShort and DcmOtherByteOtherWord parameters
+    DcmElement *vldata = &voiLUTData;
+    vldata->operator=(*(DcmElement *)(stack.top()));
+  }
 
   if (EC_Normal == result)
   {