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  if (length > 0) {
135  vector_uchar data((size_t)length);
136  _in.read((char *)&data[0], length);
137  _datagram = Datagram(std::move(data));
138  } else {
139  _datagram = Datagram();
140  }
141 
142  if (_in.fail()) {
143  if (_in.eof()) {
144  _state = S_eof;
145  assert(!flt_error_abort);
146  return FE_end_of_file;
147  }
148 
149  _state = S_error;
150  assert(!flt_error_abort);
151  return FE_read_error;
152  }
153 
154  // Check out the next header in case it's a continuation.
155  read_next_header();
156  while (_next_error == FE_ok && _next_opcode == FO_continuation) {
157  if (flt_cat.is_debug()) {
158  flt_cat.debug()
159  << "Reading continuation of length " << _next_record_length << "\n";
160  }
161 
162  // Read the continuation and tack it on.
163  _record_length += _next_record_length;
164  length = _next_record_length - header_size;
165 
166  if (length > 0) {
167  char *buffer = new char[length];
168  _in.read(buffer, length);
169  _datagram.append_data(buffer, length);
170  delete[] buffer;
171  }
172 
173  if (_in.fail()) {
174  if (_in.eof()) {
175  _state = S_eof;
176  assert(!flt_error_abort);
177  return FE_end_of_file;
178  }
179 
180  _state = S_error;
181  assert(!flt_error_abort);
182  return FE_read_error;
183  }
184 
185  read_next_header();
186  }
187 
188  // Finally, create a new iterator to read this record.
189  _iterator = new DatagramIterator(_datagram);
190  _state = S_normal;
191 
192  return FE_ok;
193 }
194 
195 /**
196  * Returns true if end-of-file has been reached without error.
197  */
199 eof() const {
200  return _state == S_eof;
201 }
202 
203 /**
204  * Returns true if some error has been encountered while reading (for
205  * instance, a truncated file).
206  */
208 error() const {
209  return _state == S_error;
210 }
211 
212 /**
213  * Reads the four-byte header for the next record, which contains the next
214  * opcode and record length.
215  *
216  * We need read the next header in advance so we can check to see if it
217  * happens to be a continuation record. If it is, we will need to concatenate
218  * the records together before returning.
219  */
220 void FltRecordReader::
221 read_next_header() {
222  char bytes[header_size];
223  _in.read(bytes, header_size);
224 
225  if (_in.fail()) {
226  if (_in.eof()) {
227  _next_error = FE_end_of_file;
228  return;
229  }
230  _next_error = FE_read_error;
231  return;
232  }
233 
234  // Now extract out the opcode and length.
235  Datagram dg(bytes, header_size);
236  DatagramIterator dgi(dg);
237  _next_opcode = (FltOpcode)dgi.get_be_int16();
238  _next_record_length = dgi.get_be_uint16();
239 
240  if (_next_record_length < header_size) {
241  _next_error = FE_invalid_record;
242  return;
243  }
244 }
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.