Panda3D
Loading...
Searching...
No Matches
iffInputFile.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 iffInputFile.cxx
10 * @author drose
11 * @date 2001-04-24
12 */
13
14#include "iffInputFile.h"
15#include "iffGenericChunk.h"
16#include "datagram.h"
17#include "datagramIterator.h"
18#include "virtualFileSystem.h"
19
20TypeHandle IffInputFile::_type_handle;
21
22/**
23 *
24 */
25IffInputFile::
26IffInputFile() {
27 _input = nullptr;
28 _owns_istream = false;
29 _eof = true;
30 _unexpected_eof = false;
31 _bytes_read = 0;
32}
33
34/**
35 *
36 */
37IffInputFile::
38~IffInputFile() {
39 if (_owns_istream) {
41 vfs->close_read_file(_input);
42 }
43}
44
45/**
46 * Attempts to open the indicated filename for reading. Returns true if
47 * successful, false otherwise.
48 */
50open_read(Filename filename) {
51 filename.set_binary();
52
54 std::istream *in = vfs->open_read_file(filename, true);
55 if (in == nullptr) {
56 return false;
57 }
58
59 set_input(in, true);
60 set_filename(filename);
61
62 return true;
63}
64
65/**
66 * Sets up the input to use an arbitrary istream. If owns_istream is true,
67 * the istream will be deleted (via vfs->close_read_file()) when the
68 * IffInputFile destructs.
69 */
71set_input(std::istream *input, bool owns_istream) {
72 if (_owns_istream) {
74 vfs->close_read_file(_input);
75 }
76 _input = input;
77 _owns_istream = owns_istream;
78 _eof = false;
79 _unexpected_eof = false;
80 _bytes_read = 0;
81}
82
83/**
84 * Extracts a signed 8-bit integer.
85 */
87get_int8() {
88 Datagram dg;
89 if (!read_bytes(dg, 1)) {
90 return 0;
91 }
92 DatagramIterator dgi(dg);
93 return dgi.get_int8();
94}
95
96/**
97 * Extracts an unsigned 8-bit integer.
98 */
100get_uint8() {
101 Datagram dg;
102 if (!read_bytes(dg, 1)) {
103 return 0;
104 }
105 DatagramIterator dgi(dg);
106 return dgi.get_int8();
107}
108
109/**
110 * Extracts a signed 16-bit big-endian integer.
111 */
113get_be_int16() {
114 Datagram dg;
115 if (!read_bytes(dg, 2)) {
116 return 0;
117 }
118 DatagramIterator dgi(dg);
119 return dgi.get_be_int16();
120}
121
122/**
123 * Extracts a signed 32-bit big-endian integer.
124 */
126get_be_int32() {
127 Datagram dg;
128 if (!read_bytes(dg, 4)) {
129 return 0;
130 }
131 DatagramIterator dgi(dg);
132 return dgi.get_be_int32();
133}
134
135/**
136 * Extracts an unsigned 16-bit big-endian integer.
137 */
140 Datagram dg;
141 if (!read_bytes(dg, 2)) {
142 return 0;
143 }
144 DatagramIterator dgi(dg);
145 return dgi.get_be_uint16();
146}
147
148/**
149 * Extracts an unsigned 32-bit big-endian integer.
150 */
153 Datagram dg;
154 if (!read_bytes(dg, 4)) {
155 return 0;
156 }
157 DatagramIterator dgi(dg);
158 return dgi.get_be_uint32();
159}
160
161/**
162 * Extracts a 32-bit big-endian single-precision floating-point number.
163 */
164PN_stdfloat IffInputFile::
166 Datagram dg;
167 if (!read_bytes(dg, 4)) {
168 return 0;
169 }
170 DatagramIterator dgi(dg);
171 return dgi.get_be_float32();
172}
173
174/**
175 * Extracts a null-terminated string.
176 */
177std::string IffInputFile::
178get_string() {
179 std::string result;
180 char byte;
181 while (read_byte(byte)) {
182 if (byte == 0) {
183 break;
184 }
185 result += byte;
186 }
187
188 align();
189 return result;
190}
191
192/**
193 * Extracts a 4-character IFF ID.
194 */
196get_id() {
197 Datagram dg;
198 if (!read_bytes(dg, 4)) {
199 return IffId();
200 }
201 const char *id = (const char *)dg.get_data();
202 return IffId(id);
203}
204
205/**
206 * Reads a single IffChunk, determining its type based on its ID. Allocates
207 * and returns a new IffChunk object of the appropriate type. Returns NULL if
208 * EOF is reached before the chunk can be read completely, or if there is some
209 * other error in reading the chunk.
210 */
211PT(IffChunk) IffInputFile::
212get_chunk() {
213 if (is_eof()) {
214 return nullptr;
215 }
216
217 IffId id = get_id();
218 uint32_t length = get_be_uint32();
219
220 if (!is_eof()) {
221 PT(IffChunk) chunk = make_new_chunk(id);
222 chunk->set_id(id);
223
224 size_t start_point = get_bytes_read();
225 size_t end_point = start_point + length;
226
227 if (chunk->read_iff(this, end_point)) {
228 if (is_eof()) {
229 if (!_unexpected_eof) {
230 nout << "Unexpected EOF on file reading " << *chunk << "\n";
231 _unexpected_eof = true;
232 }
233 return nullptr;
234 }
235
236 size_t num_bytes_read = get_bytes_read() - start_point;
237 if (num_bytes_read > length) {
238 nout << *chunk << " read " << num_bytes_read
239 << " instead of " << length << " bytes.\n";
240 return nullptr;
241
242 } else if (num_bytes_read < length) {
243 size_t skip_count = length - num_bytes_read;
244 nout << "Ignoring " << skip_count << " bytes at the end of "
245 << *chunk << "\n";
246 skip_bytes(skip_count);
247 }
248 return chunk;
249 }
250 }
251
252 return nullptr;
253}
254
255/**
256 * Similar to get_chunk(), except the chunk size is only a 16-bit number
257 * instead of 32-bit, and it takes a context, which is the chunk in which this
258 * chunk is encountered. The parent chunk may (or may not) decide what kind
259 * of chunk is meant by the various id's encountered.
260 */
261PT(IffChunk) IffInputFile::
262get_subchunk(IffChunk *context) {
263 if (is_eof()) {
264 return nullptr;
265 }
266
267 IffId id = get_id();
268 uint16_t length = get_be_uint16();
269
270 if (!is_eof()) {
271 PT(IffChunk) chunk = context->make_new_chunk(this, id);
272 chunk->set_id(id);
273
274 size_t start_point = get_bytes_read();
275 size_t end_point = start_point + length;
276
277 if (chunk->read_iff(this, end_point)) {
278 if (is_eof()) {
279 if (!_unexpected_eof) {
280 nout << "Unexpected EOF on file reading " << *chunk << "\n";
281 _unexpected_eof = true;
282 }
283 return nullptr;
284 }
285
286 size_t num_bytes_read = get_bytes_read() - start_point;
287 if (num_bytes_read > length) {
288 nout << *chunk << " read " << num_bytes_read
289 << " instead of " << length << " bytes.\n";
290 return nullptr;
291
292 } else if (num_bytes_read < length) {
293 size_t skip_count = length - num_bytes_read;
294 nout << "Ignoring " << skip_count << " bytes at the end of "
295 << *chunk << "\n";
296 skip_bytes(skip_count);
297 }
298 return chunk;
299 }
300 }
301
302 return nullptr;
303}
304
305/**
306 * Reads a single byte. Returns true if successful, false otherwise.
307 */
309read_byte(char &byte) {
310 if (is_eof()) {
311 return false;
312 }
313
314 _input->get(byte);
315 _bytes_read++;
316 _eof = _input->eof() || _input->fail();
317 return !is_eof();
318}
319
320/**
321 * Reads a series of bytes, and stores them in the indicated Datagram.
322 * Returns true if successful, false otherwise.
323 */
325read_bytes(Datagram &datagram, int length) {
326 if (is_eof()) {
327 return false;
328 }
329
330 char *buffer = new char[length];
331 _input->read(buffer, length);
332 _eof = (_input->gcount() != length);
333 if (is_eof()) {
334 return false;
335 }
336
337 _bytes_read += length;
338 datagram = Datagram(buffer, length);
339 delete[] buffer;
340 return true;
341}
342
343/**
344 * Reads a series of bytes, but does not store them. Returns true if
345 * successful, false otherwise.
346 */
348skip_bytes(int length) {
349 if (is_eof()) {
350 return false;
351 }
352
353 char byte;
354 while (length > 0 && !is_eof()) {
355 read_byte(byte);
356 length--;
357 }
358
359 return !is_eof();
360}
361
362/**
363 * Allocates and returns a new chunk of the appropriate type based on the
364 * given ID.
365 */
366IffChunk *IffInputFile::
367make_new_chunk(IffId) {
368 return new IffGenericChunk;
369}
A class to retrieve the individual data elements previously stored in a Datagram.
uint16_t get_be_uint16()
Extracts an unsigned 16-bit big-endian integer.
uint32_t get_be_uint32()
Extracts an unsigned 32-bit big-endian integer.
int32_t get_be_int32()
Extracts a signed 32-bit big-endian integer.
PN_float32 get_be_float32()
Extracts a 32-bit big-endian single-precision floating-point number.
int8_t get_int8()
Extracts a signed 8-bit integer.
int16_t get_be_int16()
Extracts a signed 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:38
const void * get_data() const
Returns a pointer to the beginning of the datagram's data.
Definition datagram.I:327
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
void set_binary()
Indicates that the filename represents a binary file.
Definition filename.I:414
The basic kind of record in an EA "IFF" file, which the LightWave object file is based on.
Definition iffChunk.h:30
virtual IffChunk * make_new_chunk(IffInputFile *in, IffId id)
Allocates and returns a new chunk of the appropriate type based on the given ID, according to the con...
Definition iffChunk.cxx:42
void set_id(IffId id)
Changes the ID associated with this chunk.
Definition iffChunk.I:33
A class for a generic kind of IffChunk that is not understood by a particular IffReader.
A four-byte chunk ID appearing in an "IFF" file.
Definition iffId.h:26
bool open_read(Filename filename)
Attempts to open the indicated filename for reading.
PN_stdfloat get_be_float32()
Extracts a 32-bit big-endian single-precision floating-point number.
bool read_bytes(Datagram &datagram, int length)
Reads a series of bytes, and stores them in the indicated Datagram.
void set_input(std::istream *input, bool owns_istream)
Sets up the input to use an arbitrary istream.
uint16_t get_be_uint16()
Extracts an unsigned 16-bit big-endian integer.
IffId get_id()
Extracts a 4-character IFF ID.
size_t get_bytes_read() const
Returns the number of bytes read so far from the input file.
uint32_t get_be_uint32()
Extracts an unsigned 32-bit big-endian integer.
int32_t get_be_int32()
Extracts a signed 32-bit big-endian integer.
int8_t get_int8()
Extracts a signed 8-bit integer.
bool skip_bytes(int length)
Reads a series of bytes, but does not store them.
bool read_byte(char &byte)
Reads a single byte.
int16_t get_be_int16()
Extracts a signed 16-bit big-endian integer.
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
void align()
If the current file pointer is not positioned on an even-byte boundary, reads and discards one byte s...
std::string get_string()
Extracts a null-terminated string.
bool is_eof() const
Returns true if the last read operation failed because of reaching EOF, false otherwise.
void set_filename(const Filename &filename)
Indicates the filename that the InputFile is currently opened on.
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
A hierarchy of directories and files that appears to be one continuous file system,...
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
std::istream * open_read_file(const Filename &filename, bool auto_unwrap) const
Convenience function; returns a newly allocated istream if the file exists and can be read,...
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.