LCOV - code coverage report
Current view: top level - midasio - midasio.cxx (source / functions) Coverage Total Hit
Test: coverage.info Lines: 0.0 % 649 0
Test Date: 2025-11-11 10:26:08 Functions: 0.0 % 60 0

            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              : 
        

Generated by: LCOV version 2.0-1