@@ -736,7 +736,7 @@ void CAMIO::ReadBlock(CAMBlock block) {
736736
737737// Helper function to read a uint16_t from the data buffer
738738static uint16_t ReadUInt16 (const std::vector<byte_type>& data, size_t offset) {
739- if ( offset + sizeof (uint16_t ) > data.size () )
739+ if ( ( offset + sizeof (uint16_t ) ) > data.size () )
740740 throw std::out_of_range ( " ReadUInt16: offset " + std::to_string (offset) + " out of range (data size: " + std::to_string (data.size ()) + " )" );
741741
742742 uint16_t value;
@@ -756,6 +756,9 @@ static uint32_t ReadUInt32(const std::vector<byte_type>& data, size_t offset) {
756756
757757// read the geometry block
758758void CAMIO::ReadGeometryBlock (size_t pos, uint16_t records) {
759+ if ( (pos + 0x28 + 2 ) > readData->size () )
760+ throw std::runtime_error ( " Data smaller than geometry block" );
761+
759762 // Get record offset and entry offset
760763 uint16_t commonFlag = ReadUInt16 (*readData, pos + 0x04 );
761764 uint16_t recOffset = commonFlag == 0x700 ? 0 : ReadUInt16 (*readData, pos + 0x22 );
@@ -824,6 +827,9 @@ void CAMIO::ReadGeometryBlock(size_t pos, uint16_t records) {
824827
825828// read the lines block
826829void CAMIO::ReadLinesBlock (size_t pos, uint16_t records) {
830+ if ( (pos + 0x22 + 2 ) > readData->size () )
831+ throw std::runtime_error ( " Data smaller than lines block" );
832+
827833 // Get record offset and size
828834 uint16_t commonFlag = ReadUInt16 (*readData, pos + 0x04 );
829835 uint16_t recOffset = (commonFlag == 0x700 || commonFlag == 0x300 ) ? 0 : ReadUInt16 (*readData, pos + 0x22 );
@@ -854,6 +860,9 @@ void CAMIO::ReadLinesBlock(size_t pos, uint16_t records) {
854860
855861// read the nuclides block
856862void CAMIO::ReadNuclidesBlock (size_t pos, uint16_t records) {
863+ if ( (pos + 0x22 + 2 ) > readData->size () )
864+ throw std::runtime_error ( " Data smaller than nuclides block" );
865+
857866 // Get record offset
858867 uint16_t commonFlag = ReadUInt16 (*readData, pos + 0x04 );
859868 uint16_t recOffset = commonFlag == 0x700 ? 0 : ReadUInt16 (*readData, pos + 0x22 );
@@ -873,6 +882,9 @@ void CAMIO::ReadNuclidesBlock(size_t pos, uint16_t records) {
873882 // Validate we can read the size field
874883 validate_bounds ( *readData, loc, 2 , " ReadNuclidesBlock: reading numLines size field" );
875884
885+ if ( (loc + 2 ) > readData->size () )
886+ throw std::runtime_error ( " Data smaller than nuclide record" );
887+
876888 // Calculate the size of this nuclide record including its lines
877889 // Validate that the size field is reasonable before subtracting
878890 const uint16_t sizeField = ReadUInt16 (*readData, loc);
@@ -913,6 +925,9 @@ void CAMIO::ReadNuclidesBlock(size_t pos, uint16_t records) {
913925
914926// read the peaks block
915927void CAMIO::ReadPeaksBlock (size_t pos, uint16_t records) {
928+ if ( (pos + 0x22 + 2 ) > readData->size () )
929+ throw std::runtime_error ( " Data smaller than peaks block" );
930+
916931 // Get record offset and size
917932 uint16_t commonFlag = ReadUInt16 (*readData, pos + 0x04 );
918933 uint16_t recOffset = commonFlag == 0x700 ? 0 : ReadUInt16 (*readData, pos + 0x22 );
@@ -949,6 +964,9 @@ void CAMIO::ReadPeaksBlock(size_t pos, uint16_t records) {
949964 });
950965 validate_bounds ( *readData, loc, maxOffset, " ReadPeaksBlock: reading peak record" );
951966
967+ if ( (pos + static_cast <uint32_t >(PeakParameterLocation::CriticalLevel) + 4 ) > readData->size () )
968+ throw std::runtime_error ( " Data smaller than peaks record" );
969+
952970 Peak peak{};
953971 peak.Energy = convert_from_CAM_float (*readData, loc + static_cast <uint32_t >(PeakParameterLocation::Energy));
954972 peak.Centroid = convert_from_CAM_float (*readData, loc + static_cast <uint32_t >(PeakParameterLocation::Centroid));
@@ -981,6 +999,9 @@ std::vector<Line>& CAMIO::GetLines() {
981999 for (auto & it = range.first ; it != range.second ; ++it) {
9821000 size_t pos = it->second ;
9831001
1002+ if ( (pos + 0x22 + 2 ) > readData->size () )
1003+ throw std::runtime_error ( " Data smaller than lines pos" );
1004+
9841005 // Get record offset and size
9851006 uint16_t commonFlag = ReadUInt16 (*readData, pos + 0x04 );
9861007 uint16_t recOffset = (commonFlag == 0x700 || commonFlag == 0x300 ) ? 0 : ReadUInt16 (*readData, pos + 0x22 );
@@ -1050,6 +1071,9 @@ std::vector<Nuclide>& CAMIO::GetNuclides() {
10501071 for (auto & it = range.first ; it != range.second ; ++it) {
10511072 size_t pos = it->second ;
10521073
1074+ if ( (pos + 0x22 + 2 ) > readData->size () )
1075+ throw std::runtime_error ( " Data smaller than nuclides pos" );
1076+
10531077 uint16_t recOffset = ReadUInt16 (*readData, pos + 0x04 ) == 0x700 ? 0 : ReadUInt16 (*readData, pos + 0x22 );
10541078 uint16_t recSize = ReadUInt16 (*readData, pos + 0x20 );
10551079 uint16_t numRec = ReadUInt16 (*readData, pos + 0x1E );
@@ -1092,7 +1116,7 @@ std::vector<Nuclide>& CAMIO::GetNuclides() {
10921116
10931117 Nuclide nuc;
10941118 nuc.HalfLife = convert_from_CAM_duration (*readData, loc + 0x1b );
1095- nuc.HalfLifeUncertainty = convert_from_CAM_duration (*readData, loc + 0x89 );
1119+ nuc.HalfLifeUncertainty = convert_from_CAM_duration (*readData, loc + static_cast < uint32_t >(NuclideParameterLocation::HalfLifeUncertainty) );
10961120
10971121 // Read name (8 characters)
10981122 char nameBuf[9 ] = {0 };
@@ -1154,7 +1178,10 @@ std::vector<Peak>& CAMIO::GetPeaks() {
11541178 for (auto & it = range.first ; it != range.second ; ++it) {
11551179 size_t pos = it->second ;
11561180
1157- uint16_t recOffset = ReadUInt16 (*readData, pos + 0x04 ) == 0x700 || secondBlock ?
1181+ if ( (pos + 0x22 + 2 ) > readData->size () )
1182+ throw std::runtime_error ( " Data smaller than peaks pos" );
1183+
1184+ uint16_t recOffset = ReadUInt16 (*readData, pos + 0x04 ) == 0x700 || secondBlock ?
11581185 0 : ReadUInt16 (*readData, pos + 0x22 );
11591186 uint16_t recSize = ReadUInt16 (*readData, pos + 0x20 );
11601187 uint16_t numRec = ReadUInt16 (*readData, pos + 0x1E );
@@ -1187,6 +1214,9 @@ std::vector<Peak>& CAMIO::GetPeaks() {
11871214 });
11881215 validate_bounds ( *readData, loc, maxOffset, " GetPeaks: reading peak record" );
11891216
1217+ if ( (pos + static_cast <uint32_t >(PeakParameterLocation::CriticalLevel) + 4 ) > readData->size () )
1218+ throw std::runtime_error ( " Data smaller than peaks record" );
1219+
11901220 Peak peak{};
11911221 peak.Energy = convert_from_CAM_float (*readData, loc + static_cast <uint32_t >(PeakParameterLocation::Energy));
11921222 peak.Centroid = convert_from_CAM_float (*readData, loc + static_cast <uint32_t >(PeakParameterLocation::Centroid));
@@ -1220,6 +1250,9 @@ std::vector<uint32_t>& CAMIO::GetSpectrum() {
12201250 for (auto & it = range.first ; it != range.second ; ++it) {
12211251 size_t pos = it->second ;
12221252
1253+ if ( (pos + 0x2A + 2 ) > readData->size () )
1254+ throw std::runtime_error ( " Data smaller than spectrum pos" );
1255+
12231256 // Get number of channels
12241257 uint16_t channels = ReadUInt16 (*readData, pos + 0x2A );
12251258 uint16_t headerOffset = ReadUInt16 (*readData, pos + 0x10 );
@@ -1234,6 +1267,9 @@ std::vector<uint32_t>& CAMIO::GetSpectrum() {
12341267 // Resize spectrum vector to accommodate all channels
12351268 fileSpectrum.resize (channels);
12361269
1270+ if ( (pos + dataOffset + headerOffset + channels*4 ) > readData->size () )
1271+ throw std::runtime_error ( " Data smaller than spectrum data" );
1272+
12371273 // Read channel data
12381274 for (size_t i = 0 ; i < channels; i++) {
12391275 uint32_t value;
@@ -1254,6 +1290,7 @@ std::string CAMIO::GetSampleTitle()
12541290
12551291 for (auto & it = range.first ; it != range.second ; ++it) {
12561292 size_t pos = it->second ;
1293+
12571294 uint16_t headSize = ReadUInt16 (*readData, pos + 0x10 );
12581295
12591296 // Validate we can read the sample title (64 bytes)
@@ -1363,6 +1400,7 @@ SpecUtils::time_point_t CAMIO::GetAquisitionTime() {
13631400
13641401 for (auto & it = range.first ; it != range.second ; ++it) {
13651402 size_t pos = it->second ;
1403+
13661404 uint16_t headSize = ReadUInt16 (*readData, pos + 0x10 );
13671405 uint16_t timeOffset = ReadUInt16 (*readData, pos + 0x24 );
13681406
@@ -1731,7 +1769,7 @@ void CAMIO::AddLineAndNuclide(const float energy, const float yield,
17311769 float t12Unc = (halfLifeUnc < size_t (0 )) ? ComputeUncertainty (halfLife) : halfLifeUnc;
17321770
17331771
1734- int nucNo = writeNuclides.size () + 1 ;
1772+ int nucNo = static_cast < int >( writeNuclides.size () + 1 ) ;
17351773 // TODO try this out without this helper vector
17361774 Nuclide nuc (name, halfLife, t12Unc, halfLifeUnit, nucNo );
17371775
@@ -2205,11 +2243,18 @@ std::vector<byte_type> CAMIO::GenerateBlockHeader(CAMBlock block, size_t loc, ui
22052243 0x03E6 , // 0x28 16 Addresss of entries in block
22062244 0x0009 , // 0x2A 17 Always 9
22072245 0x0000 , // 0x2C 18
2208- static_cast <uint16_t >(values[ 4 ] + values[ 11 ] * values[ 12 ] + values[ 13 ] ) // 0x2E 19 Computed size of block
2209- };
2246+ static_cast <uint16_t >(sec_header_length + numRec * static_cast < uint16_t >(RecordSize::ACQP) + 0x02EA ) // 0x2E 19 Computed size of block
2247+ };
22102248 std::vector<uint16_t > temp = { values[4 ] , values[11 ] , values[12 ] , values[13 ] , values[17 ]};
22112249 // Modify values based on block type
22122250 switch (block) {
2251+ case CAMBlock::ACQP:
2252+ case CAMBlock::GEOM:
2253+ case CAMBlock::DISP:
2254+ case CAMBlock::PEAK:
2255+ // No action
2256+ break ;
2257+
22132258 case CAMBlock::PROC:
22142259 values[0 ] = 0x0100 ;
22152260 values[1 ] = static_cast <uint16_t >(BlockSize::PROC);
@@ -2331,7 +2376,7 @@ std::vector<byte_type> CAMIO::GenerateBlockHeader(CAMBlock block, size_t loc, ui
23312376 }
23322377 break ;
23332378
2334-
2379+
23352380 }
23362381
23372382 // Copy in the block code
0 commit comments