Panda3D
Loading...
Searching...
No Matches
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 */
24FltRecordReader::
25FltRecordReader(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 */
43FltRecordReader::
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 */
55get_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 */
86get_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 */
95advance(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 */
199eof() 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 */
208error() 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 */
220void FltRecordReader::
221read_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}
A class to retrieve the individual data elements previously stored in a Datagram.
const Datagram & get_datagram() const
Return the datagram of this iterator.
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
void append_data(const void *data, size_t size)
Appends some more raw data to the end of the datagram.
Definition datagram.cxx:129
FltOpcode get_opcode() const
Returns the opcode associated with the current record.
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.
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.
FltError advance(bool ok_eof=false)
Extracts the next record from the file.
const Datagram & get_datagram()
Returns the datagram representing the entire record, less the four-byte header.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.