Follow this link to skip to the main content

fdm_cdr_file.cc

Go to the documentation of this file.
00001 // -*-c++-*- 
00002 //---------------------------< /-/ CLARAty /-/ >------------------------------
00003 /** 
00004  * @file  fdm_cdr_file.cc
00005  *
00006  * FDM CDR file utilities.
00007  *
00008  * <br>@b Designer(s):  Anne Wright
00009  * <br>@b Author(s):    Anne Wright
00010  * <br>@b Date:         April 12, 2003
00011  *
00012  * <b>Software License:</b><br>
00013  * <code>  http://claraty.jpl.nasa.gov/license/open_src/  or
00014  *         file: license/open_src.txt  </code>
00015  *
00016  * &copy; 2006, Jet Propulsion Laboratory, California Institute of Technology<br>
00017  * &copy; 2006, NASA Ames Research Center
00018  *
00019  * $Revision: 1.2 $
00020  */ 
00021 //-----------------------------------------------------------------------------
00022 
00023 #include "claraty/fdm_cdr_file.h"
00024 #include <map>
00025 
00026 using namespace std;
00027 
00028 FDM_CDR_File::FDM_CDR_File(FDM::Direction dir) : 
00029     FDM_CDR(dir), _conn(), _io_file(NULL), _file_ok(false), 
00030     _file_eof(false), _got_block(false), _topform_typename("")
00031 {
00032 }
00033 
00034 FDM_CDR_File::FDM_CDR_File(const string &filename,
00035                            FDM::Direction dir, bool append) : 
00036   FDM_CDR(dir), _conn(), _io_file(NULL), _file_ok(false),
00037   _file_eof(false), _got_block(false), _topform_typename("")
00038 {
00039   open(filename, append);
00040 }
00041 
00042 FDM_CDR_File::FDM_CDR_File(auto_ptr<ACE_FILE_IO> fio, FDM::Direction dir): 
00043   FDM_CDR(dir), _conn(), _io_file(NULL), _file_ok(false), 
00044   _file_eof(false), _got_block(false), _topform_typename("")
00045 {
00046   if(fio.get()!=NULL) {
00047     _io_file = fio.release();
00048     _file_ok=true;
00049   }
00050 }
00051 FDM_CDR_File::~FDM_CDR_File() {
00052   close();
00053 }
00054 
00055 bool 
00056 FDM_CDR_File::open(const string &filename, bool append) 
00057 {
00058   if(_io_file!=NULL) {
00059     // destruct old file, should close it
00060     delete _io_file;
00061     _io_file = NULL;
00062     _file_ok = false;
00063   }
00064   // Create a new _io_file
00065   _io_file = new ACE_FILE_IO();
00066   _file_ok = false;
00067 
00068   if(is_read()) {
00069     // Try to open the file
00070     if(_conn.connect (*_io_file, 
00071                       ACE_FILE_Addr (filename.c_str()),
00072                       0, // No timeout.
00073                       ACE_Addr::sap_any, // Ignored.
00074                       0, // Don't try to reuse the addr.
00075                       O_RDONLY,
00076                       ACE_DEFAULT_FILE_PERMS) < 0) {
00077       // Open failed, return false
00078       _file_ok=false;
00079       return(false);
00080     }
00081     // Opened the file ok, reset flags
00082     _file_ok=true;
00083     _file_eof=false;
00084     _got_block=false;
00085     return(true);
00086   }
00087   else {                        // Writing
00088     // Try to open the file for write, TODO: append option
00089     int appflag = (append) ? (O_APPEND) : (O_TRUNC);
00090     if(_conn.connect (*_io_file, 
00091                       ACE_FILE_Addr (filename.c_str()),
00092                       0, // No timeout.
00093                       ACE_Addr::sap_any, // Ignored.
00094                       0, // Don't try to reuse the addr.
00095                       O_RDWR|O_CREAT|appflag,
00096                       ACE_DEFAULT_FILE_PERMS) < 0) {
00097       // Open failed, return false
00098       _file_ok=false;
00099       return(false);
00100     }
00101     // Opened the file ok
00102     _file_ok=true;
00103     _file_eof=false;
00104     return(true);
00105 
00106   }
00107 }
00108 
00109 void 
00110 FDM_CDR_File::close() 
00111 {
00112   if(_io_file != NULL) {
00113     if(is_write() && _file_ok && _ostr != NULL) {
00114       // Make sure everything's been written
00115       flush();
00116     }
00117     delete _io_file;
00118     _io_file = NULL;
00119   }
00120   _file_ok = false;
00121 }
00122 
00123 bool 
00124 FDM_CDR_File::_read_block(auto_ptr<ACE_Message_Block> &msg)
00125 {
00126   if(!_file_ok || _file_eof || _io_file == NULL) {
00127     return(false);
00128   }
00129 
00130   // Deal with the Header
00131   ACE_Message_Block header(ACE_DEFAULT_CDR_BUFSIZE);
00132   // The header has 4 character ID and an unsigned long that is length
00133   ACE_CDR::mb_align(&header);
00134 
00135   // Read the header from the file
00136   size_t nread;
00137   nread = _io_file->recv_n(header.wr_ptr(), 8);
00138   if(nread == 0) {
00139     // EOF
00140     _file_eof = true;
00141     return(false);
00142   }
00143   else if(nread != 8) {
00144     cerr << "fdm_cdr_       file: ..ader file read failed" << endl;
00145     _file_ok = false;
00146     return(false);
00147   }
00148   // Advance the write pointer
00149   header.wr_ptr(8);
00150 
00151   // Parse the header
00152   ACE_InputCDR h_in(&header);
00153   char idstr[5];
00154   ACE_CDR::ULong len;
00155   bool ok = true;
00156 
00157   // Read and null-terminate 4-byte id string
00158   ok &= h_in.read_char_array(idstr, 4);
00159   idstr[4] = 0;
00160   // Read length of following data block
00161   ok &= h_in.read_ulong(len);
00162 
00163   if(!ok || string(idstr) != FDM_CDR_FILETAG) {
00164     cerr << "fdm_cdr_       file: ..ader read failed" << endl;
00165     _file_ok = false;
00166     return(false);
00167   }
00168 
00169   // We now know the length, create and fill an appropriate message block
00170   // for the payload
00171   msg.reset(new ACE_Message_Block(len + ACE_CDR::MAX_ALIGNMENT));
00172   ACE_CDR::mb_align(msg.get());
00173     
00174   size_t remsize = len;
00175   bool done=false;
00176 
00177   while(!done) {
00178     nread = _io_file->recv(msg->wr_ptr(), remsize);
00179     if(nread == 0) {
00180       // Assume EOF, TODO: how would we do better?
00181       _file_eof = true;
00182       return(true);
00183     }
00184     remsize -= nread;
00185     msg->wr_ptr(nread);
00186 
00187     if(remsize == 0) {
00188       done=true;
00189     }
00190   }
00191   return(true);
00192 }
00193 
00194 bool
00195 FDM_CDR_File::_write_block(const ACE_Message_Block &msg)
00196 {
00197   if(!_file_ok || _file_eof || _io_file == NULL) {
00198     return(false);
00199   }
00200 
00201   // Create Header
00202   ACE_OutputCDR header(ACE_CDR::MAX_ALIGNMENT +8);
00203   ACE_CDR::ULong len = msg.total_length();
00204   bool ok = true;
00205 
00206   ok &= header.write_char_array(FDM_CDR_FILETAG,4);
00207   ok &= header.write_ulong(len);
00208 
00209   // Send header
00210   if(_io_file->send_n(header.begin()) < 0) {
00211     // Write failed
00212     _file_ok = false;
00213     return(false);
00214   }
00215 
00216   // Send message block
00217   if(_io_file->send_n(&msg) < 0) {
00218     // Write failed
00219     _file_ok = false;
00220     return(false);
00221   }
00222   return(true);
00223 }
00224 
00225 bool 
00226 FDM_CDR_File::flush() 
00227 {
00228   const ACE_Message_Block &msg = get_message_block();
00229   if(msg.total_length() == 0) {
00230     // Nothing to write, just return true
00231     return(true);
00232   }
00233   // Something to write, write the existing block
00234   if(_write_block(msg)) {
00235     // Write succeeded, clear the ACE_OutputCDR
00236     clear();
00237     return(true);
00238   }
00239   return(false);
00240 }
00241 
00242 // Helper functions to make the case where there is one object per
00243 // file convenient
00244 bool 
00245 FDM_CDR_File::message_block_to_file(const ACE_Message_Block &mb, 
00246                                     string filename, 
00247                                     bool append)
00248 {
00249   // Create conduit between fdr and the file
00250   FDM_CDR_File out(filename, FDM::Write, append);
00251     
00252   // Put the message block into the output file
00253   return(out._write_block(mb));
00254 }
00255   
00256 // For now only get the first block
00257 bool 
00258 FDM_CDR_File::file_to_message_block(ACE_Message_Block &mb, 
00259                                     const string &filename)
00260 {
00261   // Create conduit between fdr and the file
00262   FDM_CDR_File  in(filename, FDM::Read);
00263 
00264   // Read the first block
00265   if(in._file_ok && in._process_next_block()) {
00266     assert(in._istr!=NULL);
00267     // This copies the data from _istr into mb
00268     ACE_CDR::consolidate(&mb, in._istr->start());
00269     return(true);
00270   }
00271   return(false);
00272 }
00273 
00274 // Debugging
00275 void
00276 FDM_CDR_File::summarize(ostream &os)
00277 {
00278   if(is_write()) {
00279     os << "File type FDM_CDR_File " << endl;
00280     return;
00281   }
00282 
00283   map<std::string,int> bmap;
00284   int i=0;
00285   while(_file_ok && !_file_eof && _process_next_block()) {
00286     // Get the type name
00287     string tname;
00288     if(_io_object(tname)) {
00289       if(bmap.find(tname) == bmap.end()) {
00290         bmap[tname] = 1;
00291       }
00292       else {
00293         bmap[tname]++;
00294       }
00295       i++;
00296     }
00297   }
00298   os << "FDM_CDR_File, " << i << " records";
00299   if(bmap.size()==1) {
00300     os << " of type " << bmap.begin()->first;
00301   }
00302   else {
00303     os << " of the following types: " << endl;
00304     std::map<std::string, int>::const_iterator it = bmap.begin();
00305     for (it = bmap.begin(); it != bmap.end(); it++) {
00306       os << "  " << it->first << "\t[" << it->second << "]" << endl;
00307     }
00308   }
00309 }
00310 bool 
00311 FDM_CDR_File::show_file_contents(ostream &os, const string &filename)
00312 {
00313   // Create conduit between fdr and the file
00314   FDM_CDR_File  in(filename, FDM::Read);
00315 
00316   if(!in._file_ok) {
00317     return(false);
00318   }
00319 
00320   // Read the first block
00321   int i=0;
00322   while(in._file_ok && !in._file_eof && in._process_next_block()) {
00323     assert(in._istr!=NULL);
00324     // Get the type name
00325     string tname="";
00326     in._peek_object(tname);
00327     os << "----------------------------------------------------" << endl;
00328     os << "Block " << i++ << ": Type " << tname << endl;
00329     os << *(in._istr->start());
00330   }
00331   return(true);
00332 }
00333 
00334 bool 
00335 FDM_CDR_File::_start_topform(const char *type_name) 
00336 {
00337   bool ok = true;
00338   // Read the next block if we haven't already
00339   if(is_read() && !_got_block) {
00340     ok &= _process_next_block();
00341   }
00342   // Put or get the type name
00343   _topform_typename = type_name;
00344   _io_object(_topform_typename);
00345   if(is_read()) {
00346     if(_topform_typename != type_name) {
00347       // If reading, _typeform_typename is now what was stored in the block, 
00348       // compare to type_name and warn if different
00349       // This is ok, since sometimes we're reading into a different type, but
00350       // ultimately using the same io routine (most often when reading into an
00351       // auto_ptr of a superclass type via a factory)
00352       /*
00353       cerr << "WARNING: Stored type differs from that requested " << endl
00354            << "   Requested '" << type_name 
00355            << "', Read '" << _topform_typename << endl;
00356       */
00357     }
00358   }
00359   return(ok & FDM_Stream::_start_topform(type_name));
00360 }
00361 bool 
00362 FDM_CDR_File::_end_topform() 
00363 {
00364   bool ok = true;
00365   // If writing, flush output to file
00366   if(is_write()) {
00367     ok &= flush();
00368   }
00369   else {
00370     // Reading, record that we don't have the next block yet
00371     _got_block=false;
00372     // Check that we read it all, print warning if not
00373     if(_istr->length() != 0) {
00374       cerr << "WARNING: In fdm_cdr_file, " << _istr->length()
00375            << " bytes left in read block, skipping" << endl;
00376     }
00377   }
00378   return(ok);
00379 }
00380 
00381 bool 
00382 FDM_CDR_File::_process_next_block()
00383 {
00384   if(!_file_ok || _file_eof || _io_file == NULL) {
00385     return(false);
00386   }
00387 
00388   auto_ptr<ACE_Message_Block> msg;
00389   // This is guaranteed to create a single, non-chained message block
00390   bool ok = _read_block(msg);
00391   if(!ok) {
00392     _file_ok=false;
00393     return(false);
00394   }
00395   // Make sure that read_block didn't return a chain
00396   assert(msg.get()!=NULL && msg->cont()==NULL);
00397   set_message_block(*msg);
00398 
00399   // Mark that we already got the next block
00400   _got_block = true;
00401 
00402   // set_read_data makes a consolidated copy, so the message block
00403   // we allocated while reading can now be freed, which the auto_ptr
00404   // takes care of for us.
00405   return(true);
00406 }      
00407 
00408 bool 
00409 FDM_CDR_File::_check_streams(size_t size) 
00410 {
00411   bool ok = FDM_CDR::_check_streams(size);
00412   if(!ok || !_file_ok || _io_file==NULL) {
00413     // Something fundamental is wrong, fail
00414     return(false);
00415   }
00416   return(true);
00417 }