Panda3D

iffInputFile.cxx

00001 // Filename: iffInputFile.cxx
00002 // Created by:  drose (24Apr01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "iffInputFile.h"
00016 #include "iffGenericChunk.h"
00017 #include "datagram.h"
00018 #include "datagramIterator.h"
00019 #include "virtualFileSystem.h"
00020 
00021 TypeHandle IffInputFile::_type_handle;
00022 
00023 ////////////////////////////////////////////////////////////////////
00024 //     Function: IffInputFile::Constructor
00025 //       Access: Public
00026 //  Description:
00027 ////////////////////////////////////////////////////////////////////
00028 IffInputFile::
00029 IffInputFile() {
00030   _input = (istream *)NULL;
00031   _owns_istream = false;
00032   _eof = true;
00033   _unexpected_eof = false;
00034   _bytes_read = 0;
00035 }
00036 
00037 ////////////////////////////////////////////////////////////////////
00038 //     Function: IffInputFile::Destructor
00039 //       Access: Public, Virtual
00040 //  Description:
00041 ////////////////////////////////////////////////////////////////////
00042 IffInputFile::
00043 ~IffInputFile() {
00044   if (_owns_istream) {
00045     VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00046     vfs->close_read_file(_input);
00047   }
00048 }
00049 
00050 ////////////////////////////////////////////////////////////////////
00051 //     Function: IffInputFile::open_read
00052 //       Access: Public
00053 //  Description: Attempts to open the indicated filename for reading.
00054 //               Returns true if successful, false otherwise.
00055 ////////////////////////////////////////////////////////////////////
00056 bool IffInputFile::
00057 open_read(Filename filename) {
00058   filename.set_binary();
00059 
00060   VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00061   istream *in = vfs->open_read_file(filename, true);
00062   if (in == (istream *)NULL) {
00063     return false;
00064   }
00065 
00066   set_input(in, true);
00067   set_filename(filename);
00068 
00069   return true;
00070 }
00071 
00072 ////////////////////////////////////////////////////////////////////
00073 //     Function: IffInputFile::set_input
00074 //       Access: Public
00075 //  Description: Sets up the input to use an arbitrary istream.  If
00076 //               owns_istream is true, the istream will be deleted
00077 //               (via vfs->close_read_file()) when the IffInputFile
00078 //               destructs.
00079 ////////////////////////////////////////////////////////////////////
00080 void IffInputFile::
00081 set_input(istream *input, bool owns_istream) {
00082   if (_owns_istream) {
00083     VirtualFileSystem *vfs = VirtualFileSystem::get_global_ptr();
00084     vfs->close_read_file(_input);
00085   }
00086   _input = input;
00087   _owns_istream = owns_istream;
00088   _eof = false;
00089   _unexpected_eof = false;
00090   _bytes_read = 0;
00091 }
00092 
00093 ////////////////////////////////////////////////////////////////////
00094 //     Function: IffInputFile::get_int8
00095 //       Access: Public
00096 //  Description: Extracts a signed 8-bit integer.
00097 ////////////////////////////////////////////////////////////////////
00098 PN_int8 IffInputFile::
00099 get_int8() {
00100   Datagram dg;
00101   if (!read_bytes(dg, 1)) {
00102     return 0;
00103   }
00104   DatagramIterator dgi(dg);
00105   return dgi.get_int8();
00106 }
00107 
00108 ////////////////////////////////////////////////////////////////////
00109 //     Function: IffInputFile::get_uint8
00110 //       Access: Public
00111 //  Description: Extracts an unsigned 8-bit integer.
00112 ////////////////////////////////////////////////////////////////////
00113 PN_uint8 IffInputFile::
00114 get_uint8() {
00115   Datagram dg;
00116   if (!read_bytes(dg, 1)) {
00117     return 0;
00118   }
00119   DatagramIterator dgi(dg);
00120   return dgi.get_int8();
00121 }
00122 
00123 ////////////////////////////////////////////////////////////////////
00124 //     Function: IffInputFile::get_be_int16
00125 //       Access: Public
00126 //  Description: Extracts a signed 16-bit big-endian integer.
00127 ////////////////////////////////////////////////////////////////////
00128 PN_int16 IffInputFile::
00129 get_be_int16() {
00130   Datagram dg;
00131   if (!read_bytes(dg, 2)) {
00132     return 0;
00133   }
00134   DatagramIterator dgi(dg);
00135   return dgi.get_be_int16();
00136 }
00137 
00138 ////////////////////////////////////////////////////////////////////
00139 //     Function: IffInputFile::get_be_int32
00140 //       Access: Public
00141 //  Description: Extracts a signed 32-bit big-endian integer.
00142 ////////////////////////////////////////////////////////////////////
00143 PN_int32 IffInputFile::
00144 get_be_int32() {
00145   Datagram dg;
00146   if (!read_bytes(dg, 4)) {
00147     return 0;
00148   }
00149   DatagramIterator dgi(dg);
00150   return dgi.get_be_int32();
00151 }
00152 
00153 ////////////////////////////////////////////////////////////////////
00154 //     Function: IffInputFile::get_be_uint16
00155 //       Access: Public
00156 //  Description: Extracts an unsigned 16-bit big-endian integer.
00157 ////////////////////////////////////////////////////////////////////
00158 PN_uint16 IffInputFile::
00159 get_be_uint16() {
00160   Datagram dg;
00161   if (!read_bytes(dg, 2)) {
00162     return 0;
00163   }
00164   DatagramIterator dgi(dg);
00165   return dgi.get_be_uint16();
00166 }
00167 
00168 ////////////////////////////////////////////////////////////////////
00169 //     Function: IffInputFile::get_be_uint32
00170 //       Access: Public
00171 //  Description: Extracts an unsigned 32-bit big-endian integer.
00172 ////////////////////////////////////////////////////////////////////
00173 PN_uint32 IffInputFile::
00174 get_be_uint32() {
00175   Datagram dg;
00176   if (!read_bytes(dg, 4)) {
00177     return 0;
00178   }
00179   DatagramIterator dgi(dg);
00180   return dgi.get_be_uint32();
00181 }
00182 
00183 ////////////////////////////////////////////////////////////////////
00184 //     Function: IffInputFile::get_be_float32
00185 //       Access: Public
00186 //  Description: Extracts a 32-bit big-endian single-precision
00187 //               floating-point number.
00188 ////////////////////////////////////////////////////////////////////
00189 PN_stdfloat IffInputFile::
00190 get_be_float32() {
00191   Datagram dg;
00192   if (!read_bytes(dg, 4)) {
00193     return 0;
00194   }
00195   DatagramIterator dgi(dg);
00196   return dgi.get_be_float32();
00197 }
00198 
00199 ////////////////////////////////////////////////////////////////////
00200 //     Function: IffInputFile::get_string
00201 //       Access: Public
00202 //  Description: Extracts a null-terminated string.
00203 ////////////////////////////////////////////////////////////////////
00204 string IffInputFile::
00205 get_string() {
00206   string result;
00207   char byte;
00208   while (read_byte(byte)) {
00209     if (byte == 0) {
00210       break;
00211     }
00212     result += byte;
00213   }
00214 
00215   align();
00216   return result;
00217 }
00218 
00219 ////////////////////////////////////////////////////////////////////
00220 //     Function: IffInputFile::get_id
00221 //       Access: Public
00222 //  Description: Extracts a 4-character IFF ID.
00223 ////////////////////////////////////////////////////////////////////
00224 IffId IffInputFile::
00225 get_id() {
00226   Datagram dg;
00227   if (!read_bytes(dg, 4)) {
00228     return IffId();
00229   }
00230   const char *id = (const char *)dg.get_data();
00231   return IffId(id);
00232 }
00233 
00234 ////////////////////////////////////////////////////////////////////
00235 //     Function: IffInputFile::get_chunk
00236 //       Access: Public
00237 //  Description: Reads a single IffChunk, determining its type based
00238 //               on its ID.  Allocates and returns a new IffChunk
00239 //               object of the appropriate type.  Returns NULL if EOF
00240 //               is reached before the chunk can be read completely,
00241 //               or if there is some other error in reading the chunk.
00242 ////////////////////////////////////////////////////////////////////
00243 PT(IffChunk) IffInputFile::
00244 get_chunk() {
00245   if (is_eof()) {
00246     return (IffChunk *)NULL;
00247   }
00248 
00249   IffId id = get_id();
00250   PN_uint32 length = get_be_uint32();
00251 
00252   if (!is_eof()) {
00253     PT(IffChunk) chunk = make_new_chunk(id);
00254     chunk->set_id(id);
00255 
00256     size_t start_point = get_bytes_read();
00257     size_t end_point = start_point + length;
00258 
00259     if (chunk->read_iff(this, end_point)) {
00260       if (is_eof()) {
00261         if (!_unexpected_eof) {
00262           nout << "Unexpected EOF on file reading " << *chunk << "\n";
00263           _unexpected_eof = true;
00264         }
00265         return (IffChunk *)NULL;
00266       }
00267 
00268       size_t num_bytes_read = get_bytes_read() - start_point;
00269       if (num_bytes_read > length) {
00270         nout << *chunk << " read " << num_bytes_read
00271              << " instead of " << length << " bytes.\n";
00272         return (IffChunk *)NULL;
00273 
00274       } else if (num_bytes_read < length) {
00275         size_t skip_count = length - num_bytes_read;
00276         nout << "Ignoring " << skip_count << " bytes at the end of "
00277              << *chunk << "\n";
00278         skip_bytes(skip_count);
00279       }
00280       return chunk;
00281     }
00282   }
00283 
00284   return (IffChunk *)NULL;
00285 }
00286 
00287 ////////////////////////////////////////////////////////////////////
00288 //     Function: IffInputFile::get_subchunk
00289 //       Access: Public
00290 //  Description: Similar to get_chunk(), except the chunk size is only
00291 //               a 16-bit number instead of 32-bit, and it takes a
00292 //               context, which is the chunk in which this chunk is
00293 //               encountered.  The parent chunk may (or may not)
00294 //               decide what kind of chunk is meant by the various
00295 //               id's encountered.
00296 ////////////////////////////////////////////////////////////////////
00297 PT(IffChunk) IffInputFile::
00298 get_subchunk(IffChunk *context) {
00299   if (is_eof()) {
00300     return (IffChunk *)NULL;
00301   }
00302 
00303   IffId id = get_id();
00304   PN_uint16 length = get_be_uint16();
00305 
00306   if (!is_eof()) {
00307     PT(IffChunk) chunk = context->make_new_chunk(this, id);
00308     chunk->set_id(id);
00309 
00310     size_t start_point = get_bytes_read();
00311     size_t end_point = start_point + length;
00312 
00313     if (chunk->read_iff(this, end_point)) {
00314       if (is_eof()) {
00315         if (!_unexpected_eof) {
00316           nout << "Unexpected EOF on file reading " << *chunk << "\n";
00317           _unexpected_eof = true;
00318         }
00319         return (IffChunk *)NULL;
00320       }
00321 
00322       size_t num_bytes_read = get_bytes_read() - start_point;
00323       if (num_bytes_read > length) {
00324         nout << *chunk << " read " << num_bytes_read
00325              << " instead of " << length << " bytes.\n";
00326         return (IffChunk *)NULL;
00327 
00328       } else if (num_bytes_read < length) {
00329         size_t skip_count = length - num_bytes_read;
00330         nout << "Ignoring " << skip_count << " bytes at the end of "
00331              << *chunk << "\n";
00332         skip_bytes(skip_count);
00333       }
00334       return chunk;
00335     }
00336   }
00337 
00338   return (IffChunk *)NULL;
00339 }
00340 
00341 ////////////////////////////////////////////////////////////////////
00342 //     Function: IffInputFile::read_byte
00343 //       Access: Public
00344 //  Description: Reads a single byte.  Returns true if successful,
00345 //               false otherwise.
00346 ////////////////////////////////////////////////////////////////////
00347 bool IffInputFile::
00348 read_byte(char &byte) {
00349   if (is_eof()) {
00350     return false;
00351   }
00352 
00353   _input->get(byte);
00354   _bytes_read++;
00355   _eof = _input->eof() || _input->fail();
00356   return !is_eof();
00357 }
00358 
00359 ////////////////////////////////////////////////////////////////////
00360 //     Function: IffInputFile::read_bytes
00361 //       Access: Public
00362 //  Description: Reads a series of bytes, and stores them in the
00363 //               indicated Datagram.  Returns true if successful,
00364 //               false otherwise.
00365 ////////////////////////////////////////////////////////////////////
00366 bool IffInputFile::
00367 read_bytes(Datagram &datagram, int length) {
00368   if (is_eof()) {
00369     return false;
00370   }
00371 
00372   char *buffer = new char[length];
00373   _input->read(buffer, length);
00374   _eof = (_input->gcount() != length);
00375   if (is_eof()) {
00376     return false;
00377   }
00378 
00379   _bytes_read += length;
00380   datagram = Datagram(buffer, length);
00381   delete[] buffer;
00382   return true;
00383 }
00384 
00385 ////////////////////////////////////////////////////////////////////
00386 //     Function: IffInputFile::skip_bytes
00387 //       Access: Public
00388 //  Description: Reads a series of bytes, but does not store them.
00389 //               Returns true if successful, false otherwise.
00390 ////////////////////////////////////////////////////////////////////
00391 bool IffInputFile::
00392 skip_bytes(int length) {
00393   if (is_eof()) {
00394     return false;
00395   }
00396 
00397   char byte;
00398   while (length > 0 && !is_eof()) {
00399     read_byte(byte);
00400     length--;
00401   }
00402 
00403   return !is_eof();
00404 }
00405 
00406 ////////////////////////////////////////////////////////////////////
00407 //     Function: IffInputFile::make_new_chunk
00408 //       Access: Protected, Virtual
00409 //  Description: Allocates and returns a new chunk of the appropriate
00410 //               type based on the given ID.
00411 ////////////////////////////////////////////////////////////////////
00412 IffChunk *IffInputFile::
00413 make_new_chunk(IffId) {
00414   return new IffGenericChunk;
00415 }
 All Classes Functions Variables Enumerations