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