Panda3D
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 
20 TypeHandle IffInputFile::_type_handle;
21 
22 /**
23  *
24  */
25 IffInputFile::
26 IffInputFile() {
27  _input = nullptr;
28  _owns_istream = false;
29  _eof = true;
30  _unexpected_eof = false;
31  _bytes_read = 0;
32 }
33 
34 /**
35  *
36  */
37 IffInputFile::
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  */
50 open_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  */
71 set_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  */
87 get_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  */
100 get_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  */
113 get_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  */
126 get_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  */
139 get_be_uint16() {
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  */
152 get_be_uint32() {
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  */
164 PN_stdfloat IffInputFile::
165 get_be_float32() {
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  */
177 std::string IffInputFile::
178 get_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  */
196 get_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  */
211 PT(IffChunk) IffInputFile::
212 get_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  */
261 PT(IffChunk) IffInputFile::
262 get_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  */
309 read_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  */
325 read_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  */
348 skip_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  */
366 IffChunk *IffInputFile::
367 make_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:39
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.
Definition: iffInputFile.I:44
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...
Definition: iffInputFile.I:53
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.
Definition: iffInputFile.I:36
void set_filename(const Filename &filename)
Indicates the filename that the InputFile is currently opened on.
Definition: iffInputFile.I:18
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.
PT(IffChunk) IffInputFile
Reads a single IffChunk, determining its type based on its ID.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.