ROOTANA
midasio.cxx
Go to the documentation of this file.
1 // midasio.cxx
2 
3 #include "midasio.h"
4 
5 #include <stdio.h>
6 #include <assert.h>
7 #include <stdlib.h> // malloc()
8 #include <string.h> // memcpy()
9 #include <errno.h> // errno
10 #include <signal.h> // signal()
11 
12 #include <string>
13 
14 #undef NDEBUG // working assert() is required by this program. K.O.
15 
16 bool TMWriterInterface::fgTrace = false;
17 bool TMReaderInterface::fgTrace = false;
18 
20 {
22  printf("TMReaderInterface::ctor!\n");
23  fError = false;
24  fErrorString = "";
25 }
26 
27 static std::string to_string(int v)
28 {
29  char buf[256];
30  sprintf(buf, "%d", v);
31  return buf;
32 }
33 
34 static std::string Errno(const char* s)
35 {
36  std::string r;
37  r += s;
38  r += " failed: errno: ";
39  r += to_string(errno);
40  r += " (";
41  r += strerror(errno);
42  r += ")";
43  return r;
44 }
45 
46 static int ReadPipe(FILE *fp, char* buf, int length)
47 {
48  int count = 0;
49  while (length > 0) {
50  int rd = fread(buf, 1, length, fp);
51  if (rd < 0)
52  return rd;
53  if (rd == 0)
54  return count;
55 
56  buf += rd;
57  length -= rd;
58  count += rd;
59  }
60  return count;
61 }
62 
63 
65 {
66  public:
67  ErrorReader(const char* filename)
68  {
70  printf("ErrorReader::ctor!\n");
71  fError = true;
72  fErrorString = "The ErrorReader always returns an error";
73  }
74 
75  ~ErrorReader() // dtor
76  {
78  printf("ErrorReader::dtor!\n");
79  }
80 
81  int Read(void* buf, int count)
82  {
83  return -1;
84  }
85 
86  int Close()
87  {
88  // an exception, no error on close.
89  return 0;
90  }
91 };
92 
94 {
95  public:
96  FileReader(const char* filename)
97  {
99  printf("FileReader::ctor!\n");
100  fFilename = filename;
101  fFp = fopen(filename, "r");
102  if (!fFp) {
103  fError = true;
104  fErrorString = Errno((std::string("fopen(\"")+filename+"\")").c_str());
105  }
106  }
107 
108  ~FileReader() // dtor
109  {
111  printf("FileReader::dtor!\n");
112  if (fFp)
113  Close();
114  }
115 
116  int Read(void* buf, int count)
117  {
118  if (fError)
119  return -1;
120  assert(fFp != NULL);
121  int rd = ReadPipe(fFp, (char*)buf, count);
122  if (rd < 0) {
123  fError = true;
124  fErrorString = Errno((std::string("fread(\"")+fFilename+"\")").c_str());
125  }
126  return rd;
127  }
128 
129  int Close()
130  {
132  printf("FileReader::Close!\n");
133  if (fFp) {
134  fclose(fFp);
135  fFp = NULL;
136  }
137  return 0;
138  }
139 
140  std::string fFilename;
141  FILE* fFp;
142 };
143 
145 {
146  public:
147  PipeReader(const char* pipename)
148  {
150  printf("PipeReader::ctor!\n");
151  fPipename = pipename;
152  fPipe = popen(pipename, "r");
153  if (!fPipe) {
154  fError = true;
155  fErrorString = Errno((std::string("popen(\"")+pipename+"\")").c_str());
156  }
157  }
158 
159  ~PipeReader() // dtor
160  {
162  printf("PipeReader::dtor!\n");
163  if (fPipe)
164  Close();
165  }
166 
167  int Read(void* buf, int count)
168  {
169  if (fError)
170  return -1;
171  assert(fPipe != NULL);
172  int rd = ReadPipe(fPipe, (char*)buf, count);
173  if (rd < 0) {
174  fError = true;
175  fErrorString = Errno((std::string("fread(\"")+fPipename+"\")").c_str());
176  }
177  return rd;
178  }
179 
180  int Close()
181  {
183  printf("PipeReader::Close!\n");
184  if (fPipe) {
185  pclose(fPipe); // FIXME: check error // only need to check error if writing to pipe
186  fPipe = NULL;
187  }
188  return 0;
189  }
190 
191  std::string fPipename;
192  FILE* fPipe;
193 };
194 
195 #ifdef HAVE_LIBZ
196 
197 #include <zlib.h>
198 
199 class ZlibReader: public TMReaderInterface
200 {
201  public:
202  ZlibReader(const char* filename)
203  {
205  printf("ZlibReader::ctor!\n");
206  fFilename = filename;
207  fGzFile = gzopen(filename, "rb");
208  if (!fGzFile) {
209  fError = true;
210  fErrorString = Errno((std::string("gzopen(\"")+fFilename+"\")").c_str());
211  }
212  }
213 
214  ~ZlibReader() // dtor
215  {
217  printf("PipeReader::dtor!\n");
218  if (fGzFile)
219  Close();
220  }
221 
222  int Read(void* buf, int count)
223  {
224  if (fError)
225  return -1;
226  assert(fGzFile != NULL);
227  int rd = gzread(fGzFile, buf, count);
228  if (rd < 0) {
229  fError = true;
230  fErrorString = Errno((std::string("gzread(\"")+fFilename+"\")").c_str());
231  }
232  return rd;
233  }
234 
235  int Close()
236  {
238  printf("ZlibReader::Close!\n");
239  if (fGzFile) {
240  gzclose(fGzFile); // FIXME: must check error on write, ok no check on read
241  fGzFile = NULL;
242  }
243  return 0;
244  }
245 
246  std::string fFilename;
247  gzFile fGzFile;
248 };
249 #endif
250 
251 #include "lz4frame.h"
252 
253 static std::string Lz4Error(int errorCode)
254 {
255  std::string s;
256  s += to_string(errorCode);
257  s += " (";
258  s += LZ4F_getErrorName(errorCode);
259  s += ")";
260  return s;
261 }
262 
264 {
265 public:
267  {
268  assert(reader);
269  fReader = reader;
270 
272  printf("Lz4Reader::ctor!\n");
273 
275  if (LZ4F_isError(errorCode)) {
276  fError = true;
277  fErrorString = "LZ4F_createDecompressionContext() error ";
278  fErrorString += Lz4Error(errorCode);
279  }
280 
281  fSrcBuf = NULL;
282  fSrcBufSize = 0;
283  fSrcBufStart = 0;
284  fSrcBufHave = 0;
285 
286  AllocSrcBuf(1024*1024);
287  }
288 
291  printf("Lz4Reader::dtor!\n");
292 
293  if (fSrcBuf) {
294  free(fSrcBuf);
295  fSrcBuf = NULL;
296  }
297 
299  if (LZ4F_isError(errorCode)) {
300  fError = true;
301  fErrorString = "LZ4F_freeDecompressionContext() error ";
302  fErrorString += Lz4Error(errorCode);
303  // NB: this error cannot be reported: we are in the destructor, fErrorString
304  // is immediately destroyed...
305  }
306 
307  if (fReader) {
308  delete fReader;
309  fReader = NULL;
310  }
311  }
312 
313 
314  int Read(void* buf, int count)
315  {
316  if (fError)
317  return -1;
318 
319  //printf("Lz4Reader::Read %d bytes!\n", count);
320 
321  char* cptr = (char*)buf;
322  int clen = 0;
323 
324  while (clen < count) {
325  int more = count - clen;
326 
327  if (fSrcBufHave == 0) {
328  assert(fSrcBufStart == 0);
329 
330  int rd = fReader->Read(fSrcBuf, fSrcBufSize);
331 
332  //printf("read asked %d, got %d\n", to_read, rd);
333 
334  if (rd < 0) {
335  if (clen > 0)
336  return clen;
337  else
338  return rd;
339  } else if (rd == 0) {
340  return clen;
341  }
342 
343  fSrcBufHave += rd;
344 
345  //printf("Lz4Reader::ReadMore: rd %d, srcbuf start %d, have %d\n", rd, fSrcBufStart, fSrcBufHave);
346  }
347 
348  LZ4F_decompressOptions_t* dOptPtr = NULL;
349 
350  char* dst = cptr;
351  size_t dst_size = more;
352  size_t src_size = fSrcBufHave;
353 
354  size_t status = LZ4F_decompress(fContext, dst, &dst_size, fSrcBuf + fSrcBufStart, &src_size, dOptPtr);
355 
356  if (LZ4F_isError(status)) {
357  fError = true;
358  fErrorString = "LZ4F_decompress() error ";
359  fErrorString += Lz4Error(status);
360  return -1;
361  }
362 
363  //printf("LZ4Reader::Decompress: status %d, dst_size %d -> %d, src_size %d -> %d\n", (int)status, more, (int)dst_size, fSrcBufHave, (int)src_size);
364 
365  assert(dst_size!=0 || src_size!=0); // make sure we make progress
366 
367  clen += dst_size;
368  cptr += dst_size;
369 
370  fSrcBufStart += src_size;
371  fSrcBufHave -= src_size;
372 
373  if (fSrcBufHave == 0)
374  fSrcBufStart = 0;
375  }
376 
377  //printf("Lz4Reader::Read %d bytes, returning %d bytes!\n", count, clen);
378  return clen;
379  }
380 
381  int Close()
382  {
384  printf("Lz4Reader::Close!\n");
385  return fReader->Close();
386  }
387 
388  void AllocSrcBuf(int size)
389  {
390  //printf("Lz4Reader::AllocSrcBuffer %d -> %d bytes!\n", fSrcBufSize, size);
391  fSrcBuf = (char*) realloc(fSrcBuf, size);
392  assert(fSrcBuf != NULL);
393  fSrcBufSize = size;
394  }
395 
398 
402  char* fSrcBuf;
403 };
404 
406 {
407  public:
408  FileWriter(const char* filename)
409  {
410  fFilename = filename;
411  fFp = fopen(filename, "w");
412  assert(fFp != NULL); // FIXME: check for error
413  }
414 
415  int Write(const void* buf, int count)
416  {
417  assert(fFp != NULL);
418  return fwrite(buf, 1, count, fFp);
419  }
420 
421  int Close()
422  {
423  assert(fFp != NULL);
424  fclose(fFp);
425  fFp = NULL;
426  return 0;
427  }
428 
429  std::string fFilename;
430  FILE* fFp;
431 };
432 
433 static int hasSuffix(const char*name,const char*suffix)
434 {
435  const char* s = strstr(name,suffix);
436  if (s == NULL)
437  return 0;
438 
439  return (s-name)+strlen(suffix) == strlen(name);
440 }
441 
443 {
444 #ifdef SIGPIPE
445  signal(SIGPIPE, SIG_IGN); // crash if reading from closed pipe
446 #endif
447 #ifdef SIGXFSZ
448  signal(SIGXFSZ, SIG_IGN); // crash if reading from file >2GB without O_LARGEFILE
449 #endif
450 
451  if (0)
452  {
453  }
454  else if (strncmp(source, "ssh://", 6) == 0)
455  {
456  const char* name = source + 6;
457  const char* s = strstr(name, "/");
458 
459  if (s == NULL) {
460  ErrorReader *e = new ErrorReader(source);
461  e->fError = true;
462  e->fErrorString = "TMidasFile::Open: Invalid ssh:// URI. Should be: ssh://user@host/file/path/...";
463  return e;
464  }
465 
466  const char* remoteFile = s + 1;
467 
468  std::string remoteHost;
469  for (s=name; *s != '/'; s++)
470  remoteHost += *s;
471 
472  std::string pipe;
473 
474  pipe = "ssh -e none -T -x -n ";
475  pipe += remoteHost;
476  pipe += " dd if=";
477  pipe += remoteFile;
478  pipe += " bs=1024k";
479 
480  if (hasSuffix(remoteFile,".gz"))
481  pipe += " | gzip -dc";
482  else if (hasSuffix(remoteFile,".bz2"))
483  pipe += " | bzip2 -dc";
484  else if (hasSuffix(remoteFile,".lz4"))
485  pipe += " | lz4 -d";
486 
487  return new PipeReader(pipe.c_str());
488  }
489  else if (strncmp(source, "dccp://", 7) == 0)
490  {
491  const char* name = source + 7;
492 
493  std::string pipe;
494 
495  pipe = "dccp ";
496  pipe += name;
497  pipe += " /dev/fd/1";
498 
499  if (hasSuffix(source,".gz"))
500  pipe += " | gzip -dc";
501  else if (hasSuffix(source,".bz2"))
502  pipe += " | bzip2 -dc";
503  else if (hasSuffix(source,".lz4"))
504  pipe += " | lz4 -d";
505 
506  return new PipeReader(pipe.c_str());
507  }
508  else if (strncmp(source, "pipein://", 9) == 0)
509  {
510  std::string pipe = source + 9;
511  return new PipeReader(pipe.c_str());
512  }
513 #if 0 // read compressed files using the zlib library
514  else if (hasSuffix(source, ".gz"))
515  {
516  pipe = "gzip -dc ";
517  pipe += source;
518  }
519 #endif
520 #if HAVE_LIBZ
521  else if (hasSuffix(source, ".gz"))
522  {
523  return new ZlibReader(source);
524  }
525 #endif
526  else if (hasSuffix(source, ".bz2"))
527  {
528  return new PipeReader((std::string("bzip2 -dc ") + source).c_str());
529  }
530  else if (hasSuffix(source, ".lz4"))
531  {
532  return new Lz4Reader(new FileReader(source));
533  }
534  else
535  {
536  return new FileReader(source);
537  }
538 }
539 
540 TMWriterInterface* TMNewWriter(const char* destination)
541 {
542  if (0) {
543 #if 0
544 #if HAVE_LIBZ
545  } else if (hasSuffix(source, ".gz")) {
546  return new ZlibReader(source);
547 #endif
548  } else if (hasSuffix(source, ".bz2")) {
549  return new PipeReader((std::string("bzip2 -dc ") + source).c_str());
550  } else if (hasSuffix(source, ".lz4")) {
551  return new Lz4Reader(new FileReader(source));
552 #endif
553  } else {
554  return new FileWriter(destination);
555  }
556 }
557 
558 static uint16_t GetU16(const void*ptr)
559 {
560  return *(uint16_t*)ptr;
561 }
562 
563 static uint32_t GetU32(const void*ptr)
564 {
565  return *(uint32_t*)ptr;
566 }
567 
568 static void PutU16(char* ptr, uint16_t v)
569 {
570  *(uint16_t*)ptr = v;
571 }
572 
573 static void PutU32(char* ptr, uint32_t v)
574 {
575  *(uint32_t*)ptr = v;
576 }
577 
578 static size_t Align8(size_t size)
579 {
580  // align to 8 bytes (uint64_t)
581  return (size + 7) & ~7;
582 }
583 
585 {
586  bool gOnce = true;
587  if (gOnce) {
588  gOnce = false;
589  assert(sizeof(char)==1);
590  assert(sizeof(uint16_t)==2);
591  assert(sizeof(uint32_t)==4);
592  }
593 
594  TMEvent* e = new TMEvent;
595 
596  e->Reset();
597 
598  const int event_header_size = 4*4;
599  char event_header[event_header_size];
600 
601  int rd = reader->Read(event_header, event_header_size);
602 
603  if (rd < 0) { // read error
604  delete e;
605  return NULL;
606  } else if (rd == 0) { // end of file
607  delete e;
608  return NULL;
609  } else if (rd != event_header_size) { // truncated data in file
610  fprintf(stderr, "TMReadEvent: error: read %d shorter than event header size %d\n", (int)rd, (int)event_header_size);
611  e->error = true;
612  return e;
613  }
614 
615  e->event_id = GetU16(event_header+0);
616  e->trigger_mask = GetU16(event_header+2);
617  e->serial_number = GetU32(event_header+4);
618  e->time_stamp = GetU32(event_header+8);
619  e->data_size = GetU32(event_header+12);
620 
621  e->event_header_size = event_header_size;
622 
623  e->bank_header_flags = 0;
624 
625  //if (!e->old_event.IsGoodSize()) { // invalid event size
626  // e->error = true;
627  // return e;
628  //}
629 
630  size_t to_read = e->data_size;
631 
632  e->data.resize(event_header_size + to_read);
633 
634  memcpy(&e->data[0], event_header, event_header_size);
635 
636  rd = reader->Read(&e->data[event_header_size], to_read);
637 
638  if (rd < 0) { // read error
639  delete e;
640  return NULL;
641  } else if ((size_t)rd != to_read) { // truncated data in file
642  fprintf(stderr, "TMReadEvent: error: short read %d instead of %d\n", (int)rd, (int)to_read);
643  e->error = true;
644  return e;
645  }
646 
647  return e;
648 }
649 
650 void TMWriteEvent(TMWriterInterface* writer, const TMEvent* event)
651 {
652  writer->Write(&(event->data[0]), event->data.size());
653 }
654 
655 std::string TMEvent::HeaderToString() const
656 {
657  char buf[1024];
658  sprintf(buf, "event: id %d, mask 0x%04x, serial %d, time %d, size %d, error %d, banks %d", event_id, trigger_mask, serial_number, time_stamp, data_size, error, (int)banks.size());
659  return buf;
660 }
661 
662 std::string TMEvent::BankListToString() const
663 {
664  std::string s;
665  for (unsigned i=0; i<banks.size(); i++) {
666  if (i>0)
667  s += ",";
668  s += banks[i].name;
669  }
670  return s;
671 }
672 
673 std::string TMEvent::BankToString(const TMBank*b) const
674 {
675  char buf[1024];
676  sprintf(buf, "name \"%s\", type %d, size %d, offset %d\n", b->name.c_str(), b->type, b->data_size, (int)b->data_offset);
677  return buf;
678 }
679 
681 {
682  Reset();
683 }
684 
686 {
687  error = false;
688 
689  event_id = 0;
690  trigger_mask = 0;
691  serial_number = 0;
692  time_stamp = 0;
693  data_size = 0;
694 
695  event_header_size = 0;
696  bank_header_flags = 0;
697 
698  banks.clear();
699  data.clear();
700 
701  found_all_banks = false;
702  bank_scan_position = 0;
703 }
704 
706 {
707  ParseHeader(data.data(), data.size());
708 
709  if (data.size() != event_header_size + data_size) {
710  fprintf(stderr, "TMEvent::ParseEvent: error: vector size %d mismatch against event size in event header: data_size %d, event_size %d\n", (int)data.size(), (int)data_size, (int)(event_header_size + data_size));
711  error = true;
712  }
713 }
714 
715 void TMEvent::ParseHeader(const void* buf, size_t buf_size)
716 {
717  event_header_size = 4*4;
718 
719  const char* event_header = (const char*)buf;
720 
721  if (buf_size < event_header_size) {
722  fprintf(stderr, "TMEvent::ctor: error: buffer size %d is smaller than event header size %d\n", (int)buf_size, (int)event_header_size);
723  error = true;
724  return;
725  }
726 
727  event_id = GetU16(event_header+0);
728  trigger_mask = GetU16(event_header+2);
729  serial_number = GetU32(event_header+4);
730  time_stamp = GetU32(event_header+8);
731  data_size = GetU32(event_header+12);
732 
733  bank_header_flags = 0;
734 
735  //if (!e->old_event.IsGoodSize()) { // invalid event size
736  // e->error = true;
737  // return e;
738  //}
739 }
740 
741 TMEvent::TMEvent(const void* buf, size_t buf_size)
742 {
743  bool gOnce = true;
744  if (gOnce) {
745  gOnce = false;
746  assert(sizeof(char)==1);
747  assert(sizeof(uint16_t)==2);
748  assert(sizeof(uint32_t)==4);
749  }
750 
751  Reset();
752  ParseHeader(buf, buf_size);
753 
754  if (error) {
755  return;
756  }
757 
758  size_t zdata_size = data_size;
759  size_t zevent_size = zdata_size + event_header_size;
760 
761  if (zevent_size != buf_size) {
762  fprintf(stderr, "TMEvent::ctor: error: buffer size %d mismatch against event size in event header: data_size %d, event_size %d\n", (int)buf_size, (int)zdata_size, (int)zevent_size);
763  error = true;
764  return;
765  }
766 
767  //data.resize(event_header_size + to_read);
768  //memcpy(&data[0], xdata, event_header_size + to_read);
769 
770  const char* cptr = (const char*)buf;
771 
772  data.assign(cptr, cptr + zevent_size);
773 
774  assert(data.size() == zevent_size);
775 }
776 
777 void TMEvent::Init(uint16_t xevent_id, uint16_t xtrigger_mask, uint32_t xserial_number, uint32_t xtime_stamp, size_t capacity)
778 {
779  Reset();
780 
781  event_header_size = 4*4;
782 
783  event_id = xevent_id;
784  trigger_mask = xtrigger_mask;
785  serial_number = xserial_number;
786  if (xtime_stamp) {
787  time_stamp = xtime_stamp;
788  } else {
789  time_stamp = time(NULL);
790  }
791 
792  data_size = 8; // data size: 2 words of bank header, 0 words of data banks
793  bank_header_flags = 0x00000031; // bank header flags, bk_init32a() format
794 
795  // bank list is empty
796 
797  bank_scan_position = 0;
798  found_all_banks = false;
799 
800  // allocate event buffer
801 
802  if (capacity < 1024)
803  capacity = 1024;
804 
805  data.reserve(capacity);
806 
807  // create event data
808 
809  data.resize(event_header_size + data_size);
810 
811  char* event_header = data.data();
812 
813  PutU16(event_header+0, event_id);
814  PutU16(event_header+2, trigger_mask);
815  PutU32(event_header+4, serial_number);
816  PutU32(event_header+8, time_stamp);
817  PutU32(event_header+12, data_size);
818  PutU32(event_header+16, 0); // bank header data size
819  PutU32(event_header+20, bank_header_flags); // bank header flags
820 }
821 
822 void TMEvent::AddBank(const char* bank_name, int tid, const char* buf, size_t size)
823 {
824  size_t bank_size = event_header_size + Align8(size);
825 
826  size_t end_of_event_offset = data.size();
827 
828  data.resize(end_of_event_offset + bank_size);
829 
830  char* pbank = data.data() + end_of_event_offset;
831 
832  pbank[0] = bank_name[0];
833  pbank[1] = bank_name[1];
834  pbank[2] = bank_name[2];
835  pbank[3] = bank_name[3];
836  PutU32(pbank+1*4, tid);
837  PutU32(pbank+2*4, size);
838  PutU32(pbank+3*4, 0); // bk_init32a() extra padding/reserved word
839 
840  memcpy(pbank+4*4, buf, size);
841 
842  // adjust event header
843 
844  data_size += bank_size;
845 
846  char* event_header = data.data();
847  PutU32(event_header + 12, data_size); // event header
848  PutU32(event_header + 16, data_size - 8); // bank header
849 
850  // add a bank record
851 
852  if (found_all_banks) {
853  TMBank b;
854  b.name = bank_name;
855  b.type = tid;
856  b.data_size = size;
857  b.data_offset = end_of_event_offset + 4*4;
858  banks.push_back(b);
859  }
860 }
861 
862 static size_t FindFirstBank(TMEvent* e)
863 {
864  if (e->error)
865  return 0;
866 
867  size_t off = e->event_header_size;
868 
869  if (e->data.size() < off + 8) {
870  fprintf(stderr, "TMEvent::FindFirstBank: error: data size %d is too small\n", (int)e->data.size());
871  e->error = true;
872  return 0;
873  }
874 
875  uint32_t bank_header_data_size = GetU32(&e->data[off]);
876  uint32_t bank_header_flags = GetU32(&e->data[off+4]);
877 
878  //printf("bank header: data size %d, flags 0x%08x\n", bank_header_data_size, bank_header_flags);
879 
880  if (bank_header_data_size + 8 != e->data_size) {
881  fprintf(stderr, "TMEvent::FindFirstBank: error: bank header size %d mismatch against data size %d\n", (int)bank_header_data_size, (int)e->data_size);
882  e->error = true;
883  return 0;
884  }
885 
886  e->bank_header_flags = bank_header_flags;
887 
888  return off+8;
889 }
890 
891 #if 0
892 static char xchar(char c)
893 {
894  if (c>='0' && c<='9')
895  return c;
896  if (c>='a' && c<='z')
897  return c;
898  if (c>='A' && c<='Z')
899  return c;
900  return '$';
901 }
902 #endif
903 
904 static size_t FindNextBank(TMEvent* e, size_t pos, TMBank** pb)
905 {
906  if (e->error)
907  return 0;
908 
909  size_t remaining = e->data.size() - pos;
910 
911  //printf("pos %d, event data_size %d, size %d, remaining %d\n", pos, e->data_size, (int)e->data.size(), remaining);
912 
913  if (remaining == 0) {
914  // end of data, no more banks to find
915  e->found_all_banks = true;
916  return 0;
917  }
918 
919  if (remaining < 8) {
920  fprintf(stderr, "TMEvent::FindNextBank: error: too few bytes %d remaining at the end of event\n", (int)remaining);
921  e->error = true;
922  e->found_all_banks = true; // no more banks will be found after this error
923  return 0;
924  }
925 
926  size_t ibank = e->banks.size();
927  e->banks.resize(ibank+1);
928 
929  TMBank* b = &e->banks[ibank];
930 
931  b->name.resize(4);
932  b->name[0] = e->data[pos+0];
933  b->name[1] = e->data[pos+1];
934  b->name[2] = e->data[pos+2];
935  b->name[3] = e->data[pos+3];
936  b->name[4] = 0;
937 
938  size_t data_offset = 0;
939 
940  //printf("bank header flags: 0x%08x\n", e->bank_header_flags);
941 
942  if (e->bank_header_flags & (1<<5)) {
943  // bk_init32a format
944  b->type = GetU32(&e->data[pos+4+0]);
945  b->data_size = GetU32(&e->data[pos+4+4]);
946  data_offset = pos+4+4+4+4;
947  } else if (e->bank_header_flags & (1<<4)) {
948  // bk_init32 format
949  b->type = GetU32(&e->data[pos+4+0]);
950  b->data_size = GetU32(&e->data[pos+4+4]);
951  data_offset = pos+4+4+4;
952  } else {
953  // bk_init format
954  b->type = GetU16(&e->data[pos+4+0]);
955  b->data_size = GetU16(&e->data[pos+4+2]);
956  data_offset = pos+4+2+2;
957  }
958 
959  b->data_offset = data_offset;
960 
961  //printf("found bank at pos %d: %s\n", pos, e->BankToString(b).c_str());
962 
963  if (b->type < 1 || b->type >= TID_LAST) {
964  fprintf(stderr, "TMEvent::FindNextBank: error: invalid tid %d\n", b->type);
965  e->error = true;
966  return 0;
967  }
968 
969  size_t aligned_data_size = Align8(b->data_size);
970 
971  //printf("data_size %d, alignemnt: %d %d, aligned %d\n", b->data_size, align, b->data_size%align, aligned_data_size);
972 
973  size_t npos = data_offset + aligned_data_size;
974 
975  //printf("pos %d, next bank at %d: [%c%c%c%c]\n", pos, npos, xchar(e->data[npos+0]), xchar(e->data[npos+1]), xchar(e->data[npos+2]), xchar(e->data[npos+3]));
976 
977  if (npos > e->data.size()) {
978  fprintf(stderr, "TMEvent::FindNextBank: error: invalid bank data size %d: aligned %d, npos %d, end of event %d\n", b->data_size, (int)aligned_data_size, (int)npos, (int)e->data.size());
979  e->error = true;
980  return 0;
981  }
982 
983  if (pb)
984  *pb = b;
985 
986  return npos;
987 }
988 
990 {
991  if (error)
992  return NULL;
993  if (event_header_size == 0)
994  return NULL;
995  if (event_header_size > data.size())
996  return NULL;
997  if (event_header_size + data_size > data.size())
998  return NULL;
999  return &data[event_header_size];
1000 }
1001 
1002 const char* TMEvent::GetEventData() const
1003 {
1004  if (error)
1005  return NULL;
1006  if (event_header_size == 0)
1007  return NULL;
1008  if (event_header_size > data.size())
1009  return NULL;
1010  if (event_header_size + data_size > data.size())
1011  return NULL;
1012  return &data[event_header_size];
1013 }
1014 
1016 {
1017  if (error)
1018  return NULL;
1019  if (!b)
1020  return NULL;
1021  if (b->data_offset >= data.size())
1022  return NULL;
1023  if (b->data_offset + b->data_size > data.size())
1024  return NULL;
1025  return &data[b->data_offset];
1026 }
1027 
1028 const char* TMEvent::GetBankData(const TMBank* b) const
1029 {
1030  if (error)
1031  return NULL;
1032  if (!b)
1033  return NULL;
1034  if (b->data_offset >= data.size())
1035  return NULL;
1036  if (b->data_offset + b->data_size > data.size())
1037  return NULL;
1038  return &data[b->data_offset];
1039 }
1040 
1041 TMBank* TMEvent::FindBank(const char* bank_name)
1042 {
1043  if (error)
1044  return NULL;
1045 
1046  // if we already found this bank, return it
1047 
1048  if (bank_name)
1049  for (unsigned i=0; i<banks.size(); i++) {
1050  if (banks[i].name == bank_name)
1051  return &banks[i];
1052  }
1053 
1054  //printf("found_all_banks %d\n", found_all_banks);
1055 
1056  if (found_all_banks)
1057  return NULL;
1058 
1059  size_t pos = bank_scan_position;
1060 
1061  if (pos == 0)
1062  pos = FindFirstBank(this);
1063 
1064  //printf("pos %d\n", pos);
1065 
1066  while (pos > 0) {
1067  TMBank* b = NULL;
1068  pos = FindNextBank(this, pos, &b);
1069  bank_scan_position = pos;
1070  //printf("pos %d, b %p\n", pos, b);
1071  if (pos>0 && b && bank_name) {
1072  if (b->name == bank_name)
1073  return b;
1074  }
1075  }
1076 
1077  found_all_banks = true;
1078 
1079  return NULL;
1080 }
1081 
1083 {
1084  if (found_all_banks)
1085  return;
1086 
1087  FindBank(NULL);
1088 
1089  assert(found_all_banks);
1090 }
1091 
1093 {
1094  printf("Event: id 0x%04x, mask 0x%04x, serial 0x%08x, time 0x%08x, data size %d, vector size %d, capacity %d\n",
1095  event_id,
1096  trigger_mask,
1097  serial_number,
1098  time_stamp,
1099  data_size,
1100  (int)data.size(),
1101  (int)data.capacity()
1102  );
1103 }
1104 
1105 void TMEvent::PrintBanks(int level)
1106 {
1107  FindAllBanks();
1108 
1109  printf("%d banks:", (int)banks.size());
1110  for (size_t i=0; i<banks.size(); i++) {
1111  printf(" %s", banks[i].name.c_str());
1112  }
1113  printf("\n");
1114 
1115  if (level > 0) {
1116  for (size_t i=0; i<banks.size(); i++) {
1117  printf("bank %3d: name \"%s\", tid %2d, data_size %8d\n",
1118  (int)i,
1119  banks[i].name.c_str(),
1120  banks[i].type,
1121  banks[i].data_size);
1122  if (level > 1) {
1123  const char* p = GetBankData(&banks[i]);
1124  if (p) {
1125  for (size_t j=0; j<banks[i].data_size; j+=4) {
1126  printf("%11d: 0x%08x\n", (int)j, *(uint32_t*)(p+j));
1127  }
1128  }
1129  }
1130  }
1131  }
1132 }
1133 
1135 {
1136  const char* p = data.data();
1137 
1138  // event header
1139  printf(" 0: 0x%08x\n", GetU32(p+0*4));
1140  printf(" 1: 0x%08x\n", GetU32(p+1*4));
1141  printf(" 2: 0x%08x\n", GetU32(p+2*4));
1142  printf(" 3: 0x%08x (0x%08x and 0x%08x-0x10)\n", GetU32(p+3*4), data_size, (int)data.size());
1143 
1144  // bank header
1145  printf(" 4: 0x%08x\n", GetU32(p+4*4));
1146  printf(" 5: 0x%08x (0x%08x)\n", GetU32(p+5*4), bank_header_flags);
1147 }
1148 
1149 /* emacs
1150  * Local Variables:
1151  * tab-width: 8
1152  * c-basic-offset: 3
1153  * indent-tabs-mode: nil
1154  * End:
1155  */
1156 
ErrorReader(const char *filename)
Definition: midasio.cxx:67
int Read(void *buf, int count)
Definition: midasio.cxx:81
~ErrorReader()
Definition: midasio.cxx:75
int Close()
Definition: midasio.cxx:86
FileReader(const char *filename)
Definition: midasio.cxx:96
int Close()
Definition: midasio.cxx:129
FILE * fFp
Definition: midasio.cxx:141
int Read(void *buf, int count)
Definition: midasio.cxx:116
std::string fFilename
Definition: midasio.cxx:140
FILE * fFp
Definition: midasio.cxx:430
int Close()
Definition: midasio.cxx:421
int Write(const void *buf, int count)
Definition: midasio.cxx:415
FileWriter(const char *filename)
Definition: midasio.cxx:408
std::string fFilename
Definition: midasio.cxx:429
int fSrcBufHave
Definition: midasio.cxx:401
int Close()
Definition: midasio.cxx:381
Lz4Reader(TMReaderInterface *reader)
Definition: midasio.cxx:266
~Lz4Reader()
Definition: midasio.cxx:289
LZ4F_decompressionContext_t fContext
Definition: midasio.cxx:397
TMReaderInterface * fReader
Definition: midasio.cxx:396
void AllocSrcBuf(int size)
Definition: midasio.cxx:388
int fSrcBufStart
Definition: midasio.cxx:400
int fSrcBufSize
Definition: midasio.cxx:399
char * fSrcBuf
Definition: midasio.cxx:402
int Read(void *buf, int count)
Definition: midasio.cxx:314
std::string fPipename
Definition: midasio.cxx:191
int Close()
Definition: midasio.cxx:180
FILE * fPipe
Definition: midasio.cxx:192
int Read(void *buf, int count)
Definition: midasio.cxx:167
PipeReader(const char *pipename)
Definition: midasio.cxx:147
Definition: midasio.h:44
uint32_t type
type of bank data, enum of TID_xxx
Definition: midasio.h:47
uint32_t data_size
size of bank data in bytes
Definition: midasio.h:48
size_t data_offset
offset of data for this bank in the event data[] container
Definition: midasio.h:49
std::string name
bank name, 4 characters max
Definition: midasio.h:46
std::string BankListToString() const
print the list of MIDAS banks
Definition: midasio.cxx:662
void PrintHeader() const
Definition: midasio.cxx:1092
void FindAllBanks()
scan the MIDAS event, find all data banks
Definition: midasio.cxx:1082
std::string HeaderToString() const
print the MIDAS event header
Definition: midasio.cxx:655
TMBank * FindBank(const char *bank_name)
scan the MIDAS event
Definition: midasio.cxx:1041
bool found_all_banks
all the banks in the event data have been discovered
Definition: midasio.h:71
std::vector< TMBank > banks
list of MIDAS banks, fill using FindAllBanks()
Definition: midasio.h:66
void Reset()
reset everything
Definition: midasio.cxx:685
void PrintBanks(int level=0)
Definition: midasio.cxx:1105
void AddBank(const char *bank_name, int tid, const char *buf, size_t size)
add new MIDAS bank
Definition: midasio.cxx:822
char * GetEventData()
get pointer to MIDAS event data
Definition: midasio.cxx:989
void DumpHeader() const
Definition: midasio.cxx:1134
void Init(uint16_t event_id, uint16_t trigger_mask=0, uint32_t serial_number=0, uint32_t time_stamp=0, size_t capacity=0)
Definition: midasio.cxx:777
uint32_t time_stamp
MIDAS event time stamp (unix time in sec)
Definition: midasio.h:60
size_t bank_scan_position
location where scan for MIDAS banks was last stopped
Definition: midasio.h:72
uint32_t bank_header_flags
flags from the MIDAS event bank header
Definition: midasio.h:64
void ParseHeader(const void *buf, size_t buf_size)
parse event header
Definition: midasio.cxx:715
void ParseEvent()
parse event data
Definition: midasio.cxx:705
std::vector< char > data
MIDAS event bytes.
Definition: midasio.h:67
size_t event_header_size
size of MIDAS event header
Definition: midasio.h:63
uint32_t serial_number
MIDAS event serial number.
Definition: midasio.h:59
uint32_t data_size
MIDAS event data size.
Definition: midasio.h:61
uint16_t trigger_mask
MIDAS trigger mask.
Definition: midasio.h:58
uint16_t event_id
MIDAS event ID.
Definition: midasio.h:57
char * GetBankData(const TMBank *)
get pointer to MIDAS data bank
Definition: midasio.cxx:1015
bool error
event has an error - incomplete, truncated, inconsistent or corrupted
Definition: midasio.h:55
std::string BankToString(const TMBank *) const
print definition of one MIDAS bank
Definition: midasio.cxx:673
TMEvent()
Definition: midasio.cxx:680
virtual int Read(void *buf, int count)=0
virtual int Close()=0
std::string fErrorString
Definition: midasio.h:116
static bool fgTrace
Definition: midasio.h:117
virtual int Write(const void *buf, int count)=0
static bool fgTrace
Definition: midasio.h:125
char * dst
Definition: lz4.h:354
size_t LZ4F_errorCode_t
Definition: lz4frame.h:56
size_t LZ4F_decompress(LZ4F_decompressionContext_t dctx, void *dstBuffer, size_t *dstSizePtr, const void *srcBuffer, size_t *srcSizePtr, const LZ4F_decompressOptions_t *dOptPtr)
Definition: lz4frame.c:1044
LZ4F_errorCode_t LZ4F_createDecompressionContext(LZ4F_decompressionContext_t *dctxPtr, unsigned version)
Definition: lz4frame.c:760
LZ4F_errorCode_t LZ4F_freeDecompressionContext(LZ4F_decompressionContext_t dctx)
Definition: lz4frame.c:772
unsigned LZ4F_isError(LZ4F_errorCode_t code)
Definition: lz4frame.c:160
const char * LZ4F_getErrorName(LZ4F_errorCode_t code)
Definition: lz4frame.c:165
#define LZ4F_VERSION
Definition: lz4frame.h:158
const char * source
Definition: lz4hc.h:181
#define TID_LAST
Definition: midasio.h:40
static size_t FindFirstBank(TMEvent *e)
Definition: midasio.cxx:862
static int ReadPipe(FILE *fp, char *buf, int length)
Definition: midasio.cxx:46
void TMWriteEvent(TMWriterInterface *writer, const TMEvent *event)
Definition: midasio.cxx:650
TMReaderInterface * TMNewReader(const char *source)
Definition: midasio.cxx:442
static std::string to_string(int v)
Definition: midasio.cxx:27
static std::string Lz4Error(int errorCode)
Definition: midasio.cxx:253
static void PutU32(char *ptr, uint32_t v)
Definition: midasio.cxx:573
static uint32_t GetU32(const void *ptr)
Definition: midasio.cxx:563
static size_t FindNextBank(TMEvent *e, size_t pos, TMBank **pb)
Definition: midasio.cxx:904
TMWriterInterface * TMNewWriter(const char *destination)
Definition: midasio.cxx:540
static void PutU16(char *ptr, uint16_t v)
Definition: midasio.cxx:568
static std::string Errno(const char *s)
Definition: midasio.cxx:34
static int hasSuffix(const char *name, const char *suffix)
Definition: midasio.cxx:433
static uint16_t GetU16(const void *ptr)
Definition: midasio.cxx:558
TMEvent * TMReadEvent(TMReaderInterface *reader)
Definition: midasio.cxx:584
static size_t Align8(size_t size)
Definition: midasio.cxx:578