Control: tags -1 patch On Sat, Jun 29, 2024 at 04:44:43PM +0200, Salvatore Bonaccorso wrote: >... > The following vulnerability was published for dcmtk. > > CVE-2024-27628[0]: > | Buffer Overflow vulnerability in DCMTK v.3.6.8 allows an attacker to > | execute arbitrary code via the EctEnhancedCT method component. > > > If you fix the vulnerability please also make sure to include the > CVE (Common Vulnerabilities & Exposures) id in your changelog entry. > > For further information see: > > [0] https://security-tracker.debian.org/tracker/CVE-2024-27628 > https://www.cve.org/CVERecord?id=CVE-2024-27628 > [1] https://support.dcmtk.org/redmine/issues/1108 > [2] > https://github.com/DCMTK/dcmtk/commit/ec52e99e1e33fc39810560421c0833b02da567b3 >...
Attached is this patch for 3.6.8 (no conflicts during rebasing). The new test fails without the fix and passes with the fix, no regressions during the build test. The actual code fix is pretty small (and not ABI breaking), most of the patch is test code. cu Adrian
>From 855ee5eacad12b4ef39d36a78c9c24d038c4a231 Mon Sep 17 00:00:00 2001 From: Michael Onken <on...@open-connections.de> Date: Tue, 20 Feb 2024 10:50:28 +0100 Subject: Fixed possible overflows when allocating memory. Thanks to GitHub user "bananabr" (Daniel Berredo) for the report and suggested patch. --- dcmect/libsrc/enhanced_ct.cc | 14 +- dcmect/tests/CMakeLists.txt | 1 + dcmect/tests/Makefile.dep | 151 +++++++++++++++ dcmect/tests/Makefile.in | 4 +- dcmect/tests/t_overflow.cc | 362 +++++++++++++++++++++++++++++++++++ dcmect/tests/tests.cc | 3 +- 6 files changed, 531 insertions(+), 4 deletions(-) create mode 100644 dcmect/tests/t_overflow.cc diff --git a/dcmect/libsrc/enhanced_ct.cc b/dcmect/libsrc/enhanced_ct.cc index 619374290..47d6335f0 100644 --- a/dcmect/libsrc/enhanced_ct.cc +++ b/dcmect/libsrc/enhanced_ct.cc @@ -24,6 +24,7 @@ #include "dcmtk/dcmect/types.h" #include "dcmtk/dcmfg/concatenationcreator.h" #include "dcmtk/dcmfg/concatenationloader.h" +#include "dcmtk/dcmfg/fgtypes.h" #include "dcmtk/dcmiod/iodutil.h" #include "dcmtk/dcmiod/modimagepixel.h" @@ -100,8 +101,19 @@ struct EctEnhancedCT::WriteVisitor m_CT.getRows(rows); m_CT.getColumns(cols); const size_t numFrames = m_CT.m_Frames.size(); + if (numFrames > 2147483647) + { + DCMECT_ERROR("More than 2147483647 frames provided"); + return FG_EC_PixelDataTooLarge; + } + const size_t numPixelsFrame = OFstatic_cast(size_t, rows) * OFstatic_cast(size_t, cols); const size_t numBytesFrame = m_CT.m_Frames[0]->length; - const size_t numPixelsFrame = rows * cols; + if (numBytesFrame != numPixelsFrame * 2) + { + DCMECT_ERROR("Invalid number of bytes per frame: Expected " << numPixelsFrame * 2 << " but got " + << numBytesFrame << " frame pixel data"); + return ECT_InvalidPixelInfo; + } // Creates the correct pixel data element, based on the image pixel module used. DcmPixelData* pixData = new DcmPixelData(DCM_PixelData); OFCondition result; diff --git a/dcmect/tests/CMakeLists.txt b/dcmect/tests/CMakeLists.txt index 5d66b1145..032553414 100644 --- a/dcmect/tests/CMakeLists.txt +++ b/dcmect/tests/CMakeLists.txt @@ -2,6 +2,7 @@ DCMTK_ADD_EXECUTABLE(dcmect_tests tests.cc t_huge_concat.cc + t_overflow.cc t_roundtrip.cc ) diff --git a/dcmect/tests/Makefile.dep b/dcmect/tests/Makefile.dep index 9d26f581c..dfb50b812 100644 --- a/dcmect/tests/Makefile.dep +++ b/dcmect/tests/Makefile.dep @@ -192,6 +192,157 @@ t_huge_concat.o: t_huge_concat.cc \ ../../dcmfg/include/dcmtk/dcmfg/fgrealworldvaluemapping.h \ ../../dcmiod/include/dcmtk/dcmiod/iodcontentitemmacro.h \ ../../dcmfg/include/dcmtk/dcmfg/fgtemporalposition.h +t_overflow.o: t_overflow.cc ../../config/include/dcmtk/config/osconfig.h \ + ../include/dcmtk/dcmect/enhanced_ct.h ../include/dcmtk/dcmect/def.h \ + ../../ofstd/include/dcmtk/ofstd/ofexport.h \ + ../include/dcmtk/dcmect/types.h ../../oflog/include/dcmtk/oflog/oflog.h \ + ../../oflog/include/dcmtk/oflog/logger.h \ + ../../oflog/include/dcmtk/oflog/config.h \ + ../../ofstd/include/dcmtk/ofstd/ofdefine.h \ + ../../ofstd/include/dcmtk/ofstd/ofcast.h \ + ../../ofstd/include/dcmtk/ofstd/ofstdinc.h \ + ../../oflog/include/dcmtk/oflog/config/defines.h \ + ../../oflog/include/dcmtk/oflog/helpers/threadcf.h \ + ../../oflog/include/dcmtk/oflog/loglevel.h \ + ../../ofstd/include/dcmtk/ofstd/ofvector.h \ + ../../ofstd/include/dcmtk/ofstd/oftypes.h \ + ../../ofstd/include/dcmtk/ofstd/ofstream.h \ + ../../oflog/include/dcmtk/oflog/tstring.h \ + ../../ofstd/include/dcmtk/ofstd/ofstring.h \ + ../../oflog/include/dcmtk/oflog/tchar.h \ + ../../oflog/include/dcmtk/oflog/spi/apndatch.h \ + ../../oflog/include/dcmtk/oflog/appender.h \ + ../../ofstd/include/dcmtk/ofstd/ofmem.h \ + ../../ofstd/include/dcmtk/ofstd/ofutil.h \ + ../../ofstd/include/dcmtk/ofstd/oftraits.h \ + ../../ofstd/include/dcmtk/ofstd/variadic/tuplefwd.h \ + ../../oflog/include/dcmtk/oflog/layout.h \ + ../../oflog/include/dcmtk/oflog/streams.h \ + ../../oflog/include/dcmtk/oflog/helpers/pointer.h \ + ../../oflog/include/dcmtk/oflog/thread/syncprim.h \ + ../../oflog/include/dcmtk/oflog/spi/filter.h \ + ../../oflog/include/dcmtk/oflog/helpers/lockfile.h \ + ../../oflog/include/dcmtk/oflog/spi/logfact.h \ + ../../oflog/include/dcmtk/oflog/logmacro.h \ + ../../oflog/include/dcmtk/oflog/helpers/snprintf.h \ + ../../oflog/include/dcmtk/oflog/tracelog.h \ + ../../ofstd/include/dcmtk/ofstd/ofcond.h \ + ../../ofstd/include/dcmtk/ofstd/ofdiag.h \ + ../../ofstd/include/dcmtk/ofstd/diag/push.def \ + ../../ofstd/include/dcmtk/ofstd/diag/useafree.def \ + ../../ofstd/include/dcmtk/ofstd/diag/pop.def \ + ../../dcmfg/include/dcmtk/dcmfg/fginterface.h \ + ../../dcmfg/include/dcmtk/dcmfg/fg.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgbase.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcitem.h \ + ../../ofstd/include/dcmtk/ofstd/offile.h \ + ../../ofstd/include/dcmtk/ofstd/ofstd.h \ + ../../ofstd/include/dcmtk/ofstd/oflist.h \ + ../../ofstd/include/dcmtk/ofstd/oflimits.h \ + ../../config/include/dcmtk/config/arith.h \ + ../../ofstd/include/dcmtk/ofstd/oferror.h \ + ../../dcmdata/include/dcmtk/dcmdata/dctypes.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcdefine.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcobject.h \ + ../../ofstd/include/dcmtk/ofstd/ofglobal.h \ + ../../ofstd/include/dcmtk/ofstd/ofthread.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcerror.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcxfer.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvr.h \ + ../../dcmdata/include/dcmtk/dcmdata/dctag.h \ + ../../dcmdata/include/dcmtk/dcmdata/dctagkey.h \ + ../../ofstd/include/dcmtk/ofstd/diag/ignrattr.def \ + ../../dcmdata/include/dcmtk/dcmdata/dcstack.h \ + ../../dcmdata/include/dcmtk/dcmdata/dclist.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcpcache.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgtypes.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgdefine.h \ + ../../ofstd/include/dcmtk/ofstd/ofmap.h \ + ../../dcmiod/include/dcmtk/dcmiod/iodimage.h \ + ../../dcmiod/include/dcmtk/dcmiod/iodcommn.h \ + ../../dcmiod/include/dcmtk/dcmiod/iodrules.h \ + ../../dcmiod/include/dcmtk/dcmiod/iodtypes.h \ + ../../dcmiod/include/dcmtk/dcmiod/ioddef.h \ + ../../dcmiod/include/dcmtk/dcmiod/modcommoninstanceref.h \ + ../../dcmiod/include/dcmtk/dcmiod/iodmacro.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcdeftag.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrlo.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcchrstr.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcbytstr.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcelem.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvris.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrus.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrlt.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrcs.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrpn.h \ + ../../dcmiod/include/dcmtk/dcmiod/modbase.h \ + ../../dcmiod/include/dcmtk/dcmiod/iodreferences.h \ + ../../dcmiod/include/dcmtk/dcmiod/modequipment.h \ + ../../dcmiod/include/dcmtk/dcmiod/modfor.h \ + ../../dcmiod/include/dcmtk/dcmiod/modgeneralseries.h \ + ../../dcmiod/include/dcmtk/dcmiod/modgeneralstudy.h \ + ../../dcmiod/include/dcmtk/dcmiod/modpatient.h \ + ../../dcmiod/include/dcmtk/dcmiod/modpatientstudy.h \ + ../../dcmiod/include/dcmtk/dcmiod/modsopcommon.h \ + ../../dcmiod/include/dcmtk/dcmiod/modgeneralimage.h \ + ../../dcmiod/include/dcmtk/dcmiod/modimagepixelvariant.h \ + ../../dcmiod/include/dcmtk/dcmiod/modimagepixelbase.h \ + ../../ofstd/include/dcmtk/ofstd/ofvriant.h \ + ../../ofstd/include/dcmtk/ofstd/variadic/variant.h \ + ../../ofstd/include/dcmtk/ofstd/variadic/helpers.h \ + ../../ofstd/include/dcmtk/ofstd/ofalign.h \ + ../../ofstd/include/dcmtk/ofstd/diag/cnvrsn.def \ + ../../ofstd/include/dcmtk/ofstd/diag/vsprfw.def \ + ../../ofstd/include/dcmtk/ofstd/diag/arrybnds.def \ + ../../ofstd/include/dcmtk/ofstd/diag/unrefprm.def \ + ../../dcmiod/include/dcmtk/dcmiod/modacquisitioncontext.h \ + ../../dcmiod/include/dcmtk/dcmiod/modenhequipment.h \ + ../../dcmiod/include/dcmtk/dcmiod/modimagepixel.h \ + ../../dcmiod/include/dcmtk/dcmiod/modmultiframedimension.h \ + ../../dcmiod/include/dcmtk/dcmiod/modmultiframefg.h \ + ../../dcmiod/include/dcmtk/dcmiod/modsynchronisation.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrdt.h \ + ../../ofstd/include/dcmtk/ofstd/ofdatime.h \ + ../../ofstd/include/dcmtk/ofstd/ofdate.h \ + ../../ofstd/include/dcmtk/ofstd/oftime.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrds.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrfd.h \ + ../../ofstd/include/dcmtk/ofstd/oftempf.h \ + ../../ofstd/include/dcmtk/ofstd/oftest.h \ + ../../ofstd/include/dcmtk/ofstd/ofconapp.h \ + ../../ofstd/include/dcmtk/ofstd/ofcmdln.h \ + ../../ofstd/include/dcmtk/ofstd/ofexbl.h \ + ../../ofstd/include/dcmtk/ofstd/ofconsol.h \ + ../../ofstd/include/dcmtk/ofstd/ofexit.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcuid.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcdict.h \ + ../../dcmdata/include/dcmtk/dcmdata/dchashdi.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcfilefo.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcsequen.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcdatset.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgctacquisitiondetails.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgctacquisitiontype.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgctadditionalxraysource.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrfl.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrsh.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgctexposure.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgctgeometry.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgctimageframetype.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgctposition.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgctreconstruction.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgcttabledynamics.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgctxraydetails.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgfracon.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrul.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgframeanatomy.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgirradiationeventid.h \ + ../../dcmdata/include/dcmtk/dcmdata/dcvrui.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgpixeltransform.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgpixmsr.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgplanor.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgplanpo.h \ + ../../dcmfg/include/dcmtk/dcmfg/fgrealworldvaluemapping.h \ + ../../dcmiod/include/dcmtk/dcmiod/iodcontentitemmacro.h t_roundtrip.o: t_roundtrip.cc \ ../../config/include/dcmtk/config/osconfig.h \ ../../ofstd/include/dcmtk/ofstd/ofmem.h \ diff --git a/dcmect/tests/Makefile.in b/dcmect/tests/Makefile.in index da1f74f11..7dda4351f 100644 --- a/dcmect/tests/Makefile.in +++ b/dcmect/tests/Makefile.in @@ -24,10 +24,10 @@ LIBDIRS = -L$(top_srcdir)/libsrc -L$(ofstddir)/libsrc -L$(oflogdir)/libsrc \ -L$(oficonvdir)/libsrc LOCALLIBS = -ldcmect -ldcmfg -ldcmiod -ldcmdata -loflog -lofstd -loficonv \ $(ZLIBLIBS) $(CHARCONVLIBS) $(MATHLIBS) -LOCALINCLUDES = -I$(top_srcdir)/include -I$(ofstddir)/include -I$(oflogdir)/include \ +LOCALINCLUDES = -I$(top_srcdir)/include -I$(configdir)/include -I$(ofstddir)/include -I$(oflogdir)/include \ -I$(dcmdatadir)/include -I$(dcmioddir)/include -I$(dcmfgdir)/include -test_objs = tests.o t_huge_concat.o t_roundtrip.o +test_objs = tests.o t_huge_concat.o t_overflow.cc t_roundtrip.o objs = $(test_objs) progs = tests diff --git a/dcmect/tests/t_overflow.cc b/dcmect/tests/t_overflow.cc new file mode 100644 index 000000000..fcc0e1abb --- /dev/null +++ b/dcmect/tests/t_overflow.cc @@ -0,0 +1,362 @@ +/* + * + * Copyright (C) 2024, OFFIS e.V. + * All rights reserved. See COPYRIGHT file for details. + * + * This software and supporting documentation were developed by + * + * OFFIS e.V. + * R&D Division Health + * Escherweg 2 + * D-26121 Oldenburg, Germany + * + * + * Module: dcmect + * + * Author: Daniel Berredo / Michael Onken + * + * Purpose: Tests that check for pixel data overflow conditions + * + */ + + +#include <dcmtk/config/osconfig.h> /* make sure OS specific configuration is included first */ + +#include <dcmtk/dcmect/enhanced_ct.h> + +#include <dcmtk/ofstd/oftempf.h> +#include <dcmtk/ofstd/oftest.h> + +#include <dcmtk/dcmdata/dcdict.h> +#include <dcmtk/dcmdata/dcfilefo.h> + +#include <dcmtk/dcmfg/fgctacquisitiondetails.h> +#include <dcmtk/dcmfg/fgctacquisitiontype.h> +#include <dcmtk/dcmfg/fgctadditionalxraysource.h> +#include <dcmtk/dcmfg/fgctexposure.h> +#include <dcmtk/dcmfg/fgctgeometry.h> +#include <dcmtk/dcmfg/fgctimageframetype.h> +#include <dcmtk/dcmfg/fgctposition.h> +#include <dcmtk/dcmfg/fgctreconstruction.h> +#include <dcmtk/dcmfg/fgcttabledynamics.h> +#include <dcmtk/dcmfg/fgctxraydetails.h> +#include <dcmtk/dcmfg/fgfracon.h> +#include <dcmtk/dcmfg/fgframeanatomy.h> +#include <dcmtk/dcmfg/fgirradiationeventid.h> +#include <dcmtk/dcmfg/fgpixeltransform.h> +#include <dcmtk/dcmfg/fgpixmsr.h> +#include <dcmtk/dcmfg/fgplanor.h> +#include <dcmtk/dcmfg/fgplanpo.h> +#include <dcmtk/dcmfg/fgrealworldvaluemapping.h> + +static const Uint16 NUM_ROWS = 1024; +static const Uint16 NUM_COLS = 1; +static const Uint16 NUM_FRAMES = 2; +static const size_t NUM_PIXELS_PER_FRAME = 1; + +static OFString EXPECTED_DUMP; + +static EctEnhancedCT *create(); +static void configureIOD(EctEnhancedCT *ct); +static void setGenericValues(EctEnhancedCT *ct); +static void addSharedFGs(EctEnhancedCT *ct); +static void addFrames(EctEnhancedCT *ct); +static void addDimensions(EctEnhancedCT *ct); + + +OFTEST(dcmect_overflow) +{ + /* make sure data dictionary is loaded */ + if (!dcmDataDict.isDictionaryLoaded()) + { + OFCHECK(dcmDataDict.isDictionaryLoaded()); + } + + // Creation + EctEnhancedCT *ct = create(); + configureIOD(ct); + setGenericValues(ct); + addSharedFGs(ct); + addFrames(ct); + addDimensions(ct); + + // Write to dataset and compare its dump with expected result + DcmFileFormat dcmff; + + OFTempFile tf(O_RDWR, "", "t_overflow", ".dcm"); + OFCondition result; + result = ct->saveFile("output.dcm", EXS_LittleEndianExplicit); + OFCHECK_MSG(result == ECT_InvalidPixelInfo, result.text()); +} + +static EctEnhancedCT *create() +{ + IODEnhGeneralEquipmentModule::EquipmentInfo eq("Open Connections", "OC CT", "4711", "0.1"); + EctEnhancedCT *ct = NULL; + OFCondition result; + result = EctEnhancedCT::create(ct, + NUM_ROWS, + NUM_COLS, + OFFalse, + EctTypes::E_ImageType1_Original, + EctTypes::DT_ImageType3_Volume, + EctTypes::DT_ImageType4_Maximum, + "1" /* instance number */, + EctTypes::E_ContQuali_Research, + EctTypes::E_PixelPres_Monochrome, + EctTypes::E_VolProps_Volume, + EctTypes::DT_VolBasedCalcTechnique_VolumeRender, + eq, + "20190801120000" /* acquisition date */, + 2.0 /* acquisition duration */); + + OFCHECK(result.good()); + OFCHECK(ct != OFnullptr); + return ct; +} + +static void configureIOD(EctEnhancedCT *ct) +{ + if (!ct) + return; +} + +static void setGenericValues(EctEnhancedCT *ct) +{ + if (!ct) + return; + OFCHECK(ct->getPatient().setPatientName("Bond^James").good()); + OFCHECK(ct->getPatient().setPatientID("007").good()); + OFCHECK(ct->getPatient().setPatientBirthDate("19771007").good()); + OFCHECK(ct->getStudy().setStudyDate("20190801").good()); + OFCHECK(ct->getStudy().setStudyTime("120000").good()); + OFCHECK(ct->getStudy().setStudyID("1").good()); + OFCHECK(ct->getPatientStudy().setPatientAge("040Y").good()); + OFCHECK(ct->getSeries().setSeriesDescription("Test Description").good()); + OFCHECK(ct->getSeries().setSeriesNumber("1").good()); + OFCHECK(ct->getSeries().setPatientPosition("HFS").good()); + + // Those values are usually computed automatically. UIDS are generated and date/times are set to current values. + // But in order to compare the "old" dump with the freshly created image attributes, we set some values manually, + // so that they are not overwritten with new, automatically created values later. + OFCHECK(ct->getStudy().setStudyInstanceUID("1.2.276.0.7230010.3.1.2.8323329.14863.1565940357.864811").good()); + OFCHECK(ct->getFrameOfReference().setFrameOfReferenceUID("2.25.30853397773651184949181049330553108086").good()); + OFCHECK(ct->getSeries().setSeriesInstanceUID("1.2.276.0.7230010.3.1.3.8323329.14863.1565940357.864812").good()); + OFCHECK(ct->getSOPCommon().setSOPInstanceUID("1.2.276.0.7230010.3.1.4.8323329.14863.1565940357.864813").good()); + + OFCHECK(ct->getIODMultiFrameFGModule().setContentTime("092557").good()); + OFCHECK(ct->getIODMultiFrameFGModule().setContentDate("20190816").good()); +} + +static void addSharedFGs(EctEnhancedCT *ct) +{ + if (!ct) + return; + + FGPixelMeasures meas; + OFCHECK(meas.setPixelSpacing("0.1\\0.1").good()); + OFCHECK(meas.setSliceThickness("1.0").good()); + OFCHECK(meas.setSpacingBetweenSlices("0.05").good()); + + FGPlanePosPatient planpo; + OFCHECK(planpo.setImagePositionPatient("0.0", "0.0", "0.0").good()); + + FGPlaneOrientationPatient planor; + OFCHECK(planor.setImageOrientationPatient("1.0", "0.0", "0.0", "0.0", "1.0", "0.0").good()); + + FGFrameAnatomy ana; + OFCHECK(ana.setLaterality(FGFrameAnatomy::LATERALITY_BOTH).good()); + OFCHECK(ana.getAnatomy().getAnatomicRegion().set("12738006", "SCT", "Brain").good()); + + FGIrradiationEventIdentification irr; + OFCHECK(irr.setIrradiationEventUID("2.25.30853892236613436472911970638347155062").good()); + + FGCTImageFrameType itype; + OFCHECK(itype.setFrameType("ORIGINAL\\PRIMARY\\VOLUME\\MAXIMUM").good()); + OFCHECK(itype.setPixelPresentation(FGCTImageFrameType::E_PixelPres_Monochrome).good()); + OFCHECK(itype.setVolumetricProperties(FGCTImageFrameType::E_VolProp_Volume).good()); + OFCHECK(itype.setVolumeBasedCalculationTechnique(FGCTImageFrameType::DT_VolBasedCalcTechnique_VolumeRender).good()); + + FGCTAcquisitionType atype; + OFCHECK(atype.setAcquisitionType(FGCTAcquisitionType::DT_AcquisitionType_ConstantAngle).good()); + OFCHECK(atype.setTubeAngle(0.1).good()); + OFCHECK(atype.setConstantVolumeFlag(FGCTAcquisitionType::E_ConstVol_Yes).good()); + OFCHECK(atype.setFluoroscopyFlag(FGCTAcquisitionType::E_Fluoroscopy_No).good()); + + FGCTAcquisitionDetails adetails; + FGCTAcquisitionDetails::FGCTAcquisitionDetailsItem *item = new FGCTAcquisitionDetails::FGCTAcquisitionDetailsItem(); + OFCHECK(item->setRotationDirection(FGCTAcquisitionDetails::E_RotationDirection_CW).good()); + OFCHECK(item->setRevolutionTime(5).good()); + OFCHECK(item->setSingleCollimationWidth(1).good()); + OFCHECK(item->setTotalCollimationWidth(10).good()); + OFCHECK(item->setTableHeight(50).good()); + OFCHECK(item->setGantryDetectorTilt(5).good()); + OFCHECK(item->setDataCollectionDiameter(20).good()); + adetails.getCTAcquisitionDetailsItems().push_back(item); + + FGCTTableDynamics dyn; + FGCTTableDynamics::FGCTTableDynamicsItem *dyn_item = new FGCTTableDynamics::FGCTTableDynamicsItem; + OFCHECK(dyn_item); + if (dyn_item) + { + OFCHECK(dyn_item->setTableSpeed(1.0).good()); + OFCHECK(dyn_item->setTableFeedPerRotation(0.1).good()); + OFCHECK(dyn_item->setSpiralPitchFactor(0.2).good()); + dyn.getCTTableDynamicsItems().push_back(dyn_item); + } + + FGCTPosition pos; + OFCHECK(pos.setTablePosition(100.0).good()); + OFCHECK(pos.setReconstructionTargetCenterPatient(OFVector<Float64>(3, 1.0)).good()); + OFCHECK(pos.setDataCollectionCenterPatient(OFVector<Float64>(3, 2.0)).good()); + + FGCTGeometry geo; + FGCTGeometry::FGCTGeometryItem *geo_item = new FGCTGeometry::FGCTGeometryItem; + if (geo_item) + { + OFCHECK(geo_item->setDistanceSourceToDataCollectionCenter(5.0).good()); + OFCHECK(geo_item->setDistanceSourceToDetector(0.5).good()); + geo.getCTGeometryItems().push_back(geo_item); + } + + FGCTReconstruction rec; + OFCHECK(rec.setConvolutionKernel("DUMMY").good()); + OFCHECK(rec.setConvolutionKernelGroup("DUMMYGROUP").good()); + OFCHECK(rec.setImageFilter("FILTER").good()); + OFCHECK(rec.setReconstructionAlgorithm("ALGO").good()); + OFCHECK(rec.setReconstructionAngle(90.0).good()); + OFCHECK(rec.setReconstructionDiameter(100.0).good()); + // Not permitted if Reconstruction Diameter is provided instead + // OFCHECK(rec.setReconstructionFieldOfView(100.0, 100.0).good()); + OFCHECK(rec.setReconstructionPixelSpacing(0.1, 0.1).good()); + + FGCTExposure exp; + FGCTExposure::FGCTExposureItem *exp_item = new FGCTExposure::FGCTExposureItem; + if (exp_item) + { + OFCHECK(exp_item->setCTDIVol(0.1).good()); + CodeSequenceMacro *phantom_item = new CodeSequenceMacro("113682", "DCM", "ACR Accreditation Phantom - CT"); + exp_item->getCTDIPhantomTypeCodeSequence().push_back(phantom_item); + OFCHECK(exp_item->setExposureInMas(0.3).good()); + OFCHECK(exp_item->setExposureModulationType("WEIRD").good()); + OFCHECK(exp_item->setExposureTimeInMs(0.4).good()); + OFCHECK(exp_item->setImageAndFluoroscopyAreaDoseProduct(0.5).good()); + OFCHECK(exp_item->setWaterEquivalentDiameter(0.6).good()); + CodeSequenceMacro *water_code = new CodeSequenceMacro("113987", "DCM", "AAPM 220"); + exp_item->getWaterEquivalentDiameterCalculationMethodCodeSequence().push_back(water_code); + OFCHECK(exp_item->setXRayTubeCurrentInMa(0.7).good()); + exp.getCTExposureItems().push_back(exp_item); + } + + FGCTXRayDetails det; + FGCTXRayDetails::FGCTXRayDetailsItem *det_item = new FGCTXRayDetails::FGCTXRayDetailsItem; + if (det_item) + { + OFCHECK(det_item->setCalciumScoringMassFactorDevice(OFVector<Float32>(3, 1)).good()); + OFCHECK(det_item->setCalciumScoringMassFactorPatient(2).good()); + OFCHECK(det_item->setEnergyWeightingFactor(3).good()); + OFCHECK(det_item->setFilterMaterial("FILTER_MATERIAL").good()); + OFCHECK(det_item->setFilterType("FILTER_TYPE").good()); + OFCHECK(det_item->setFocalSpots(OFVector<Float64>(4, 4.4)).good()); + OFCHECK(det_item->setKVP(5.0).good()); + det.getCTXRayDetailsItems().push_back(det_item); + } + + FGPixelValueTransformation trans; + trans.setFGType(FGPixelValueTransformation::E_PixelValTrans_CT); + trans.setRescaleIntercept("0"); + trans.setRescaleSlope("1"); + trans.setRescaleType("HU"); + + FGCTAdditionalXRaySource asrc; + FGCTAdditionalXRaySource::FGCTAdditionalXRaySourceItem *asrc_item = new FGCTAdditionalXRaySource::FGCTAdditionalXRaySourceItem; + if (asrc_item) + { + OFCHECK(asrc_item->setDataCollectionDiameter(1.0).good()); + OFCHECK(asrc_item->setEnergyWeightingFactor(2.0).good()); + OFCHECK(asrc_item->setExposureInmAs(3.0).good()); + OFCHECK(asrc_item->setFilterMaterial("FILTER_MATERIAL").good()); + OFCHECK(asrc_item->setFilterType("FILTER_TYPE").good()); + OFCHECK(asrc_item->setFocalSpots(OFVector<Float64>(4, 4.4)).good()); + OFCHECK(asrc_item->setKVP(5).good()); + OFCHECK(asrc_item->setXRayTubeCurrentInmA(6).good()); + asrc.getCTAdditionalXRaySourceItems().push_back(asrc_item); + } + + OFCHECK(ct->addForAllFrames(meas).good()); + OFCHECK(ct->addForAllFrames(planpo).good()); + OFCHECK(ct->addForAllFrames(planor).good()); + OFCHECK(ct->addForAllFrames(ana).good()); + OFCHECK(ct->addForAllFrames(irr).good()); + OFCHECK(ct->addForAllFrames(itype).good()); + OFCHECK(ct->addForAllFrames(atype).good()); + OFCHECK(ct->addForAllFrames(adetails).good()); + OFCHECK(ct->addForAllFrames(dyn).good()); + OFCHECK(ct->addForAllFrames(pos).good()); + OFCHECK(ct->addForAllFrames(geo).good()); + OFCHECK(ct->addForAllFrames(rec).good()); + OFCHECK(ct->addForAllFrames(exp).good()); + OFCHECK(ct->addForAllFrames(det).good()); + OFCHECK(ct->addForAllFrames(trans).good()); + OFCHECK(ct->addForAllFrames(asrc).good()); +} + +static void addFrames(EctEnhancedCT *ct) +{ + if (!ct) + return; + + FGFrameContent *fg = new FGFrameContent(); + fg->setStackID("1"); + OFCHECK(fg); + if (fg) + { + EctEnhancedCT::FramesType frames = ct->getFrames(); + for (Uint16 frameNo = 1; frameNo <= NUM_FRAMES; frameNo++) + { + OFCHECK(fg->setFrameAcquisitionNumber(frameNo).good()); + OFCHECK(fg->setFrameReferenceDateTime("20190816092557").good()); + OFCHECK(fg->setFrameAcquisitionDateTime("20190816092557").good()); + OFCHECK(fg->setFrameAcquisitionDuration(0.001).good()); + OFCHECK(fg->setInStackPositionNumber(frameNo).good()); + OFCHECK(fg->setDimensionIndexValues(1, 0).good()); + OFCHECK(fg->setDimensionIndexValues(frameNo, 1).good()); + OFVector<FGBase *> groups; + groups.push_back(fg); + + Uint16 *data = new Uint16[NUM_PIXELS_PER_FRAME]; + for (size_t i = 0; i < NUM_PIXELS_PER_FRAME; ++i) + { + data[i] = 0x4141; + } + OFCHECK( + OFget<EctEnhancedCT::Frames<Uint16>>(&frames)->addFrame(data, NUM_PIXELS_PER_FRAME, groups).good()); + delete[] data; + } + } + delete fg; +} + +static void addDimensions(EctEnhancedCT *ct) +{ + if (!ct) + return; + IODMultiframeDimensionModule &dims = ct->getDimensions(); + OFCHECK(dims.addDimensionIndex( + DCM_StackID, "2.25.30855560781715986879861690673941231222", DCM_FrameContentSequence, "STACK_DIM") + .good()); + OFCHECK(dims.addDimensionIndex(DCM_InStackPositionNumber, + "2.25.30855560781715986879861690673941231222", + DCM_FrameContentSequence, + "STACK_DIM") + .good()); + OFunique_ptr<IODMultiframeDimensionModule::DimensionOrganizationItem> org( + new IODMultiframeDimensionModule::DimensionOrganizationItem); + if (org) + { + org->setDimensionOrganizationUID("2.25.30855560781715986879861690673941231222"); + dims.getDimensionOrganizationSequence().push_back(org.release()); + } +} + + diff --git a/dcmect/tests/tests.cc b/dcmect/tests/tests.cc index 54a6ca021..8639dc1ac 100644 --- a/dcmect/tests/tests.cc +++ b/dcmect/tests/tests.cc @@ -1,6 +1,6 @@ /* * - * Copyright (C) 2019, OFFIS e.V. + * Copyright (C) 2019-2024, OFFIS e.V. * All rights reserved. See COPYRIGHT file for details. * * This software and supporting documentation were developed by @@ -23,5 +23,6 @@ #include "dcmtk/ofstd/oftest.h" OFTEST_REGISTER(dcmect_huge_concat); +OFTEST_REGISTER(dcmect_overflow); OFTEST_REGISTER(dcmect_roundtrip); OFTEST_MAIN("dcmect") -- 2.30.2