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