Panda3D
 All Classes Functions Variables Enumerations
fltRecordReader.cxx
00001 // Filename: fltRecordReader.cxx
00002 // Created by:  drose (24Aug00)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "fltRecordReader.h"
00016 #include "config_flt.h"
00017 
00018 #include "datagramIterator.h"
00019 
00020 #include <assert.h>
00021 
00022 ////////////////////////////////////////////////////////////////////
00023 //     Function: FltRecordReader::Constructor
00024 //       Access: Public
00025 //  Description:
00026 ////////////////////////////////////////////////////////////////////
00027 FltRecordReader::
00028 FltRecordReader(istream &in) :
00029   _in(in)
00030 {
00031   _opcode = FO_none;
00032   _record_length = 0;
00033   _iterator = (DatagramIterator *)NULL;
00034   _state = S_begin;
00035   _next_error = FE_ok;
00036   _next_opcode = FO_none;
00037   _next_record_length = 0;
00038 
00039   // Read the first header to get us going.
00040   read_next_header();
00041 }
00042 
00043 ////////////////////////////////////////////////////////////////////
00044 //     Function: FltRecordReader::Destructor
00045 //       Access: Public
00046 //  Description:
00047 ////////////////////////////////////////////////////////////////////
00048 FltRecordReader::
00049 ~FltRecordReader() {
00050   if (_iterator != (DatagramIterator *)NULL) {
00051     delete _iterator;
00052     _iterator = (DatagramIterator *)NULL;
00053   }
00054 }
00055 
00056 ////////////////////////////////////////////////////////////////////
00057 //     Function: FltRecordReader::get_opcode
00058 //       Access: Public
00059 //  Description: Returns the opcode associated with the current
00060 //               record.
00061 ////////////////////////////////////////////////////////////////////
00062 FltOpcode FltRecordReader::
00063 get_opcode() const {
00064   nassertr(_state == S_normal, FO_none);
00065   return _opcode;
00066 }
00067 
00068 ////////////////////////////////////////////////////////////////////
00069 //     Function: FltRecordReader::get_iterator
00070 //       Access: Public
00071 //  Description: Returns an iterator suitable for extracting data from
00072 //               the current record.
00073 ////////////////////////////////////////////////////////////////////
00074 DatagramIterator &FltRecordReader::
00075 get_iterator() {
00076   nassertr(_state == S_normal, *_iterator);
00077   return *_iterator;
00078 }
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: FltRecordReader::get_datagram
00082 //       Access: Public
00083 //  Description: Returns the datagram representing the entire record,
00084 //               less the four-byte header.
00085 ////////////////////////////////////////////////////////////////////
00086 const Datagram &FltRecordReader::
00087 get_datagram() {
00088 #ifndef NDEBUG
00089   static Datagram bogus_datagram;
00090   nassertr(_state == S_normal, bogus_datagram);
00091 #endif
00092   return _iterator->get_datagram();
00093 }
00094 
00095 ////////////////////////////////////////////////////////////////////
00096 //     Function: FltRecordReader::get_record_length
00097 //       Access: Public
00098 //  Description: Returns the entire length of the record, including
00099 //               the four-byte header.
00100 ////////////////////////////////////////////////////////////////////
00101 int FltRecordReader::
00102 get_record_length() const {
00103   return _record_length;
00104 }
00105 
00106 ////////////////////////////////////////////////////////////////////
00107 //     Function: FltRecordReader::advance
00108 //       Access: Public
00109 //  Description: Extracts the next record from the file.  Returns true
00110 //               if there is another record, or false if the end of
00111 //               file has been reached.
00112 ////////////////////////////////////////////////////////////////////
00113 FltError FltRecordReader::
00114 advance(bool ok_eof) {
00115   if (_state == S_eof) {
00116     assert(!flt_error_abort);
00117     return FE_end_of_file;
00118   }
00119   if (_state == S_error) {
00120     assert(!flt_error_abort);
00121     return FE_read_error;
00122   }
00123   if (_iterator != (DatagramIterator *)NULL) {
00124     delete _iterator;
00125     _iterator = (DatagramIterator *)NULL;
00126   }
00127 
00128   if (_next_error == FE_end_of_file) {
00129     _state = S_eof;
00130     if (ok_eof) {
00131       return FE_ok;
00132     }
00133     assert(!flt_error_abort);
00134     return FE_end_of_file;
00135 
00136   } else if (_next_error != FE_ok) {
00137     _state = S_error;
00138     assert(!flt_error_abort);
00139     return _next_error;
00140   }
00141 
00142   _opcode = _next_opcode;
00143   _record_length = _next_record_length;
00144 
00145   if (flt_cat.is_debug()) {
00146     flt_cat.debug()
00147       << "Reading " << _opcode
00148       << " of length " << _record_length << "\n";
00149   }
00150 
00151   // And now read the full record based on the length.
00152   int length = _next_record_length - header_size;
00153   char *buffer = new char[length];
00154   if (length > 0) {
00155     _in.read(buffer, length);
00156   }
00157   _datagram = Datagram(buffer, length);
00158   delete[] buffer;
00159 
00160   if (_in.eof()) {
00161     _state = S_eof;
00162     assert(!flt_error_abort);
00163     return FE_end_of_file;
00164   }
00165 
00166   if (_in.fail()) {
00167     _state = S_error;
00168     assert(!flt_error_abort);
00169     return FE_read_error;
00170   }
00171 
00172   // Check out the next header in case it's a continuation.
00173   read_next_header();
00174   while (_next_error == FE_ok && _next_opcode == FO_continuation) {
00175     if (flt_cat.is_debug()) {
00176       flt_cat.debug()
00177         << "Reading continuation of length " << _next_record_length << "\n";
00178     }
00179 
00180     // Read the continuation and tack it on.
00181     _record_length += _next_record_length;
00182     length = _next_record_length - header_size;
00183 
00184     buffer = new char[length];
00185     if (length > 0) {
00186       _in.read(buffer, length);
00187     }
00188     _datagram.append_data(buffer, length);
00189     delete[] buffer;
00190 
00191     if (_in.eof()) {
00192       _state = S_eof;
00193       assert(!flt_error_abort);
00194       return FE_end_of_file;
00195     }
00196 
00197     if (_in.fail()) {
00198       _state = S_error;
00199       assert(!flt_error_abort);
00200       return FE_read_error;
00201     }
00202 
00203     read_next_header();
00204   }
00205 
00206   // Finally, create a new iterator to read this record.
00207   _iterator = new DatagramIterator(_datagram);
00208   _state = S_normal;
00209 
00210   return FE_ok;
00211 }
00212 
00213 ////////////////////////////////////////////////////////////////////
00214 //     Function: FltRecordReader::eof
00215 //       Access: Public
00216 //  Description: Returns true if end-of-file has been reached without
00217 //               error.
00218 ////////////////////////////////////////////////////////////////////
00219 bool FltRecordReader::
00220 eof() const {
00221   return _state == S_eof;
00222 }
00223 
00224 ////////////////////////////////////////////////////////////////////
00225 //     Function: FltRecordReader::error
00226 //       Access: Public
00227 //  Description: Returns true if some error has been encountered while
00228 //               reading (for instance, a truncated file).
00229 ////////////////////////////////////////////////////////////////////
00230 bool FltRecordReader::
00231 error() const {
00232   return _state == S_error;
00233 }
00234 
00235 ////////////////////////////////////////////////////////////////////
00236 //     Function: FltRecordReader::read_next_header
00237 //       Access: Private
00238 //  Description: Reads the four-byte header for the next record, which
00239 //               contains the next opcode and record length.
00240 //
00241 //               We need read the next header in advance so we can
00242 //               check to see if it happens to be a continuation
00243 //               record.  If it is, we will need to concatenate the
00244 //               records together before returning.
00245 ////////////////////////////////////////////////////////////////////
00246 void FltRecordReader::
00247 read_next_header() {
00248   char bytes[header_size];
00249   _in.read(bytes, header_size);
00250 
00251   if (_in.eof()) {
00252     _next_error = FE_end_of_file;
00253     return;
00254 
00255   } else if (_in.fail()) {
00256     _next_error = FE_read_error;
00257     return;
00258   }
00259 
00260   // Now extract out the opcode and length.
00261   Datagram dg(bytes, header_size);
00262   DatagramIterator dgi(dg);
00263   _next_opcode = (FltOpcode)dgi.get_be_int16();
00264   _next_record_length = dgi.get_be_uint16();
00265 
00266   if (_next_record_length < header_size) {
00267     _next_error = FE_invalid_record;
00268     return;
00269   }
00270 }
 All Classes Functions Variables Enumerations