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