1919#include < ROOT/RFieldBase.hxx>
2020#include < ROOT/RFieldUtils.hxx>
2121#include < ROOT/RFieldVisitor.hxx>
22+ #include < ROOT/RNTupleSerialize.hxx>
2223#include < ROOT/RNTupleUtils.hxx>
2324#include < ROOT/RSpan.hxx>
2425
@@ -1316,18 +1317,29 @@ std::size_t ROOT::RStreamerField::AppendImpl(const void *from)
13161317 [this ](TVirtualStreamerInfo *info) { fStreamerInfos [info->GetNumber ()] = info; });
13171318 fClass ->Streamer (const_cast <void *>(from), buffer);
13181319
1319- auto nbytes = buffer.Length ();
1320+ const auto nbytes = buffer.Length ();
1321+ std::size_t szBufCounts = 0 ;
13201322 R__ASSERT (nbytes >= 0 );
13211323 if (static_cast <std::size_t >(nbytes) > kMaxSmallBuffer ) {
1322- throw RException (R__FAIL (" large objects (>1GiB) not supported by the version 0 streamer field" ));
1324+ const std::uint64_t nCounts = buffer.GetByteCounts ().size ();
1325+ szBufCounts = sizeof (std::uint64_t ) * (2 * nCounts + 1 );
1326+ auto bufCounts = Internal::MakeUninitArray<unsigned char >(szBufCounts);
1327+ std::size_t pos = Internal::RNTupleSerializer::SerializeUInt64 (nCounts, bufCounts.get ());
1328+ for (const auto &[bcountLoc, bcountVal] : buffer.GetByteCounts ()) {
1329+ pos += Internal::RNTupleSerializer::SerializeUInt64 (bcountLoc, bufCounts.get () + pos);
1330+ pos += Internal::RNTupleSerializer::SerializeUInt64 (bcountVal, bufCounts.get () + pos);
1331+ }
1332+ assert (pos == szBufCounts);
1333+ fAuxiliaryColumn ->AppendV (bufCounts.get (), szBufCounts);
1334+ fIndex += szBufCounts;
13231335 } else {
13241336 assert (buffer.GetByteCounts ().empty ());
13251337 }
13261338
13271339 fAuxiliaryColumn ->AppendV (buffer.Buffer (), buffer.Length ());
13281340 fIndex += nbytes;
13291341 fPrincipalColumn ->Append (&fIndex );
1330- return nbytes + fPrincipalColumn ->GetElement ()->GetPackedSize ();
1342+ return szBufCounts + nbytes + fPrincipalColumn ->GetElement ()->GetPackedSize ();
13311343}
13321344
13331345void ROOT::RStreamerField::ReadGlobalImpl (ROOT ::NTupleSize_t globalIndex, void *to)
@@ -1336,10 +1348,47 @@ void ROOT::RStreamerField::ReadGlobalImpl(ROOT::NTupleSize_t globalIndex, void *
13361348 ROOT ::NTupleSize_t nbytes;
13371349 fPrincipalColumn ->GetCollectionInfo (globalIndex, &collectionStart, &nbytes);
13381350
1339- if (nbytes > kMaxSmallBuffer )
1340- throw RException (R__FAIL (" large objects (>1GiB) not supported by the version 0 streamer field" ));
1351+ TBufferFile::ByteCountFinder_t byteCounts;
1352+ if (nbytes > kMaxSmallBuffer ) {
1353+ unsigned char bufNCounts[sizeof (std::uint64_t )];
1354+ fAuxiliaryColumn ->ReadV (collectionStart, sizeof (std::uint64_t ), bufNCounts);
1355+ nbytes -= sizeof (std::uint64_t );
1356+ collectionStart = collectionStart + sizeof (std::uint64_t );
1357+
1358+ std::uint64_t nCounts;
1359+ Internal::RNTupleSerializer::DeserializeUInt64 (bufNCounts, nCounts);
1360+ if (nCounts > (std::numeric_limits<std::size_t >::max () / sizeof (std::uint64_t )) / 2 - 1 )
1361+ throw RException (R__FAIL (" invalid byte count size in streamer field: " + std::to_string (nCounts)));
1362+ const std::size_t szBufCounts = sizeof (std::uint64_t ) * (2 * nCounts);
1363+ if (szBufCounts > nbytes) {
1364+ throw RException (R__FAIL (" invalid byte count size in streamer field: nCounts=" + std::to_string (nCounts) +
1365+ " szBufCounts=" + std::to_string (szBufCounts) + " nbytes=" + std::to_string (nbytes)));
1366+ }
1367+
1368+ auto bufCounts = Internal::MakeUninitArray<unsigned char >(szBufCounts);
1369+ fAuxiliaryColumn ->ReadV (collectionStart, szBufCounts, bufCounts.get ());
1370+ nbytes -= szBufCounts;
1371+ collectionStart = collectionStart + szBufCounts;
1372+
1373+ byteCounts.reserve (nCounts);
1374+ std::size_t pos = 0 ;
1375+ for (std::uint64_t i = 0 ; i < nCounts; ++i) {
1376+ std::uint64_t bcountLoc, bcountVal;
1377+ pos += Internal::RNTupleSerializer::DeserializeUInt64 (bufCounts.get () + pos, bcountLoc);
1378+ pos += Internal::RNTupleSerializer::DeserializeUInt64 (bufCounts.get () + pos, bcountVal);
1379+ if ((bcountLoc > nbytes) || (bcountVal > nbytes) || (nbytes - bcountVal < bcountLoc)) {
1380+ throw RException (
1381+ R__FAIL (" invalid byte count record: " + std::to_string (bcountLoc) + " , " + std::to_string (bcountVal)));
1382+ }
1383+ byteCounts.emplace (bcountLoc, bcountVal);
1384+ }
1385+ assert (pos == szBufCounts);
1386+ if (byteCounts.size () != nCounts)
1387+ throw RException (R__FAIL (" duplicate byte counts" ));
1388+ }
13411389
13421390 TBufferFile buffer (TBuffer::kRead , nbytes);
1391+ buffer.SetByteCounts (std::move (byteCounts));
13431392 fAuxiliaryColumn ->ReadV (collectionStart, nbytes, buffer.Buffer ());
13441393 fClass ->Streamer (to, buffer);
13451394}
0 commit comments