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