#include #include #include #include #include #include #include "IMidasFile.hxx" #include "IMidasEventParser.hxx" #include "ICOMETRawEvent.hxx" #include "ICOMETEvent.hxx" #include "ICOMETContext.hxx" ClassImp(COMET::IMidasFile); COMET::IMidasFile::IMidasFile() { UInt_t endian = 0x12345678; fLastErrno = 0; fDoByteSwap = *(char*)(&endian) != 0x78; fFile = -1; fGzFile = NULL; fEndOfFile = false; fEventsRead = 0; } COMET::IMidasFile::~IMidasFile() { Close(); } bool COMET::IMidasFile::IsOpen() { return ((fFile > 0) || fGzFile); } bool COMET::IMidasFile::Open(const char *filename) { /// Opens a midas .mid file with given file name. /// /// \param [in] filename The file to open. /// /// \returns "true" for succes, "false" for error, use GetLastError() to /// see why if (IsOpen()) Close(); fFilename = filename; fEventsRead = 0; #ifndef O_LARGEFILE #define O_LARGEFILE 0 #endif // Open either compressed (if last 2 characters of filename are 'gz') or // uncompressed file. int len = strlen(filename); if (filename[len-2]=='g' && filename[len-1]=='z') { fGzFile = gzopen(filename,"rb"); if (fGzFile == NULL) { fLastErrno = -1; fLastError = "zlib gzdopen() error"; return false; } } else { fFile = open(filename, O_RDONLY | O_LARGEFILE); if (fFile <= 0) { fLastErrno = errno; fLastError = strerror(errno); return false; } } return true; } static int readpipe(int fd, char* buf, int length) { int count = 0; while (length > 0) { int rd = read(fd, buf, length); if (rd > 0) { buf += rd; length -= rd; count += rd; } else if (rd == 0) { return count; } else { return -1; } } return count; } bool COMET::IMidasFile::Read(IMidasEventParser *midasEvent) { /// \param [in] midasEvent Pointer to an empty IMidasEventParser /// /// \returns "true" for success, "false" for failure, see GetLastError() to /// see why midasEvent->Clear(); int rd = 0; if (fGzFile) { rd = gzread(fGzFile, midasEvent->GetEventHeader(), midasEvent->GetEventHeaderSize()); } else { rd = readpipe(fFile, midasEvent->GetEventHeader(), midasEvent->GetEventHeaderSize()); } if (rd == 0) { fLastErrno = 0; fLastError = "EOF"; return false; } else if (rd != (int)midasEvent->GetEventHeaderSize()) { fLastErrno = errno; fLastError = strerror(errno); return false; } if (fDoByteSwap) midasEvent->SwapBytesEventHeader(); if (!midasEvent->IsGoodSize()) { fLastErrno = -1; fLastError = "Invalid event size"; return false; } if (fGzFile) { rd = gzread(fGzFile, midasEvent->GetData(), midasEvent->GetDataSize()); } else { rd = readpipe(fFile, midasEvent->GetData(), midasEvent->GetDataSize()); } if (rd != (int)midasEvent->GetDataSize()) { fLastErrno = errno; fLastError = strerror(errno); return false; } midasEvent->SwapBytes(false); return true; } void COMET::IMidasFile::Close() { if (fGzFile) gzclose(fGzFile); if (fFile > 0) close(fFile); fGzFile = NULL; fFile = -1; fFilename = ""; fLastErrno = 0; fLastError = ""; fEndOfFile = false; } int COMET::IMidasFile::GetPosition(void) const { // We are past the end of file, so the position is the number of events // read. if (fEndOfFile) return fEventsRead; // The position of the event just read. int position = fEventsRead - 1; // If we haven't read an event yet, then the position is -1; if (position<0) return -1; return position; } COMET::ICOMETRawEvent* COMET::IMidasFile::ReadRawEvent() { // Create a scratch IMidasEventParser and if filled succesfully return // a ICOMETRawEvent filled by it. COMET::IMidasEventParser mep; if ( ! this->Read(&mep) ) { fEndOfFile = true; return 0; } ++ fEventsRead; return new COMET::ICOMETRawEvent(mep,"Unnamed"); } COMET::ICOMETEvent* COMET::IMidasFile::NextEvent(int skip) { ICOMETRawEvent* raw = NULL; do { raw = ReadRawEvent(); if (!raw) return NULL; } while (0 < skip--); // Information in the context will be overridden by information found in // the raw event when the ICOMETEvent is built. This context provides // back up information incase the raw event is missing data (e.g. the // sub-run number). COMET::ICOMETContext context; const COMET::IRawDataHeader& header = raw->GetHeader(); context.SetRun(header.GetRun()); // KLUDGE ALERT: Extract the sub run number from the filename, using // the assumption that the filename has convention *_XXXX.daq.mid or // *_XXXX.daq.mid.gz where XXXX is the four digit sub run number. std::string::size_type nn = fFilename.find(".daq.mid"); if(nn != std::string::npos && nn >= 5 && fFilename[nn-5] == '_'){ std::string str2 = fFilename.substr(nn-4,4); context.SetSubRun(std::atoi(str2.c_str())); } ICOMETEvent* event = new ICOMETEvent(context, raw); return event; } COMET::ICOMETEvent* COMET::IMidasFile::FirstEvent() { // Take a copy of the filename (Open calls Close which wipes fFilename). std::string file_name(fFilename); this->Open(file_name.c_str()); return NextEvent(); }