Panda3D
|
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 }