GRSISort "v4.0.0.5"
An extension of the ROOT analysis Framework
Loading...
Searching...
No Matches
TMidasEvent.cxx
Go to the documentation of this file.
1//
2// TMidasEvent.cxx.
3//
4// $Id: TMidasEvent.cxx 91 2012-04-12 18:36:17Z olchansk $
5//
6
7#include <cstdio>
8#include <cstdlib>
9#include <ctime>
10#include <cstring>
11#include <cassert>
12
13#include "TMidasEvent.h"
14
16 : fData(nullptr), fBanksN(0), fBankList(nullptr), fAllocatedByUs(false)
17{
18 // Default constructor
24}
25
26void TMidasEvent::Copy(TObject& rhs) const
27{
28 // Copies the entire TMidasEvent. This includes the bank information.
29 static_cast<TMidasEvent&>(rhs).fEventHeader = fEventHeader;
30
31 static_cast<TMidasEvent&>(rhs).fData = static_cast<char*>(malloc(static_cast<TMidasEvent&>(rhs).fEventHeader.fDataSize)); // NOLINT(cppcoreguidelines-no-malloc)
32 assert(static_cast<TMidasEvent&>(rhs).fData);
33 memcpy(static_cast<TMidasEvent&>(rhs).fData, fData, static_cast<TMidasEvent&>(rhs).fEventHeader.fDataSize);
34 static_cast<TMidasEvent&>(rhs).fAllocatedByUs = true;
35
36 static_cast<TMidasEvent&>(rhs).fBanksN = fBanksN;
37 static_cast<TMidasEvent&>(rhs).fBankList = nullptr;
38}
39
41{
42 // Copy ctor.
43 rhs.Copy(*this);
44}
45
50
52{
53 if(&rhs != this) {
54 Clear();
55 }
56
57 rhs.Copy(*this);
58 return *this;
59}
60
61void TMidasEvent::Clear(Option_t*)
62{
63 // Clears the TMidasEvent.
64 std::free(fBankList);
65 fBankList = nullptr;
66
67 if(fAllocatedByUs) {
68 std::free(fData);
69 }
70 fData = nullptr;
71
72 fAllocatedByUs = false;
73 fBanksN = 0;
74
80
82}
83
84void TMidasEvent::SetData(uint32_t size, char* data)
85{
86 // Sets the data in the TMidasEvent as the data argument passed into
87 // this function.
89 assert(!fAllocatedByUs);
90 assert(IsGoodSize());
91 fData = data;
92 fAllocatedByUs = false;
93 SwapBytes(false);
94}
95
97{
99}
100
102{
104}
105
107{
109}
110
112{
114}
115
117{
118 return fEventHeader.fDataSize;
119}
120
122{
123 // Allocates the data if it has not been already, and then
124 // returns the allocated data.
125 if(fData == nullptr) {
126 AllocateData();
127 }
128 return fData;
129}
130
135
137{
138 return fEventHeader.fDataSize > 0 && fEventHeader.fDataSize <= 500 * 1024 * 1024;
139}
140
142{
143 return ((reinterpret_cast<TMidas_BANK_HEADER*>(fData))->fFlags & (1 << 4)) != 0u;
144}
145
146int TMidasEvent::LocateBank(const void*, const char* name, void** pdata) const
147{
148 /// See FindBank()
149
150 int bktype = 0;
151 int bklen = 0;
152
153 int status = FindBank(name, &bklen, &bktype, pdata);
154
155 if(status == 0) {
156 *pdata = nullptr;
157 return 0;
158 }
159
160 return bklen;
161}
162
163/// Find a data bank.
164/// \param [in] name Name of the data bank to look for.
165/// \param [out] bklen Number of array elements in this bank.
166/// \param [out] bktype Bank data type (MIDAS TID_xxx).
167/// \param [out] pdata Pointer to bank data, Returns nullptr if bank not found.
168/// \returns 1 if bank found, 0 otherwise.
169///
170int TMidasEvent::FindBank(const char* name, int* bklen, int* bktype, void** pdata) const
171{
172 auto* pbkh = reinterpret_cast<TMidas_BANK_HEADER*>(fData);
173 TMidas_BANK* pbk = nullptr;
174
175 std::array<unsigned, 17> TID_SIZE = {0, 1, 1, 1, 2, 2, 4, 4, 4, 4, 8, 1, 0, 0, 0, 0, 0};
176
177 if(((pbkh->fFlags & (1 << 4)) > 0)) {
178 TMidas_BANK32* pbk32 = nullptr;
179
180 while(true) {
181 IterateBank32(&pbk32, reinterpret_cast<char**>(pdata));
182 if(pbk32 == nullptr) {
183 break;
184 }
185
186 if(name[0] == pbk32->fName[0] && name[1] == pbk32->fName[1] && name[2] == pbk32->fName[2] &&
187 name[3] == pbk32->fName[3]) {
188
189 if(TID_SIZE[pbk32->fType & 0xFF] == 0) {
190 *bklen = pbk32->fDataSize;
191 } else {
192 *bklen = pbk32->fDataSize / TID_SIZE[pbk32->fType & 0xFF];
193 }
194
195 *bktype = pbk32->fType;
196 return 1;
197 }
198 }
199 } else {
200 pbk = reinterpret_cast<TMidas_BANK*>(pbkh + 1);
201 do {
202 if(name[0] == pbk->fName[0] && name[1] == pbk->fName[1] && name[2] == pbk->fName[2] &&
203 name[3] == pbk->fName[3]) {
204 *pdata = pbk + 1;
205 if(TID_SIZE[pbk->fType & 0xFF] == 0) {
206 *bklen = pbk->fDataSize;
207 } else {
208 *bklen = pbk->fDataSize / TID_SIZE[pbk->fType & 0xFF];
209 }
210
211 *bktype = pbk->fType;
212 return 1;
213 }
214 pbk = reinterpret_cast<TMidas_BANK*>(reinterpret_cast<char*>(pbk + 1) + (((pbk->fDataSize) + 7) & ~7));
215 } while(reinterpret_cast<char*>(pbk) < reinterpret_cast<char*>(pbkh) + pbkh->fDataSize + sizeof(TMidas_BANK_HEADER));
216 }
217 //
218 // bank not found
219 //
220 *pdata = nullptr;
221 return 0;
222}
223
224void TMidasEvent::Print(const char* option) const
225{
226 /// Print data held in this class.
227 /// \param [in] option If 'a' (for "all") then the raw data will be
228 /// printed out too.
229 ///
230
231 auto t = static_cast<time_t>(fEventHeader.fTimeStamp);
232
233 std::cout << "Event start:" << std::endl;
234 std::cout << " event id: " << hex(fEventHeader.fEventId, 4) << std::endl;
235 std::cout << " trigger mask: " << hex(fEventHeader.fTriggerMask, 4) << std::endl;
236 std::cout << " serial number: " << fEventHeader.fSerialNumber << std::endl;
237 std::cout << " time stamp: " << fEventHeader.fTimeStamp << ", " << ctime(&t) << std::endl;
238 std::cout << " data size: " << std::setw(8) << fEventHeader.fDataSize << std::endl;
239 // const_cast<TMidasEvent*>(this)->SetBankList(); // moved here to get event information in case SetBankList crashes
240 if((fEventHeader.fEventId & 0xffff) == 0x8000) {
241 std::cout << "Begin of run " << fEventHeader.fSerialNumber << std::endl;
242 } else if((fEventHeader.fEventId & 0xffff) == 0x8001) {
243 std::cout << "End of run " << fEventHeader.fSerialNumber << std::endl;
244 } else if((fEventHeader.fEventId & 0xffff) == 0x8002) {
245 std::cout << "Message event \"" << fData << "\"" << std::endl;
246 } else if(fBanksN <= 0) {
247 std::cout << "TMidasEvent::Print: Use SetBankList() before Print() to print bank data" << std::endl;
248 } else {
249 std::cout << "Banks: " << fBankList << std::endl;
250
251 for(int i = 0; i < fBanksN * 4; i += 4) {
252 int bankLength = 0;
253 int bankType = 0;
254 void* pdata = nullptr;
255 int found = FindBank(&fBankList[i], &bankLength, &bankType, &pdata);
256
257 std::cout << "Bank " << fBankList[i] << fBankList[i + 1] << fBankList[i + 2] << fBankList[i + 3] << ", length " << std::setw(6) << bankLength << ", type " << bankType << std::endl;
258
259 int highlight = -1;
260 if(strlen(option) > 1) {
261 highlight = atoi(option + 1);
262 }
263
264 if(option[0] == 'a' && (found != 0)) {
265 switch(bankType) {
266 case 4: // TID_WORD
267 for(int j = 0; j < bankLength; j++) {
268 if(j == highlight) {
269 std::cout << ALERTTEXT << hex((reinterpret_cast<uint16_t*>(pdata))[j], 4) << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
270 } else {
271 std::cout << hex((reinterpret_cast<uint16_t*>(pdata))[j], 4) << ((j % 10 == 9) ? '\n' : ' ');
272 }
273 }
274 std::cout << std::endl;
275 break;
276 case 6: // TID_DWORD
277 for(int j = 0; j < bankLength; j++) {
278 if(j == highlight) {
279 std::cout << ALERTTEXT << hex((reinterpret_cast<uint32_t*>(pdata))[j], 8) << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
280 } else {
281 std::cout << hex((reinterpret_cast<uint32_t*>(pdata))[j], 8) << ((j % 10 == 9) ? '\n' : ' ');
282 }
283 }
284 std::cout << std::endl;
285 break;
286 case 7: // TID_nd280 (like a DWORD?)
287 for(int j = 0; j < bankLength; j++) {
288 if(j == highlight) {
289 std::cout << ALERTTEXT << hex((reinterpret_cast<uint32_t*>(pdata))[j], 8) << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
290 } else {
291 std::cout << hex((reinterpret_cast<uint32_t*>(pdata))[j], 8) << ((j % 10 == 9) ? '\n' : ' ');
292 }
293 }
294 std::cout << std::endl;
295 break;
296 case 9: // TID_FLOAT
297 for(int j = 0; j < bankLength; j++) {
298 if(j == highlight) {
299 std::cout << ALERTTEXT << (reinterpret_cast<float*>(pdata))[j] << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
300 } else {
301 std::cout << (reinterpret_cast<float*>(pdata))[j] << ((j % 10 == 9) ? '\n' : ' ');
302 }
303 }
304 std::cout << std::endl;
305 break;
306 case 10: // TID_DOUBLE
307 for(int j = 0; j < bankLength; j++) {
308 if(j == highlight) {
309 std::cout << ALERTTEXT << (reinterpret_cast<double*>(pdata))[j] << RESET_COLOR << ((j % 10 == 9) ? '\n' : ' ');
310 } else {
311 std::cout << (reinterpret_cast<double*>(pdata))[j] << ((j % 10 == 9) ? '\n' : ' ');
312 }
313 }
314 std::cout << std::endl;
315 break;
316 default:
317 std::cout << "TMidasEvent::Print: Do not know how to print bank of type " << bankType << std::endl;
318 break;
319 }
320 }
321 }
322 }
323}
324
326{
327 // Allocates space for the data from the event header if it is a good size
328 assert(!fAllocatedByUs);
329 assert(IsGoodSize());
330 fData = reinterpret_cast<char*>(malloc(fEventHeader.fDataSize)); // NOLINT(cppcoreguidelines-no-malloc)
331 assert(fData);
332 fAllocatedByUs = true;
333}
334
335const char* TMidasEvent::GetBankList() const
336{
337 return fBankList;
338}
339
341{
342 // Sets the bank list by Iterating of the banks.
343 // See IterateBank32 and IterateBank
344 if(fEventHeader.fEventId <= 0) {
345 return 0;
346 }
347
348 if(fBankList != nullptr) {
349 return fBanksN;
350 }
351
352 int listSize = 0;
353
354 fBanksN = 0;
355
356 TMidas_BANK32* pmbk32 = nullptr;
357 TMidas_BANK* pmbk = nullptr;
358 char* pdata = nullptr;
359
360 while(true) {
361 if(fBanksN * 4 >= listSize) {
362 listSize += 400;
363 fBankList = reinterpret_cast<char*>(realloc(fBankList, listSize)); // NOLINT(cppcoreguidelines-no-malloc)
364 }
365
366 if(IsBank32()) {
367 IterateBank32(&pmbk32, &pdata);
368 if(pmbk32 == nullptr) {
369 break;
370 }
371 memcpy(fBankList + fBanksN * 4, pmbk32->fName, 4); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
372 fBanksN++;
373 } else {
374 IterateBank(&pmbk, &pdata);
375 if(pmbk == nullptr) {
376 break;
377 }
378 memcpy(fBankList + fBanksN * 4, pmbk->fName, 4); // NOLINT(cppcoreguidelines-pro-bounds-array-to-pointer-decay)
379 fBanksN++;
380 }
381 }
382
383 fBankList[fBanksN * 4] = 0;
384
385 return fBanksN;
386}
387
388int TMidasEvent::IterateBank(TMidas_BANK** pbk, char** pdata) const
389{
390 /// Iterates through banks inside an event. The function can be used
391 /// to enumerate all banks of an event.
392 /// \param [in] pbk Pointer to the bank header, must be nullptr for the
393 /// first call to this function. Returns nullptr if no more banks
394 /// \param [in] pdata Pointer to data area of bank. Returns nullptr if no more banks
395 /// \returns Size of bank in bytes or 0 if no more banks.
396 ///
397 auto* event = reinterpret_cast<TMidas_BANK_HEADER*>(fData);
398
399 if(*pbk == nullptr) {
400 *pbk = reinterpret_cast<TMidas_BANK*>(event + 1);
401 } else {
402 *pbk = reinterpret_cast<TMidas_BANK*>(reinterpret_cast<char*>(*pbk + 1) + ((((*pbk)->fDataSize) + 7) & ~7));
403 }
404
405 *pdata = reinterpret_cast<char*>((*pbk) + 1);
406
407 if(reinterpret_cast<char*>(*pbk) >=
408 reinterpret_cast<char*>(event) + event->fDataSize + sizeof(TMidas_BANK_HEADER)) {
409 *pbk = nullptr;
410 *pdata = nullptr;
411 return 0;
412 }
413
414 return (*pbk)->fDataSize;
415}
416
417int TMidasEvent::IterateBank32(TMidas_BANK32** pbk, char** pdata) const
418{
419 /// See IterateBank()
420
421 auto* event = reinterpret_cast<TMidas_BANK_HEADER*>(fData);
422 if(*pbk == nullptr) {
423 *pbk = reinterpret_cast<TMidas_BANK32*>(event + 1);
424 } else {
425 uint32_t length = (*pbk)->fDataSize;
426 uint32_t length_adjusted = (length + 7) & ~7;
427 *pbk = reinterpret_cast<TMidas_BANK32*>(reinterpret_cast<char*>(*pbk + 1) + length_adjusted);
428 }
429
430 auto* bk4 = reinterpret_cast<TMidas_BANK32*>((reinterpret_cast<char*>(*pbk)) + 4);
431
432 if((*pbk)->fType > 17) { // bad - unknown bank type - it's invalid MIDAS file?
433 if(bk4->fType <= 17) { // okey, this is a malformed T2K/ND280 data file
434 *pbk = bk4;
435 } else {
436 // truncate invalid data
437 *pbk = nullptr;
438 *pdata = nullptr;
439 return 0;
440 }
441 }
442
443 *pdata = reinterpret_cast<char*>((*pbk) + 1);
444
445 if(reinterpret_cast<char*>(*pbk) >= reinterpret_cast<char*>(event) + event->fDataSize + sizeof(TMidas_BANK_HEADER)) {
446 *pbk = nullptr;
447 *pdata = nullptr;
448 return 0;
449 }
450
451 return (*pbk)->fDataSize;
452}
453
454using BYTE = uint8_t;
455
456// NOLINTBEGIN(cppcoreguidelines-macro-usage, cppcoreguidelines-pro-type-cstyle-cast)
457/// Byte swapping routine.
458///
459#define QWORD_SWAP(x) \
460 { \
461 BYTE _tmp; \
462 _tmp = *((BYTE*)(x)); \
463 *((BYTE*)(x)) = *(((BYTE*)(x)) + 7); \
464 *(((BYTE*)(x)) + 7) = _tmp; \
465 _tmp = *(((BYTE*)(x)) + 1); \
466 *(((BYTE*)(x)) + 1) = *(((BYTE*)(x)) + 6); \
467 *(((BYTE*)(x)) + 6) = _tmp; \
468 _tmp = *(((BYTE*)(x)) + 2); \
469 *(((BYTE*)(x)) + 2) = *(((BYTE*)(x)) + 5); \
470 *(((BYTE*)(x)) + 5) = _tmp; \
471 _tmp = *(((BYTE*)(x)) + 3); \
472 *(((BYTE*)(x)) + 3) = *(((BYTE*)(x)) + 4); \
473 *(((BYTE*)(x)) + 4) = _tmp; \
474 }
475
476/// Byte swapping routine.
477///
478#define DWORD_SWAP(x) \
479 { \
480 BYTE _tmp; \
481 _tmp = *((BYTE*)(x)); \
482 *((BYTE*)(x)) = *(((BYTE*)(x)) + 3); \
483 *(((BYTE*)(x)) + 3) = _tmp; \
484 _tmp = *(((BYTE*)(x)) + 1); \
485 *(((BYTE*)(x)) + 1) = *(((BYTE*)(x)) + 2); \
486 *(((BYTE*)(x)) + 2) = _tmp; \
487 }
488
489/// Byte swapping routine.
490///
491#define WORD_SWAP(x) \
492 { \
493 BYTE _tmp; \
494 _tmp = *((BYTE*)(x)); \
495 *((BYTE*)(x)) = *(((BYTE*)(x)) + 1); \
496 *(((BYTE*)(x)) + 1) = _tmp; \
497 }
498// NOLINTEND(cppcoreguidelines-macro-usage, cppcoreguidelines-pro-type-cstyle-cast)
499
509
511{
512 // Swaps bytes for endian-ness reasons
513 TMidas_BANK_HEADER* pbh = nullptr;
514 TMidas_BANK* pbk = nullptr;
515 TMidas_BANK32* pbk32 = nullptr;
516 void* pdata = nullptr;
517 uint16_t type = 0;
518
519 pbh = reinterpret_cast<TMidas_BANK_HEADER*>(fData);
520
521 uint32_t dssw = pbh->fDataSize;
522
523 DWORD_SWAP(&dssw);
524
525 // only swap if flags in high 16-bit
526 //
527 if(pbh->fFlags < 0x10000 && !force) {
528 return 0;
529 }
530
531 if(pbh->fDataSize == 0x6d783f3c) { // string "<xml..." in wrong-endian format
532 return 1;
533 }
534
535 if(pbh->fDataSize == 0x3c3f786d) { // string "<xml..."
536 return 1;
537 }
538
539 if(dssw > fEventHeader.fDataSize + 100) { // swapped data size looks wrong. do not swap.
540 return 1;
541 }
542
543 //
544 // swap bank header
545 //
546 DWORD_SWAP(&pbh->fDataSize);
547 DWORD_SWAP(&pbh->fFlags);
548 //
549 // check for 32-bit banks
550 //
551 bool b32 = IsBank32();
552
553 pbk = reinterpret_cast<TMidas_BANK*>(pbh + 1);
554 pbk32 = reinterpret_cast<TMidas_BANK32*>(pbk);
555 //
556 // scan event
557 //
558 while(reinterpret_cast<char*>(pbk) < reinterpret_cast<char*>(pbh) + pbh->fDataSize + sizeof(TMidas_BANK_HEADER)) {
559 //
560 // swap bank header
561 //
562 if(b32) {
563 DWORD_SWAP(&pbk32->fType);
564 DWORD_SWAP(&pbk32->fDataSize);
565 pdata = pbk32 + 1;
566 type = static_cast<uint16_t>(pbk32->fType);
567 } else {
568 WORD_SWAP(&pbk->fType);
569 WORD_SWAP(&pbk->fDataSize);
570 pdata = pbk + 1;
571 type = pbk->fType;
572 }
573 //
574 // pbk points to next bank
575 //
576 if(b32) {
577 assert(pbk32->fDataSize < fEventHeader.fDataSize + 100);
578 pbk32 = reinterpret_cast<TMidas_BANK32*>(reinterpret_cast<char*>(pbk32 + 1) + (((pbk32->fDataSize) + 7) & ~7));
579 pbk = reinterpret_cast<TMidas_BANK*>(pbk32);
580 } else {
581 assert(pbk->fDataSize < fEventHeader.fDataSize + 100);
582 pbk = reinterpret_cast<TMidas_BANK*>(reinterpret_cast<char*>(pbk + 1) + (((pbk->fDataSize) + 7) & ~7));
583 pbk32 = reinterpret_cast<TMidas_BANK32*>(pbk);
584 }
585
586 switch(type) {
587 case 4:
588 case 5:
589 while(pdata < pbk) {
590 WORD_SWAP(pdata);
591 pdata = (reinterpret_cast<char*>(pdata)) + 2;
592 }
593 break;
594 case 6:
595 case 7:
596 case 8:
597 case 9:
598 while(pdata < pbk) {
599 DWORD_SWAP(pdata);
600 pdata = (reinterpret_cast<char*>(pdata)) + 4;
601 }
602 break;
603 case 10:
604 while(pdata < pbk) {
605 QWORD_SWAP(pdata);
606 pdata = (reinterpret_cast<char*>(pdata)) + 8;
607 }
608 break;
609 }
610 }
611 return 1;
612}
std::string hex(T val, int width=-1)
Definition Globals.h:129
#define RESET_COLOR
Definition Globals.h:5
uint8_t BYTE
#define WORD_SWAP(x)
#define QWORD_SWAP(x)
#define DWORD_SWAP(x)
MIDAS event.
Definition TMidasEvent.h:35
bool IsBank32() const
returns "true" if event uses 32-bit banks
int IterateBank32(TMidas_BANK32 **, char **pdata) const
iterate through 32-bit data banks
TMidas_EVENT_HEADER * GetEventHeader()
return pointer to the event header
int fBanksN
number of banks in this event
Definition TMidasEvent.h:85
int SetBankList()
create the list of data banks, return number of banks
void SetData(uint32_t size, char *data)
set an externally allocated data buffer
void Clear(Option_t *opt="") override
clear event for reuse
char * GetData() override
return pointer to the data buffer
void AllocateData()
allocate data buffer using the existing event header
const char * GetBankList() const
return a list of data banks
int IterateBank(TMidas_BANK **, char **pdata) const
iterate through 16-bit data banks
uint16_t GetEventId() const
return the event id
void Print(const char *option="") const override
show all event information
~TMidasEvent() override
destructor
uint32_t GetTimeStamp() const override
return the time stamp (unix time in seconds)
int FindBank(const char *name, int *bklen, int *bktype, void **pdata) const
TMidasEvent()
default constructor
TMidasEvent & operator=(const TMidasEvent &)
assignement operator
bool fAllocatedByUs
"true" if we own the data buffer
Definition TMidasEvent.h:87
int LocateBank(const void *unused, const char *name, void **pdata) const
char * fData
event data buffer
Definition TMidasEvent.h:84
uint32_t GetSerialNumber() const
return the serial number
uint16_t GetTriggerMask() const
return the triger mask
int SwapBytes(bool) override
convert event data between little-endian (Linux-x86) and big endian (MacOS-PPC)
TMidas_EVENT_HEADER fEventHeader
event header
Definition TMidasEvent.h:83
bool IsGoodSize() const
validate the event length
uint32_t GetDataSize() const override
return the event size
void Copy(TObject &) const override
copy helper
char * fBankList
list of bank names in this event
Definition TMidasEvent.h:86
void SwapBytesEventHeader()
convert event header between little-endian (Linux-x86) and big endian (MacOS-PPC)
RAW event.
Definition TRawEvent.h:22
void Clear(Option_t *="") override
clear event for reuse
Definition TRawEvent.h:31
uint32_t fDataSize
event size in bytes
uint16_t fTriggerMask
event trigger mask
uint16_t fEventId
event id
uint32_t fSerialNumber
event serial number
uint32_t fTimeStamp
event timestamp in seconds
char fName[4]
bank name // NOLINT(*-avoid-c-arrays)
Definition TMidasEvent.h:47
16-bit data bank
Definition TMidasEvent.h:38
char fName[4]
bank name // NOLINT(*-avoid-c-arrays)
Definition TMidasEvent.h:39