[PATCH] Fixed unchecked typecasts and fixed LUT handling.
authorMarco Eichelberg <dicom@offis.de>
Mon, 15 Apr 2024 10:19:33 +0000 (12:19 +0200)
committerMathieu Malaterre <malat@debian.org>
Mon, 8 Jul 2024 11:31:04 +0000 (13:31 +0200)
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.

Gbp-Pq: Name 0002-Fixed-unchecked-typecasts-and-fixed-LUT-handling.patch

dcmpstat/libsrc/dcmpstat.cc
dcmpstat/libsrc/dvpspl.cc
dcmpstat/libsrc/dvpssv.cc
dcmpstat/libsrc/dvpssvl.cc
dcmpstat/libsrc/dvpstat.cc
dcmpstat/libsrc/dvpsvl.cc

index 4a8e5af6c361187c6a08675a50741dc79faa78d5..a7d11abaca028b2b41673a86ed52c394e134b9df 100644 (file)
@@ -384,12 +384,16 @@ OFCondition DcmPresentationState::read(DcmItem &dset)
       {
          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 @@ OFCondition DcmPresentationState::read(DcmItem &dset)
 
          // 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 @@ OFCondition DcmPresentationState::createFromImage(
       {
          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 @@ OFCondition DcmPresentationState::createFromImage(
 
          // 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 @@ OFCondition DcmPresentationState::write(DcmItem &dset, OFBool replaceSOPInstance
         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)
index ec4cccf97300a26b394dcc9c44de86dd9cf8cf05..f5574ab33714fc88035e8af6a8fceee0a63543b2 100644 (file)
@@ -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 @@ OFCondition DVPSPresentationLUT::read(DcmItem &dset, OFBool withSOPInstance)
   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 @@ OFCondition DVPSPresentationLUT::write(DcmItem &dset, OFBool withSOPInstance)
         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);
index 8e3d49bd4fc7d03fbc95e6233d4c0a4a60519c02..4a7fd0e3092e972b3234ca28a190f0f0e01441b8 100644 (file)
@@ -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 @@ OFCondition DVPSSoftcopyVOI::read(DcmItem &dset)
   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 @@ OFCondition DVPSSoftcopyVOI::write(DcmItem &dset)
       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);
index d1532db5c29d7b1eb2940ba7a62708201b169902..efcb6a26be6f461c10a96fdd5018cff4f97d448b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1999-2023, 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
@@ -72,7 +72,7 @@ OFCondition DVPSSoftcopyVOI_PList::read(DcmItem &dset)
   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)
@@ -249,29 +249,36 @@ OFCondition DVPSSoftcopyVOI_PList::createFromImage(
   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))
+           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;
     }
index ce2f5ad5ffe4cc2213319cd82e43347f8ce05bd9..4bfe8f9cbd44cf1c29be7b9bb0d70f88697a3b70 100644 (file)
@@ -1,6 +1,6 @@
 /*
  *
- *  Copyright (C) 1998-2021, 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
@@ -578,14 +578,14 @@ OFCondition DVPresentationState::attachImage(DcmDataset *dataset, OFBool transfe
       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 @@ OFCondition DVPresentationState::attachImage(DcmDataset *dataset, OFBool transfe
       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 @@ OFCondition DVPresentationState::setGammaVOILUT(double gammaValue, DVPSObjectApp
         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 @@ OFCondition DVPresentationState::setGammaVOILUT(double gammaValue, DVPSObjectApp
       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;
index b10b83f20dc86a7564d66d4eeb992c0a86148649..fdba0a0e0698bedd9d69f0bfe31c0f04f7cda6a8 100644 (file)
@@ -59,9 +59,24 @@ OFCondition DVPSVOILUT::read(DcmItem &dset)
   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)
   {