2424#include < cstddef> // ptrdiff_t fix
2525#include < cstring>
2626#include < vector>
27+ #include < array>
2728
2829#include < gdcmrle/rle.h>
2930
@@ -33,37 +34,75 @@ namespace gdcm
3334// TODO ideally this code should be in utilities for ease of reuse
3435class RLEHeader
3536{
37+ private:
38+ uint32_t NumSegments = 0 ;
39+ uint32_t Offset[15 ] = {0 };
40+
3641public:
37- uint32_t NumSegments;
38- uint32_t Offset[15 ];
42+ uint32_t GetNumSegments () const { return NumSegments; }
43+ bool SetNumSegments (uint32_t num)
44+ {
45+ if (num > 15 )
46+ {
47+ gdcmErrorMacro (" Number of segments cannot be bigger than 15" );
48+ return false ;
49+ }
50+ NumSegments = num;
51+ return true ;
52+ };
53+ bool SetOffset (const std::array<uint32_t , 15 > &offset)
54+ {
55+ std::copy (offset.begin (), offset.end (), Offset);
56+ return true ;
57+ };
58+ uint32_t GetOffset (size_t index) const
59+ {
60+ if (index < 15 ) return Offset[index];
61+ return 0 ;
62+ };
63+ bool SetOffset (size_t index, uint32_t value) {
64+ if (index >= 15 ) return false ;
3965
40- void Print (std::ostream &os)
66+ Offset[index] = value;
67+ return true ;
68+ }
69+
70+ bool Read (std::istream &is)
4171 {
42- os << " NumSegments:" << NumSegments << " \n " ;
43- for (int i=0 ; i<15 ; ++i)
44- {
45- os << i << " :" << Offset[i] << " \n " ;
72+ // read Header (64 bytes)
73+ uint32_t buffer[16 ] = {0 };
74+ is.read (reinterpret_cast <char *>(buffer), 64 );
75+ if (static_cast <size_t >(is.gcount ()) != 64 )
76+ {
77+ gdcmErrorMacro (" RLE Header truncated: expected 64 bytes, got " << is.gcount ());
78+ return false ;
79+ }
80+ gdcm_assert (sizeof (uint32_t ) * 16 == 64 );
81+ SwapperNoOp::SwapArray (reinterpret_cast <uint32_t *>(buffer), 16 );
82+ if (!SetNumSegments (buffer[0 ])) return false ;
83+ memcpy (Offset, &buffer[1 ], sizeof (uint32_t ) * 15 );
84+ if (NumSegments >= 1 ) {
85+ if (Offset[0 ] != 64 ) return false ;
86+ }
87+ // We just check that we are indeed at the proper position start+64
88+ return true ;
89+ }
90+ void Print (std::ostream &os)
91+ {
92+ os << " NumSegments:" << NumSegments << " \n " ;
93+ for (int i = 0 ; i < 15 ; ++i) {
94+ os << i << " :" << Offset[i] << " \n " ;
4695 }
4796 }
48- };
4997
98+ };
99+ static_assert (sizeof (RLEHeader) == 64 , " RLEHeader size must be 64 bits to comply with dicom standard" );
50100class RLEFrame
51101{
52102public:
53103 bool Read (std::istream &is)
54104 {
55- // read Header (64 bytes)
56- is.read ((char *)(&Header), sizeof (uint32_t )*16 );
57- gdcm_assert ( sizeof (uint32_t )*16 == 64 );
58- gdcm_assert ( sizeof (RLEHeader) == 64 );
59- SwapperNoOp::SwapArray ((uint32_t *)&Header,16 );
60- uint32_t numSegments = Header.NumSegments ;
61- if ( numSegments >= 1 )
62- {
63- if ( Header.Offset [0 ] != 64 ) return false ;
64- }
65- // We just check that we are indeed at the proper position start+64
66- return true ;
105+ return Header.Read (is);
67106 }
68107 void Print (std::ostream &os)
69108 {
@@ -379,7 +418,9 @@ bool RLECodec::Code(DataElement const &in, DataElement &out)
379418 gdcm_assert ( MaxNumSegments % 3 == 0 );
380419 }
381420
382- RLEHeader header = { static_cast <uint32_t > ( MaxNumSegments ), { 64 } };
421+ RLEHeader header;
422+ header.SetNumSegments (static_cast <uint32_t >(MaxNumSegments));
423+ header.SetOffset ({64 });
383424 // there cannot be any space in between the end of the RLE header and the start
384425 // of the first RLE segment
385426 //
@@ -521,12 +562,12 @@ bool RLECodec::Code(DataElement const &in, DataElement &out)
521562 length += llength;
522563 }
523564 // update header
524- header.Offset [ 1 + seg] = (uint32_t )(header.Offset [ seg] + length);
565+ header.SetOffset ( 1 + seg, (uint32_t )(header.GetOffset ( seg) + length) );
525566
526567 gdcm_assert ( data.str ().size () == length );
527568 datastr += data.str ();
528569 }
529- header.Offset [ MaxNumSegments] = 0 ;
570+ header.SetOffset ( MaxNumSegments, 0 ) ;
530571 std::stringstream os;
531572 // header.Print( std::cout );
532573 os.write ((char *)&header,sizeof (header));
@@ -769,7 +810,7 @@ bool RLECodec::DecodeByStreams(std::istream &is, std::ostream &os)
769810 RLEFrame &frame = Internals->Frame ;
770811 if ( !frame.Read (is) )
771812 return false ;
772- unsigned long numSegments = frame.Header .NumSegments ;
813+ unsigned long numSegments = frame.Header .GetNumSegments () ;
773814
774815 unsigned long length = Length;
775816 gdcm_assert ( length );
@@ -801,18 +842,24 @@ bool RLECodec::DecodeByStreams(std::istream &is, std::ostream &os)
801842 {
802843 unsigned long numberOfReadBytes = 0 ;
803844 std::streampos pos = is.tellg () - start;
804- if ( frame.Header .Offset [i] - pos != 0 )
845+ if (frame.Header .GetOffset (i) > BufferLength)
846+ {
847+ gdcmErrorMacro (" Offset is bigger then buffer Length" );
848+ return false ;
849+ }
850+
851+ if ( frame.Header .GetOffset (i) - pos != 0 )
805852 {
806853 // ACUSON-24-YBR_FULL-RLE.dcm
807854 // D_CLUNIE_CT1_RLE.dcm
808855 // This should be at most the \0 padding
809856 // gdcmWarningMacro( "RLE Header says: " << frame.Header.Offset[i] <<
810857 // " when it should says: " << pos << std::endl );
811- std::streamoff check = frame.Header .Offset [i] - pos;// should it be a streampos or a uint32? mmr
858+ std::streamoff check = frame.Header .GetOffset (i) - pos;// should it be a streampos or a uint32? mmr
812859 // check == 2 for gdcmDataExtra/gdcmSampleData/US_DataSet/GE_US/2929J686-breaker
813860 // gdcm_assert( check == 1 || check == 2);
814861 (void )check; // warning removal
815- is.seekg ( frame.Header .Offset [i] + start, std::ios::beg );
862+ is.seekg (frame.Header .GetOffset (i) + start, std::ios::beg);
816863 }
817864
818865 unsigned long numOutBytes = 0 ;
@@ -865,8 +912,8 @@ bool RLECodec::GetHeaderInfo(std::istream &is, TransferSyntax &ts)
865912 return false ;
866913 // numsegments = num_comp * bpp / 8;
867914 // numsegments >0 && numsegments <= 12
868- uint32_t bytespercomp = frame.Header .NumSegments ;
869- if ( frame.Header .NumSegments % 3 == 0 )
915+ uint32_t bytespercomp = frame.Header .GetNumSegments () ;
916+ if ( frame.Header .GetNumSegments () % 3 == 0 )
870917 {
871918 PI = PhotometricInterpretation::RGB;
872919 PlanarConfiguration = 1 ;
0 commit comments