Panda3D
|
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 }