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
20 TypeHandle 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) {
40 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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 */
49 bool IffInputFile::
50 open_read(Filename filename) {
51 filename.set_binary();
52
53 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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 */
70 void IffInputFile::
71 set_input(std::istream *input, bool owns_istream) {
72 if (_owns_istream) {
73 VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
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 */
86int8_t IffInputFile::
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 */
99uint8_t IffInputFile::
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 */
112int16_t IffInputFile::
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 */
125int32_t IffInputFile::
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 */
138uint16_t IffInputFile::
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 */
151uint32_t IffInputFile::
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 */
164PN_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 */
177std::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 */
195 IffId IffInputFile::
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 */
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 */
308 bool IffInputFile::
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 */
324 bool IffInputFile::
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 */
347 bool IffInputFile::
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::
367make_new_chunk(IffId) {
368 return new IffGenericChunk;
369}
DatagramIterator
A class to retrieve the individual data elements previously stored in a Datagram.
Definition datagramIterator.h:30
DatagramIterator::get_be_uint16
uint16_t get_be_uint16()
Extracts an unsigned 16-bit big-endian integer.
Definition datagramIterator.I:312
DatagramIterator::get_be_uint32
uint32_t get_be_uint32()
Extracts an unsigned 32-bit big-endian integer.
Definition datagramIterator.I:331
DatagramIterator::get_be_int32
int32_t get_be_int32()
Extracts a signed 32-bit big-endian integer.
Definition datagramIterator.I:274
DatagramIterator::get_be_float32
PN_float32 get_be_float32()
Extracts a 32-bit big-endian single-precision floating-point number.
Definition datagramIterator.I:369
DatagramIterator::get_int8
int8_t get_int8()
Extracts a signed 8-bit integer.
Definition datagramIterator.I:56
DatagramIterator::get_be_int16
int16_t get_be_int16()
Extracts a signed 16-bit big-endian integer.
Definition datagramIterator.I:255
Datagram
An ordered list of data elements, formatted in memory for transmission over a socket or writing to a ...
Definition datagram.h:38
Datagram::get_data
const void * get_data() const
Returns a pointer to the beginning of the datagram's data.
Definition datagram.I:327
Filename
The name of a file, such as a texture file or an Egg file.
Definition filename.h:44
Filename::set_binary
void set_binary()
Indicates that the filename represents a binary file.
Definition filename.I:414
IffChunk
The basic kind of record in an EA "IFF" file, which the LightWave object file is based on.
Definition iffChunk.h:30
IffChunk::make_new_chunk
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
IffChunk::set_id
void set_id(IffId id)
Changes the ID associated with this chunk.
Definition iffChunk.I:33
IffGenericChunk
A class for a generic kind of IffChunk that is not understood by a particular IffReader.
Definition iffGenericChunk.h:28
IffId
A four-byte chunk ID appearing in an "IFF" file.
Definition iffId.h:26
IffInputFile::open_read
bool open_read(Filename filename)
Attempts to open the indicated filename for reading.
Definition iffInputFile.cxx:50
IffInputFile::get_be_float32
PN_stdfloat get_be_float32()
Extracts a 32-bit big-endian single-precision floating-point number.
Definition iffInputFile.cxx:165
IffInputFile::read_bytes
bool read_bytes(Datagram &datagram, int length)
Reads a series of bytes, and stores them in the indicated Datagram.
Definition iffInputFile.cxx:325
IffInputFile::set_input
void set_input(std::istream *input, bool owns_istream)
Sets up the input to use an arbitrary istream.
Definition iffInputFile.cxx:71
IffInputFile::get_be_uint16
uint16_t get_be_uint16()
Extracts an unsigned 16-bit big-endian integer.
Definition iffInputFile.cxx:139
IffInputFile::get_id
IffId get_id()
Extracts a 4-character IFF ID.
Definition iffInputFile.cxx:196
IffInputFile::get_bytes_read
size_t get_bytes_read() const
Returns the number of bytes read so far from the input file.
Definition iffInputFile.I:44
IffInputFile::get_be_uint32
uint32_t get_be_uint32()
Extracts an unsigned 32-bit big-endian integer.
Definition iffInputFile.cxx:152
IffInputFile::get_be_int32
int32_t get_be_int32()
Extracts a signed 32-bit big-endian integer.
Definition iffInputFile.cxx:126
IffInputFile::get_int8
int8_t get_int8()
Extracts a signed 8-bit integer.
Definition iffInputFile.cxx:87
IffInputFile::skip_bytes
bool skip_bytes(int length)
Reads a series of bytes, but does not store them.
Definition iffInputFile.cxx:348
IffInputFile::read_byte
bool read_byte(char &byte)
Reads a single byte.
Definition iffInputFile.cxx:309
IffInputFile::get_be_int16
int16_t get_be_int16()
Extracts a signed 16-bit big-endian integer.
Definition iffInputFile.cxx:113
IffInputFile::get_uint8
uint8_t get_uint8()
Extracts an unsigned 8-bit integer.
Definition iffInputFile.cxx:100
IffInputFile::align
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
IffInputFile::get_string
std::string get_string()
Extracts a null-terminated string.
Definition iffInputFile.cxx:178
IffInputFile::is_eof
bool is_eof() const
Returns true if the last read operation failed because of reaching EOF, false otherwise.
Definition iffInputFile.I:36
IffInputFile::set_filename
void set_filename(const Filename &filename)
Indicates the filename that the InputFile is currently opened on.
Definition iffInputFile.I:18
TypeHandle
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
VirtualFileSystem
A hierarchy of directories and files that appears to be one continuous file system,...
Definition virtualFileSystem.h:40
VirtualFileSystem::close_read_file
static void close_read_file(std::istream *stream)
Closes a file opened by a previous call to open_read_file().
Definition virtualFileSystem.cxx:866
VirtualFileSystem::get_global_ptr
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
Definition virtualFileSystem.cxx:741
datagramIterator.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
datagram.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
iffGenericChunk.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
iffInputFile.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
virtualFileSystem.h
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.