Reader.cc

00001 #include "Reader.hh"
00002 #include "Message.hh"
00003 #include "ConfigHandler.hh"
00004 #include "EventHandler.hh"
00005 #include <fstream>
00006 #include <stdexcept>
00007 #include <iomanip>
00008 
00009 Reader::Reader(const std::string& filename) : 
00010   _filename(filename), _fin(0),  _ok(true),
00011   _current_index(-1), _current_event(), _current_file_index(_unset_file_index),
00012   _current_file_name(""),
00013   _end_last_file(false)
00014 {
00015   
00016   if(!OpenNextFile()){
00017     //look for a saved config file
00018     if(ConfigHandler::GetInstance()->GetSavedCfgFile()==""){
00019       std::string cfgfile = _current_file_name+".";
00020       size_t pos;
00021       bool cfgfound = false;
00022       while( (pos = cfgfile.rfind('.')) != std::string::npos){
00023         cfgfile.resize(pos);
00024         std::string testfile = cfgfile+".cfg";
00025         Message(DEBUG2)<<"Testing for config file with name "<<testfile<<"\n";
00026         std::ifstream cfgfin(testfile.c_str());
00027         if(cfgfin.is_open()){
00028           ConfigHandler::GetInstance()->SetSavedCfgFile(testfile);
00029           Message(DEBUG)<<"Found saved cfg file at "<<testfile<<"\n";
00030           cfgfound = true;
00031           break;
00032         }
00033         cfgfin.close();
00034       }
00035       if(!cfgfound)
00036         Message(WARNING)<<"Unable to locate configuration file for raw file "
00037                         <<filename<<"\n";
00038     }
00039     //try to set the run id for processing modules
00040     if(_ghead.global_header_version>0)
00041       EventHandler::GetInstance()->SetRunID(_ghead.run_id);
00042     else
00043       EventHandler::GetInstance()->SetRunIDFromFilename(filename);
00044   }
00045 
00046 }
00047 
00048 Reader::~Reader()
00049 {
00050   if(_fin) CloseCurrentFile();
00051 }
00052 
00053 bool Reader::ErrorCheck(int bytes_read, int bytes_requested)
00054 {
00055   //returns true if error encountered
00056   if(bytes_read == -1){
00057     Message(ERROR)<<"Error encountered when reading from file.\n";
00058     _ok = false;
00059     return true;
00060   }
00061   else if(bytes_read == 0){
00062     Message(DEBUG)<<"End of file reached.\n";
00063     return true;
00064   }
00065   else if(bytes_read < bytes_requested){
00066     Message(ERROR)<<"Problem reading header for next event.\n";
00067     _ok = false;
00068     return true;
00069   }
00070   return false;
00071 }
00072 
00073 
00074 int Reader::ReadNextHeader()
00075 {
00076   if(!_ok){
00077     Message(ERROR)<<"Attempt to read from file in bad state.\n";
00078     return 1;
00079   }
00080   //see if we need to open the next file
00081   if(eof()){
00082     Message(DEBUG)<<"Reached end of files to search.\n";
00083     return 1;
00084   }
00085   int bytes_read = 0;
00086   switch(_ghead.event_header_version){
00087   case 0:
00088     //use the legacy header
00089     event_header_v0 head;
00090     bytes_read = gzread(_fin, &head, sizeof(event_header_v0));
00091     if(ErrorCheck(bytes_read, sizeof(event_header_v0)))
00092       return 1;
00093     // copy legacy header info into the latest header version
00094     _ehead.event_size = head.event_size;
00095     _ehead.event_id = head.event_id;
00096     _ehead.timestamp = head.timestamp;
00097     _ehead.nblocks = 1;
00098     break;
00099   case latest_event_version:
00100     //use the current header
00101     bytes_read = gzread(_fin, &_ehead, sizeof(_ehead));
00102     if(ErrorCheck(bytes_read, sizeof(_ehead))){
00103       if(bytes_read==0) //could just be EOF, not actual error; try again
00104         return ReadNextHeader();
00105       //otherwise its a problem
00106       return 1;
00107     }
00108     break;
00109   default:
00110     Message(CRITICAL)<<"Unknown event header version number!\n";
00111   }
00112   return 0;
00113 }
00114 
00115 z_off_t Reader::SkipNextEvent(bool skip_header)
00116 {
00117   //see if we need to open the next file
00118   if(gzeof(_fin) && OpenNextFile()){
00119     Message(DEBUG)<<"Reached end of files to search.\n";
00120     return 0;
00121   }
00122   
00123   z_off_t seekpos=0;
00124   if(skip_header){
00125     //first byte is event size
00126     uint32_t esize = 0;
00127     int bytes_read = gzread(_fin, &esize, sizeof(uint32_t));
00128     if(ErrorCheck(bytes_read, sizeof(uint32_t)))
00129       return 0;
00130     z_off_t seek_length = esize - sizeof(uint32_t);
00131     seekpos =  gzseek(_fin, seek_length, SEEK_CUR);
00132   }
00133   else{
00134     z_off_t seek_length = _ehead.event_size - sizeof(event_header);
00135     if(_ghead.event_header_version == 0)
00136       seek_length = _ehead.event_size - sizeof(event_header_v0);
00137     seekpos =  gzseek(_fin, seek_length, SEEK_CUR);
00138   }
00139   _current_index++;
00140   return seekpos;
00141     
00142 }
00143 
00144 RawEventPtr Reader::GetNextEvent(bool read_header)
00145 {
00146   if(read_header) 
00147     ReadNextHeader();
00148   if(!_ok){
00149     Message(ERROR)<<"Attempt to read from file in bad state.\n";
00150     return RawEventPtr();
00151   }
00152   if(eof()){
00153     return RawEventPtr();
00154   }
00155   //read depends on file version
00156   RawEventPtr next(new RawEvent);
00157   
00158   switch(_ghead.event_header_version){
00159   case 0:{
00160     //event data in this generation of file is not internally zipped
00161     //consists only of V172X blocks after the legacy header
00162     uint32_t evsize = _ehead.event_size - sizeof(event_header_v0);
00163     int blockn = next->AddDataBlock(RawEvent::CAEN_V172X, evsize);
00164     int bytes_read = gzread(_fin, next->GetRawDataBlock(blockn), evsize);
00165     if(ErrorCheck(bytes_read, evsize))
00166       return RawEventPtr();
00167     break;
00168   }
00169   case latest_event_version: {
00170     //this event structure has individually zipped data blocks
00171     datablock_header bh;
00172     uint32_t thisblock = 0;
00173     int bytes_read = 0;
00174     while(thisblock < _ehead.nblocks && 
00175           (uint32_t)bytes_read<_ehead.event_size-sizeof(event_header)){
00176       int head_read = gzread(_fin, &bh, sizeof(bh));
00177       if(ErrorCheck(head_read, sizeof(bh)))
00178         return RawEventPtr();
00179       //create datablock in the raw event
00180       int blockn = next->AddDataBlock(bh.type, bh.datasize);
00181       //read the compressed block into a temporary buffer
00182       std::vector<char> buf(bh.total_blocksize_disk);
00183       int block_read = gzread(_fin, &(buf[0]), 
00184                               bh.total_blocksize_disk-sizeof(bh));
00185       if(ErrorCheck(block_read, bh.total_blocksize_disk-sizeof(bh))){
00186         Message(ERROR)<<"Incorrect blocksize for block "<<thisblock<<" in event "
00187                       <<_ehead.event_id;
00188         return RawEventPtr();
00189       }
00190       //unzip the buffer into the RawEvent
00191       uLongf decomp = bh.datasize;
00192       int err = uncompress(next->GetRawDataBlock(blockn), &decomp,
00193                            (Bytef*)(&(buf[0])), block_read);
00194       if(err != Z_OK){
00195         Message(ERROR)<<"uncompress function returned "<<err
00196                       <<" while reading event!\n";
00197         return RawEventPtr();
00198       }
00199       next->SetDataBlockSize(blockn,decomp);
00200       //done with this block
00201       thisblock++;
00202       bytes_read += head_read + block_read;
00203     }
00204     //make sure everything got read
00205     if((uint32_t)bytes_read != _ehead.event_size-sizeof(event_header) || 
00206        thisblock != _ehead.nblocks){
00207       Message(ERROR)<<"The event with id "<<_ehead.event_id
00208                     <<" was not fully read out!\n";
00209       return RawEventPtr();
00210     }
00211     break;
00212   }
00213   default:
00214     Message(CRITICAL)<<"Unknown event header version number!\n";
00215     return RawEventPtr();
00216   }//end switch on event head version
00217   
00218   //if we get here everything seems ok
00219   next->SetID(_ehead.event_id);
00220   next->SetTimestamp(_ehead.timestamp);
00221   if(_ghead.global_header_version > 0)
00222     next->SetRunID(_ghead.run_id);
00223   
00224   _current_index++;
00225   _current_event = next;
00226   return next;
00227 }
00228 
00229 RawEventPtr Reader::GetLastEvent()
00230 {
00231   if(!_ok){
00232     Message(ERROR)<<"Attempt to read from file in bad state.\n";
00233     return RawEventPtr();
00234   }
00235   int last_id=0;
00236   while(!ReadNextHeader()){
00237     last_id = _ehead.event_id;
00238     SkipNextEvent(false);
00239   }
00240   if(!_ok) 
00241     return RawEventPtr();
00242   Reset();
00243   return GetEventWithID(last_id);
00244 }
00245  
00246 
00247 RawEventPtr Reader::GetEventWithIndex(int index)
00248 {
00249   if(!_ok){
00250     Message(ERROR)<<"Attempt to read from file in bad state.\n";
00251     return RawEventPtr();
00252   }
00253   if(index == _current_index) 
00254     return _current_event;
00255   //we can't read backward one event at a time, so if requested index
00256   //is lower than current, we have to rewind the whole file
00257   if(index < _current_index){
00258     Message(DEBUG)<<"Rewinding raw file...\n";
00259     Reset();
00260   }
00261   //Now we can go looking for the right one
00262   while(_ok && _current_index < index-1){
00263     if(SkipNextEvent())
00264       return RawEventPtr();
00265   }
00266   //if here, either we are ready to read the next event, or there was an error
00267   if(!_ok || _end_last_file)
00268     return RawEventPtr();
00269   else if(_current_index == index-1)
00270     return GetNextEvent();
00271   else{
00272     Message(ERROR)<<"Unknown problem occurred trying to seek to index "
00273                   <<index<<"\n";
00274     return RawEventPtr();
00275   }
00276 }
00277 
00278 RawEventPtr Reader::GetEventWithID(uint32_t id)
00279 {
00280   if(!_ok){
00281     Message(ERROR)<<"Attempt to read from file in bad state.\n";
00282     return RawEventPtr();
00283   }
00284   if(id == 0){
00285     Reset();
00286     return GetNextEvent();
00287   }
00288   if(id == _ehead.event_id)
00289     return _current_event;
00290   //we can't read backward one event at a time, so if requested id
00291   //is lower than current, we have to rewind the whole file
00292   if(id != 0 && id < _ehead.event_id ){
00293     Message(DEBUG)<<"Rewinding raw file...\n;";
00294     if(Reset())
00295       return RawEventPtr();
00296   }
00297   //see if we're in the right file
00298   while( _ghead.global_header_version > 0 && _ghead.event_id_max > 0 &&
00299          _ghead.nevents>0 && id > _ghead.event_id_max ){
00300     if(OpenNextFile()){
00301       Message(ERROR)<<"Event with id "<<id
00302                     <<" is not present in this file set.\n";
00303       return RawEventPtr();
00304     }
00305   }
00306   
00307   while(_ok && !_end_last_file ){
00308     //read in the current header so we know how long to seek
00309     if(ReadNextHeader())
00310       return RawEventPtr();
00311     if(_ehead.event_id == id){
00312       return GetNextEvent(false);
00313     }
00314     else if(_ehead.event_id > id){
00315       Message(ERROR)<<"Event with id "<<id<<" is not present in this file.\n";
00316       return RawEventPtr();
00317     }
00318     //still deeper in the file; skip to next
00319     SkipNextEvent(false);
00320   }
00321   //if here, either we are ready to read the next event, or there was an error
00322   if(!_ok || _end_last_file)
00323     return RawEventPtr();
00324   //we shouldn't really get here...
00325   return _current_event;
00326 }
00327 
00328 bool Reader::GetAssociatedParameter(VParameterNode* par, std::string key)
00329 {       
00330   if(key == "") 
00331     key = par->GetDefaultKey();
00332   bool cfg_found = true;
00333   if(!(par->ReadFromFile((_filename+".cfg").c_str(),key,true))){
00334     //ok, that didn't work, try removing a possible .gz suffix
00335     std::string fnamecopy(_filename);
00336     fnamecopy.resize(fnamecopy.size()-3);
00337     if(!(par->ReadFromFile((fnamecopy+".cfg").c_str(),
00338                            key, true))){
00339       //that still didn't work.  Print a message and give up
00340       Message(INFO)<<"Unable to find associated config file.\n";
00341       cfg_found = false;
00342     }
00343   }
00344   return cfg_found;
00345 }
00346 
00347 int Reader::Reset()
00348 {
00349   if(!_ok)
00350     return 0;
00351   if(_fin)
00352     CloseCurrentFile();
00353   _current_file_index = _unset_file_index;
00354   _current_index = -1;
00355   _current_event = RawEventPtr();
00356   _ehead.reset();
00357   _end_last_file = false;
00358   return OpenNextFile();
00359 }
00360 
00361 int Reader::CloseCurrentFile()
00362 {
00363   if(_fin)
00364     gzclose(_fin);
00365   _fin = 0;
00366   return 0;
00367 }
00368 
00369 int Reader::OpenNextFile()
00370 {
00371   using std::string;
00372   if(_fin)
00373     CloseCurrentFile();
00374   if(_current_file_index == _unset_file_index && 
00375      ( _filename.substr(_filename.size()-7) == ".out.gz" ||
00376        _filename.substr(_filename.size()-4) == ".out"       ) ){
00377     //we haven't tried to open anything yet, so this may be the first file
00378     //we don't know if this is the old or new file system, try the old first
00379     Message(DEBUG)<<"Attempting to open file "<<_filename.c_str()
00380                   <<" as legacy format."<<std::endl;
00381     _current_file_name = _filename;
00382     _fin = gzopen(_current_file_name.c_str(),"rb");
00383   }
00384   if(!_fin && _current_file_name != _filename){
00385     //we have already opened a previous split file
00386     std::stringstream fname;
00387     fname<<_current_file_name.substr(0,_current_file_name.size()-7)
00388          <<std::setw(3)<<std::setfill('0')<<_current_file_index+1 <<".out";
00389     _current_file_name = fname.str();
00390     Message(DEBUG)<<"Next file in series should be "<<_current_file_name
00391                   <<"\n";
00392     _fin = gzopen(_current_file_name.c_str(),"rb");
00393   }
00394   if(!_fin){
00395     Message(DEBUG)<<"No file with name "<<_filename<<" exists; "
00396                   <<"trying alterations for new format.\n";
00397     //try opening the first split
00398     //format is FILE.###.out, ### is file index
00399     string filename = _filename;
00400     size_t last_slash = filename.rfind('/');
00401 
00402     string dirpart="", filepart=filename;
00403     if(last_slash == filename.size()-1){
00404       dirpart = filename;
00405       filepart = "";
00406     }
00407     else if(last_slash != string::npos){
00408       dirpart = filename.substr(0, last_slash+1);
00409       filepart = filename.substr(last_slash+1, string::npos);
00410     }
00411     
00412     //first, try removing suffixes one at a time from the filename part
00413     // and appending .###.out
00414     while(!filepart.empty()){
00415       std::stringstream fname;
00416       fname<<dirpart<<filepart<<"."
00417            <<std::setw(3)<<std::setfill('0')<<_current_file_index+1<<".out";
00418       _current_file_name = fname.str();
00419       Message(DEBUG2)<<"Testing filename "<<_current_file_name<<" ...\n";
00420       _fin = gzopen(_current_file_name.c_str(),"rb");
00421       if(_fin)
00422         break;
00423       size_t last_dot = filepart.rfind('.');
00424       if(last_dot == string::npos)
00425         break;
00426       filepart.resize(last_dot);
00427     }
00428 
00429     if(!_fin){
00430       //we may be pointing to a directory, which could be either the filepart
00431       // or last bit of dirpart
00432       if(!filepart.empty()){
00433         dirpart += filepart + "/";
00434         std::stringstream fname;
00435         fname<<dirpart<<filepart<<"."
00436              <<std::setw(3)<<std::setfill('0')<<_current_file_index+1<<".out";
00437         _current_file_name = fname.str();
00438         Message(DEBUG2)<<"Testing filename "<<_current_file_name<<" ...\n";
00439         _fin = gzopen(_current_file_name.c_str(),"rb");
00440       }
00441       else{
00442         //if we get here, the filename command ended in /, so try to extract it
00443         if(!dirpart.empty() && dirpart[dirpart.size()-1]=='/'){
00444           last_slash = dirpart.rfind('/',dirpart.size()-2);
00445           if(last_slash == string::npos)
00446             last_slash = -1;
00447           filepart = dirpart.substr(last_slash+1,string::npos);
00448           filepart.resize(filepart.size()-1);
00449           std::stringstream fname;
00450           fname<<dirpart<<filepart<<"."
00451                <<std::setw(3)<<std::setfill('0')<<_current_file_index+1
00452                <<".out";
00453           _current_file_name = fname.str();
00454           Message(DEBUG2)<<"Testing filename "<<_current_file_name<<" ...\n";
00455           _fin = gzopen(_current_file_name.c_str(),"rb");
00456         }
00457       }//end check on dirpart empty
00458     }//end trying a directory
00459     if(_fin){
00460       _current_file_index++;
00461       //_filename = dirpart + filepart;
00462     }
00463   }
00464   
00465   if(!_fin){
00466     if(_current_file_index == _unset_file_index){
00467       Message(ERROR)<<"Unable to open file "<<_filename<<" for reading!\n";
00468       _ok = false;
00469     }
00470     _end_last_file = true;
00471     return 1;
00472   }
00473   
00474   _ehead.reset();
00475   //read in the global file header
00476   //assume we're using the latest header, then check to make sure
00477   gzread(_fin, &_ghead, _ghead.global_header_size);
00478   //check the magic number in the first 4 bytes
00479   if(_ghead.magic_num_check != magic_number){
00480     //we are in a legacy (pre-header) file
00481     _ghead.global_header_version = 0;
00482     _ghead.event_header_version = 0;
00483     _ghead.run_id = 0;
00484     _ghead.nevents = 0;
00485     _ghead.event_id_min = 0;
00486     _ghead.event_id_max = 0;
00487     _current_file_index = 0;
00488     gzrewind(_fin);
00489   }
00490   else{ 
00491     if(_ghead.global_header_version != latest_global_version || 
00492        _ghead.event_header_version != latest_event_version){
00493       //handle future version number updates here
00494       Message(CRITICAL)<<"Header version number stored in this file is larger"
00495                        <<" than latest version!\n";
00496       throw std::out_of_range("incorrect header version number");
00497     }
00498     else if(_ghead.global_header_size != sizeof(global_header) || 
00499             _ghead.event_header_size != sizeof(event_header) ){
00500       Message(CRITICAL)<<"Incorrect size of headers in raw file!\n";
00501       throw std::out_of_range("incorrect header size");
00502     }
00503     Message(DEBUG)<<"Successfully opened file "<<_current_file_name
00504                   <<"\nFile header information:"
00505                   <<"\n\tMagic number: 0x"<<std::hex<<_ghead.magic_num_check
00506                   <<std::dec
00507                   <<"\n\tHeader size: "<<_ghead.global_header_size
00508                   <<"\n\tHeader version: "<<_ghead.global_header_version
00509                   <<"\n\tEvent header size: "<<_ghead.event_header_size
00510                   <<"\n\tEvent header version: "<<_ghead.event_header_version
00511                   <<"\n\tStart time: "<<_ghead.start_time
00512                   <<"\n\tEnd time: "<<_ghead.end_time
00513                   <<"\n\tRun ID: "<<_ghead.run_id
00514                   <<"\n\tFileIndex: "<<_ghead.file_index
00515                   <<"\n\tEvents: "<<_ghead.nevents
00516                   <<"\n\tMin Event: "<<_ghead.event_id_min
00517                   <<"\n\tMax Event: "<<_ghead.event_id_max
00518                   <<std::endl;
00519     _current_file_index = _ghead.file_index;
00520   }
00521   return 0;
00522 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Defines

Generated on 20 Jun 2014 for daqman by  doxygen 1.6.1