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