Skip to content

Commit aa91016

Browse files
author
pierre
committed
Refactor the RLE header to ensure it conforms to the DICOM standard.
1 parent fc9ac24 commit aa91016

File tree

1 file changed

+76
-29
lines changed

1 file changed

+76
-29
lines changed

Source/MediaStorageAndFileFormat/gdcmRLECodec.cxx

Lines changed: 76 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@
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
3435
class RLEHeader
3536
{
37+
private:
38+
uint32_t NumSegments = 0;
39+
uint32_t Offset[15] = {0};
40+
3641
public:
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");
50100
class RLEFrame
51101
{
52102
public:
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

Comments
 (0)