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 */
63 DatagramIterator &FltRecordReader::
64 get_iterator() {
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 */
73 const Datagram &FltRecordReader::
74 get_datagram() {
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 */
85 int FltRecordReader::
86 get_record_length() const {
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 */
198 bool FltRecordReader::
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 */
207 bool FltRecordReader::
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 }
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition: datagramIterator.h:27
DatagramIterator::get_datagram
const Datagram & get_datagram() const
Return the datagram of this iterator.
Definition: datagramIterator.I:462
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition: datagram.h:38
Datagram::append_data
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
Definition: datagram.cxx:129
FltRecordReader::get_opcode
FltOpcode get_opcode() const
Returns the opcode associated with the current record.
Definition: fltRecordReader.cxx:55
FltRecordReader::eof
bool eof() const
Returns true if end-of-file has been reached without error.
Definition: fltRecordReader.cxx:199
FltRecordReader::get_record_length
int get_record_length() const
Returns the entire length of the record, including the four-byte header.
Definition: fltRecordReader.cxx:86
FltRecordReader::error
bool error() const
Returns true if some error has been encountered while reading (for instance, a truncated file).
Definition: fltRecordReader.cxx:208
FltRecordReader::get_iterator
DatagramIterator & get_iterator()
Returns an iterator suitable for extracting data from the current record.
Definition: fltRecordReader.cxx:64
FltRecordReader::advance
FltError advance(bool ok_eof=false)
Extracts the next record from the file.
Definition: fltRecordReader.cxx:95
FltRecordReader::get_datagram
const Datagram & get_datagram()
Returns the datagram representing the entire record, less the four-byte header.
Definition: fltRecordReader.cxx:74
config_flt.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
fltRecordReader.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.