Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/express/subStreamBuf.cxx

Go to the documentation of this file.
00001 // Filename: subStreamBuf.cxx
00002 // Created by:  drose (02Aug02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "subStreamBuf.h"
00020 
00021 #ifndef HAVE_STREAMSIZE
00022 // Some compilers (notably SGI) don't define this for us
00023 typedef int streamsize;
00024 #endif /* HAVE_STREAMSIZE */
00025 
00026 // Temporary hack to make these thread-safe.
00027 //#define SUBSTREAM_THREAD_SAFE
00028 
00029 #ifdef SUBSTREAM_THREAD_SAFE
00030 // This requires NSPR for now.
00031 #include <prlock.h>
00032 PRLock *substream_mutex = (PRLock *)NULL;
00033 
00034 inline void init_lock() {
00035   if (substream_mutex == (PRLock *)NULL) {
00036     substream_mutex = PR_NewLock();
00037   }
00038 }
00039 inline void grab_lock() {
00040   PR_Lock(substream_mutex);
00041 }
00042 inline void release_lock() {
00043   PR_Unlock(substream_mutex);
00044 }
00045 #else  // SUBSTREAM_THREAD_SAFE
00046 inline void init_lock() {
00047 }
00048 inline void grab_lock() {
00049 }
00050 inline void release_lock() {
00051 }
00052 #endif  // SUBSTREAM_THREAD_SAFE
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: SubStreamBuf::Constructor
00056 //       Access: Public
00057 //  Description:
00058 ////////////////////////////////////////////////////////////////////
00059 SubStreamBuf::
00060 SubStreamBuf() {
00061   _source = (istream *)NULL;
00062 
00063   // _start is the streampos of the first byte of the SubStream within
00064   // its parent stream.
00065   _start = 0;
00066 
00067   // _end is the streampos of the byte following the last byte of the
00068   // SubStream within its parent stream.  If _end is 0, the SubStream
00069   // continues to the end of the parent stream, wherever that is.
00070   _end = 0;
00071 
00072   // _cur is the streampos of the end of the read buffer (that is,
00073   // egptr()) within the parent stream.  By comparing _cur to gpos(),
00074   // we can determine the actual current file position.
00075   _cur = 0;
00076 
00077   // _unused counts the number of bytes at the beginning of the buffer
00078   // that are unused.  Usually this is 0 after a read, but when we
00079   // reach the end of the file we might not need the whole buffer to
00080   // read the last bit, so the first part of the buffer is unused.
00081   // This is important to prevent us from inadvertently seeking into
00082   // the unused part of the buffer.
00083   _unused = 0;
00084 
00085   init_lock();
00086 
00087 #ifdef HAVE_IOSTREAM
00088   // The new-style iostream library doesn't seem to support allocate().
00089   char *buf = new char[4096];
00090   char *ebuf = buf + 4096;
00091   setg(buf, ebuf, ebuf);
00092 
00093 #else
00094   allocate();
00095   setg(base(), ebuf(), ebuf());
00096 #endif
00097 }
00098 
00099 ////////////////////////////////////////////////////////////////////
00100 //     Function: SubStreamBuf::Destructor
00101 //       Access: Public, Virtual
00102 //  Description:
00103 ////////////////////////////////////////////////////////////////////
00104 SubStreamBuf::
00105 ~SubStreamBuf() {
00106   close();
00107 }
00108 
00109 ////////////////////////////////////////////////////////////////////
00110 //     Function: SubStreamBuf::open
00111 //       Access: Public
00112 //  Description:
00113 ////////////////////////////////////////////////////////////////////
00114 void SubStreamBuf::
00115 open(istream *source, streampos start, streampos end) {
00116   _source = source;
00117   _start = start;
00118   _end = end;
00119   _cur = _start;
00120 
00121   // Initially, the entire buffer is unused.  Duh.
00122   _unused = egptr() - eback();
00123 }
00124 
00125 ////////////////////////////////////////////////////////////////////
00126 //     Function: SubStreamBuf::close
00127 //       Access: Public
00128 //  Description:
00129 ////////////////////////////////////////////////////////////////////
00130 void SubStreamBuf::
00131 close() {
00132   _source = (istream *)NULL;
00133   _start = 0;
00134   _end = 0;
00135   _cur = 0;
00136   _unused = 0;
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: SubStreamBuf::seekoff
00141 //       Access: Public, Virtual
00142 //  Description: Implements seeking within the stream.
00143 ////////////////////////////////////////////////////////////////////
00144 streampos SubStreamBuf::
00145 seekoff(streamoff off, ios_seekdir dir, ios_openmode mode) {
00146   // Invariant: _cur points to the file location of the buffer at
00147   // egptr().
00148 
00149   // Use this to determine the actual file position right now.
00150   size_t n = egptr() - gptr();
00151   streampos cur_pos = _cur - (streampos)n;
00152   streampos new_pos = cur_pos;
00153 
00154   // Now adjust the data pointer appropriately.
00155 
00156   // Casting this to int to prevent GCC 3.2 compiler warnings.  Very
00157   // suspicious, need to investigate further.
00158   switch ((int)dir) {
00159   case ios::beg:
00160     new_pos = _start + off;
00161     break;
00162 
00163   case ios::cur:
00164     new_pos = cur_pos + off;
00165     break;
00166 
00167   case ios::end:
00168     if (_end == (streampos)0) {
00169       // If the end of the file is unspecified, we have to seek to
00170       // find it.
00171       grab_lock();
00172       _source->seekg(off, ios::end);
00173       new_pos = _source->tellg();
00174       release_lock();
00175 
00176     } else {
00177       new_pos = _end + off;
00178     }
00179     break;
00180   }
00181 
00182   new_pos = max(_start, new_pos);
00183   streamsize delta = new_pos - cur_pos;
00184 
00185   if (gptr() + delta >= eback() + _unused && gptr() + delta <= egptr()) {
00186     // If we can get away with just bumping the gptr within the
00187     // buffer, do so.
00188     gbump(delta);
00189 
00190   } else {
00191     // Otherwise, empty the buffer and force it to call underflow().
00192     gbump(n);
00193     _cur = new_pos;
00194   }
00195 
00196   return new_pos - _start;
00197 }
00198 
00199 ////////////////////////////////////////////////////////////////////
00200 //     Function: SubStreamBuf::seekpos
00201 //       Access: Public, Virtual
00202 //  Description: A variant on seekoff() to implement seeking within a
00203 //               stream.
00204 //
00205 //               The MSDN Library claims that it is only necessary to
00206 //               redefine seekoff(), and not seekpos() as well, as the
00207 //               default implementation of seekpos() is supposed to
00208 //               map to seekoff() exactly as I am doing here; but in
00209 //               fact it must do something else, because seeking
00210 //               didn't work on Windows until I redefined this
00211 //               function as well.
00212 ////////////////////////////////////////////////////////////////////
00213 streampos SubStreamBuf::
00214 seekpos(streampos pos, ios_openmode mode) {
00215   return seekoff(pos, ios::beg, mode);
00216 }
00217 
00218 ////////////////////////////////////////////////////////////////////
00219 //     Function: SubStreamBuf::overflow
00220 //       Access: Protected, Virtual
00221 //  Description: Called by the system ostream implementation when its
00222 //               internal buffer is filled, plus one character.
00223 ////////////////////////////////////////////////////////////////////
00224 int SubStreamBuf::
00225 overflow(int c) {
00226   // We don't support ostream.
00227   return 0;
00228 }
00229 
00230 ////////////////////////////////////////////////////////////////////
00231 //     Function: SubStreamBuf::sync
00232 //       Access: Protected, Virtual
00233 //  Description: Called by the system iostream implementation to
00234 //               implement a flush operation.
00235 ////////////////////////////////////////////////////////////////////
00236 int SubStreamBuf::
00237 sync() {
00238   size_t n = egptr() - gptr();
00239   gbump(n);
00240 
00241   return 0;
00242 }
00243 
00244 ////////////////////////////////////////////////////////////////////
00245 //     Function: SubStreamBuf::underflow
00246 //       Access: Protected, Virtual
00247 //  Description: Called by the system istream implementation when its
00248 //               internal buffer needs more characters.
00249 ////////////////////////////////////////////////////////////////////
00250 int SubStreamBuf::
00251 underflow() {
00252   // Sometimes underflow() is called even if the buffer is not empty.
00253   if (gptr() >= egptr()) {
00254     if (_end != (streampos)0 && _cur >= _end) {
00255       // We're done.
00256       return EOF;
00257     }
00258     
00259     size_t buffer_size = egptr() - eback();
00260     size_t num_bytes;
00261     if (_end == (streampos)0 || _end - _cur > (streampos)buffer_size) {
00262       // We have enough bytes in the input stream to fill our buffer.
00263       num_bytes = buffer_size;
00264     } else {
00265       // We won't quite fill the buffer.
00266       num_bytes = (size_t)(_end - _cur);
00267     }
00268 
00269     gbump(-(int)num_bytes);
00270     nassertr(gptr() + num_bytes <= egptr(), EOF);
00271 
00272     grab_lock();
00273     _source->seekg(_cur);
00274     _source->read(gptr(), num_bytes);
00275     size_t read_count = _source->gcount();
00276     release_lock();
00277 
00278     if (read_count != num_bytes) {
00279       // Oops, we didn't read what we thought we would.
00280       if (read_count == 0) {
00281         _unused = buffer_size;
00282         if (_end != (streampos)0) {
00283           _end = _cur;
00284         }
00285         gbump(num_bytes);
00286         return EOF;
00287       }
00288 
00289       // Slide what we did read to the top of the buffer.
00290       nassertr(read_count < num_bytes, EOF);
00291       size_t delta = num_bytes - read_count;
00292       memmove(gptr() + delta, gptr(), read_count);
00293       gbump(delta);
00294     }
00295 
00296     // Now record whatever bytes at the beginning of the buffer are
00297     // unused, so we won't try to seek into that area.
00298     _unused = buffer_size - read_count;
00299 
00300     // Invariant: _cur points to the file location of the buffer at
00301     // egptr().
00302 
00303     _cur += read_count;
00304   }
00305 
00306   return (unsigned char)*gptr();
00307 }

Generated on Fri May 2 00:38:36 2003 for Panda by doxygen1.3