Panda3D
fltRecordReader.cxx
1 // Filename: fltRecordReader.cxx
2 // Created by: drose (24Aug00)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "fltRecordReader.h"
16 #include "config_flt.h"
17 
18 #include "datagramIterator.h"
19 
20 #include <assert.h>
21 
22 ////////////////////////////////////////////////////////////////////
23 // Function: FltRecordReader::Constructor
24 // Access: Public
25 // Description:
26 ////////////////////////////////////////////////////////////////////
27 FltRecordReader::
28 FltRecordReader(istream &in) :
29  _in(in)
30 {
31  _opcode = FO_none;
32  _record_length = 0;
33  _iterator = (DatagramIterator *)NULL;
34  _state = S_begin;
35  _next_error = FE_ok;
36  _next_opcode = FO_none;
37  _next_record_length = 0;
38 
39  // Read the first header to get us going.
40  read_next_header();
41 }
42 
43 ////////////////////////////////////////////////////////////////////
44 // Function: FltRecordReader::Destructor
45 // Access: Public
46 // Description:
47 ////////////////////////////////////////////////////////////////////
48 FltRecordReader::
49 ~FltRecordReader() {
50  if (_iterator != (DatagramIterator *)NULL) {
51  delete _iterator;
52  _iterator = (DatagramIterator *)NULL;
53  }
54 }
55 
56 ////////////////////////////////////////////////////////////////////
57 // Function: FltRecordReader::get_opcode
58 // Access: Public
59 // Description: Returns the opcode associated with the current
60 // record.
61 ////////////////////////////////////////////////////////////////////
62 FltOpcode FltRecordReader::
63 get_opcode() const {
64  nassertr(_state == S_normal, FO_none);
65  return _opcode;
66 }
67 
68 ////////////////////////////////////////////////////////////////////
69 // Function: FltRecordReader::get_iterator
70 // Access: Public
71 // Description: Returns an iterator suitable for extracting data from
72 // the current record.
73 ////////////////////////////////////////////////////////////////////
76  nassertr(_state == S_normal, *_iterator);
77  return *_iterator;
78 }
79 
80 ////////////////////////////////////////////////////////////////////
81 // Function: FltRecordReader::get_datagram
82 // Access: Public
83 // Description: Returns the datagram representing the entire record,
84 // less the four-byte header.
85 ////////////////////////////////////////////////////////////////////
88 #ifndef NDEBUG
89  static Datagram bogus_datagram;
90  nassertr(_state == S_normal, bogus_datagram);
91 #endif
92  return _iterator->get_datagram();
93 }
94 
95 ////////////////////////////////////////////////////////////////////
96 // Function: FltRecordReader::get_record_length
97 // Access: Public
98 // Description: Returns the entire length of the record, including
99 // the four-byte header.
100 ////////////////////////////////////////////////////////////////////
103  return _record_length;
104 }
105 
106 ////////////////////////////////////////////////////////////////////
107 // Function: FltRecordReader::advance
108 // Access: Public
109 // Description: Extracts the next record from the file. Returns true
110 // if there is another record, or false if the end of
111 // file has been reached.
112 ////////////////////////////////////////////////////////////////////
113 FltError FltRecordReader::
114 advance(bool ok_eof) {
115  if (_state == S_eof) {
116  assert(!flt_error_abort);
117  return FE_end_of_file;
118  }
119  if (_state == S_error) {
120  assert(!flt_error_abort);
121  return FE_read_error;
122  }
123  if (_iterator != (DatagramIterator *)NULL) {
124  delete _iterator;
125  _iterator = (DatagramIterator *)NULL;
126  }
127 
128  if (_next_error == FE_end_of_file) {
129  _state = S_eof;
130  if (ok_eof) {
131  return FE_ok;
132  }
133  assert(!flt_error_abort);
134  return FE_end_of_file;
135 
136  } else if (_next_error != FE_ok) {
137  _state = S_error;
138  assert(!flt_error_abort);
139  return _next_error;
140  }
141 
142  _opcode = _next_opcode;
143  _record_length = _next_record_length;
144 
145  if (flt_cat.is_debug()) {
146  flt_cat.debug()
147  << "Reading " << _opcode
148  << " of length " << _record_length << "\n";
149  }
150 
151  // And now read the full record based on the length.
152  int length = _next_record_length - header_size;
153  char *buffer = new char[length];
154  if (length > 0) {
155  _in.read(buffer, length);
156  }
157  _datagram = Datagram(buffer, length);
158  delete[] buffer;
159 
160  if (_in.eof()) {
161  _state = S_eof;
162  assert(!flt_error_abort);
163  return FE_end_of_file;
164  }
165 
166  if (_in.fail()) {
167  _state = S_error;
168  assert(!flt_error_abort);
169  return FE_read_error;
170  }
171 
172  // Check out the next header in case it's a continuation.
173  read_next_header();
174  while (_next_error == FE_ok && _next_opcode == FO_continuation) {
175  if (flt_cat.is_debug()) {
176  flt_cat.debug()
177  << "Reading continuation of length " << _next_record_length << "\n";
178  }
179 
180  // Read the continuation and tack it on.
181  _record_length += _next_record_length;
182  length = _next_record_length - header_size;
183 
184  buffer = new char[length];
185  if (length > 0) {
186  _in.read(buffer, length);
187  }
188  _datagram.append_data(buffer, length);
189  delete[] buffer;
190 
191  if (_in.eof()) {
192  _state = S_eof;
193  assert(!flt_error_abort);
194  return FE_end_of_file;
195  }
196 
197  if (_in.fail()) {
198  _state = S_error;
199  assert(!flt_error_abort);
200  return FE_read_error;
201  }
202 
203  read_next_header();
204  }
205 
206  // Finally, create a new iterator to read this record.
207  _iterator = new DatagramIterator(_datagram);
208  _state = S_normal;
209 
210  return FE_ok;
211 }
212 
213 ////////////////////////////////////////////////////////////////////
214 // Function: FltRecordReader::eof
215 // Access: Public
216 // Description: Returns true if end-of-file has been reached without
217 // error.
218 ////////////////////////////////////////////////////////////////////
220 eof() const {
221  return _state == S_eof;
222 }
223 
224 ////////////////////////////////////////////////////////////////////
225 // Function: FltRecordReader::error
226 // Access: Public
227 // Description: Returns true if some error has been encountered while
228 // reading (for instance, a truncated file).
229 ////////////////////////////////////////////////////////////////////
231 error() const {
232  return _state == S_error;
233 }
234 
235 ////////////////////////////////////////////////////////////////////
236 // Function: FltRecordReader::read_next_header
237 // Access: Private
238 // Description: Reads the four-byte header for the next record, which
239 // contains the next opcode and record length.
240 //
241 // We need read the next header in advance so we can
242 // check to see if it happens to be a continuation
243 // record. If it is, we will need to concatenate the
244 // records together before returning.
245 ////////////////////////////////////////////////////////////////////
246 void FltRecordReader::
247 read_next_header() {
248  char bytes[header_size];
249  _in.read(bytes, header_size);
250 
251  if (_in.eof()) {
252  _next_error = FE_end_of_file;
253  return;
254 
255  } else if (_in.fail()) {
256  _next_error = FE_read_error;
257  return;
258  }
259 
260  // Now extract out the opcode and length.
261  Datagram dg(bytes, header_size);
262  DatagramIterator dgi(dg);
263  _next_opcode = (FltOpcode)dgi.get_be_int16();
264  _next_record_length = dgi.get_be_uint16();
265 
266  if (_next_record_length < header_size) {
267  _next_error = FE_invalid_record;
268  return;
269  }
270 }
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
Definition: datagram.cxx:144
const Datagram & get_datagram() const
Return the datagram of this iterator.
bool error() const
Returns true if some error has been encountered while reading (for instance, a truncated file)...
DatagramIterator & get_iterator()
Returns an iterator suitable for extracting data from the current record.
const Datagram & get_datagram()
Returns the datagram representing the entire record, less the four-byte header.
PN_int16 get_be_int16()
Extracts a signed 16-bit big-endian integer.
FltOpcode get_opcode() const
Returns the opcode associated with the current record.
A class to retrieve the individual data elements previously stored in a Datagram. ...
PN_uint16 get_be_uint16()
Extracts an unsigned 16-bit big-endian integer.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:43
FltError advance(bool ok_eof=false)
Extracts the next record from the file.
bool eof() const
Returns true if end-of-file has been reached without error.
int get_record_length() const
Returns the entire length of the record, including the four-byte header.