Panda3D
|
00001 // Filename: stringStreamBuf.cxx 00002 // Created by: drose (02Jul07) 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 "stringStreamBuf.h" 00016 #include "pnotify.h" 00017 #include "config_express.h" 00018 00019 //////////////////////////////////////////////////////////////////// 00020 // Function: StringStreamBuf::Constructor 00021 // Access: Public 00022 // Description: 00023 //////////////////////////////////////////////////////////////////// 00024 StringStreamBuf:: 00025 StringStreamBuf() { 00026 #ifdef PHAVE_IOSTREAM 00027 _buffer = (char *)PANDA_MALLOC_ARRAY(2048); 00028 char *ebuf = _buffer + 2048; 00029 char *mbuf = _buffer + 1024; 00030 setg(_buffer, mbuf, mbuf); 00031 setp(mbuf, ebuf); 00032 00033 #else 00034 allocate(); 00035 // Chop the buffer in half. The bottom half goes to the get buffer; 00036 // the top half goes to the put buffer. 00037 char *b = base(); 00038 char *t = ebuf(); 00039 char *m = b + (t - b) / 2; 00040 setg(b, m, m); 00041 setp(b, m); 00042 #endif 00043 00044 _gpos = 0; 00045 _ppos = 0; 00046 } 00047 00048 //////////////////////////////////////////////////////////////////// 00049 // Function: StringStreamBuf::Destructor 00050 // Access: Public, Virtual 00051 // Description: 00052 //////////////////////////////////////////////////////////////////// 00053 StringStreamBuf:: 00054 ~StringStreamBuf() { 00055 #ifdef PHAVE_IOSTREAM 00056 PANDA_FREE_ARRAY(_buffer); 00057 #endif 00058 } 00059 00060 //////////////////////////////////////////////////////////////////// 00061 // Function: StringStreamBuf::clear 00062 // Access: Public 00063 // Description: Empties the buffer. 00064 //////////////////////////////////////////////////////////////////// 00065 void StringStreamBuf:: 00066 clear() { 00067 _data.clear(); 00068 _gpos = 0; 00069 _ppos = 0; 00070 00071 pbump(pbase() - pptr()); 00072 gbump(egptr() - gptr()); 00073 } 00074 00075 //////////////////////////////////////////////////////////////////// 00076 // Function: StringStreamBuf::read_chars 00077 // Access: Public 00078 // Description: Attempts to extract the indicated number of 00079 // characters from the current file position. Returns 00080 // the number of characters extracted. 00081 //////////////////////////////////////////////////////////////////// 00082 size_t StringStreamBuf:: 00083 read_chars(char *start, size_t length) { 00084 if (length == 0) { 00085 return 0; 00086 } 00087 00088 // Make sure the write buffer is flushed. 00089 sync(); 00090 00091 if (_data.size() <= _gpos) { 00092 return 0; 00093 } 00094 00095 length = min(length, _data.size() - _gpos); 00096 memcpy(start, &_data[_gpos], length); 00097 _gpos += length; 00098 return length; 00099 } 00100 00101 //////////////////////////////////////////////////////////////////// 00102 // Function: StringStreamBuf::write_chars 00103 // Access: Public 00104 // Description: Appends the indicated stream of characters to the 00105 // current file position. 00106 //////////////////////////////////////////////////////////////////// 00107 void StringStreamBuf:: 00108 write_chars(const char *start, size_t length) { 00109 if (length != 0) { 00110 // Make sure the read buffer is flushed. 00111 size_t n = egptr() - gptr(); 00112 gbump(n); 00113 _gpos -= n; 00114 00115 if (_data.size() > _ppos) { 00116 // We are overwriting some data. 00117 size_t remaining_length = _data.size() - _ppos; 00118 size_t overwrite_length = min(remaining_length, length); 00119 memcpy(&_data[_ppos], start, overwrite_length); 00120 length -= overwrite_length; 00121 _ppos += overwrite_length; 00122 start += overwrite_length; 00123 } 00124 00125 if (_data.size() < _ppos) { 00126 // We need to append some zeroes. 00127 _data.insert(_data.end(), _ppos - _data.size(), (unsigned char)0); 00128 } 00129 00130 if (length != 0) { 00131 // We are appending some data. 00132 _data.insert(_data.begin() + _ppos, (const unsigned char *)start, (const unsigned char *)start + length); 00133 _ppos += length; 00134 } 00135 } 00136 } 00137 00138 //////////////////////////////////////////////////////////////////// 00139 // Function: StringStreamBuf::seekoff 00140 // Access: Public, Virtual 00141 // Description: Implements seeking within the stream. 00142 //////////////////////////////////////////////////////////////////// 00143 streampos StringStreamBuf:: 00144 seekoff(streamoff off, ios_seekdir dir, ios_openmode which) { 00145 streampos result = -1; 00146 00147 // Sync the iostream buffer first. 00148 sync(); 00149 00150 if (which & ios::in) { 00151 // Determine the current file position. 00152 size_t n = egptr() - gptr(); 00153 gbump(n); 00154 _gpos -= n; 00155 size_t cur_pos = _gpos; 00156 size_t new_pos = cur_pos; 00157 00158 // Now adjust the data pointer appropriately. 00159 switch (dir) { 00160 case ios::beg: 00161 new_pos = (size_t)off; 00162 break; 00163 00164 case ios::cur: 00165 new_pos = (size_t)((int)cur_pos + off); 00166 break; 00167 00168 case ios::end: 00169 new_pos = (size_t)((int)_data.size() + off); 00170 break; 00171 00172 default: 00173 // Shouldn't get here. 00174 break; 00175 } 00176 00177 _gpos = new_pos; 00178 result = new_pos; 00179 } 00180 00181 if (which & ios::out) { 00182 // Determine the current file position. 00183 size_t n = pptr() - pbase(); 00184 size_t cur_pos = _ppos + n; 00185 size_t new_pos = cur_pos; 00186 00187 // Now adjust the data pointer appropriately. 00188 switch (dir) { 00189 case ios::beg: 00190 new_pos = (size_t)off; 00191 break; 00192 00193 case ios::cur: 00194 new_pos = (size_t)((int)cur_pos + off); 00195 break; 00196 00197 case ios::end: 00198 new_pos = (size_t)((int)_data.size() + off); 00199 break; 00200 00201 default: 00202 // Shouldn't get here. 00203 break; 00204 } 00205 00206 _ppos = new_pos; 00207 result = new_pos; 00208 } 00209 00210 return result; 00211 } 00212 00213 //////////////////////////////////////////////////////////////////// 00214 // Function: StringStreamBuf::seekpos 00215 // Access: Public, Virtual 00216 // Description: A variant on seekoff() to implement seeking within a 00217 // stream. 00218 // 00219 // The MSDN Library claims that it is only necessary to 00220 // redefine seekoff(), and not seekpos() as well, as the 00221 // default implementation of seekpos() is supposed to 00222 // map to seekoff() exactly as I am doing here; but in 00223 // fact it must do something else, because seeking 00224 // didn't work on Windows until I redefined this 00225 // function as well. 00226 //////////////////////////////////////////////////////////////////// 00227 streampos StringStreamBuf:: 00228 seekpos(streampos pos, ios_openmode which) { 00229 return seekoff(pos, ios::beg, which); 00230 } 00231 00232 //////////////////////////////////////////////////////////////////// 00233 // Function: StringStreamBuf::overflow 00234 // Access: Protected, Virtual 00235 // Description: Called by the system ostream implementation when its 00236 // internal buffer is filled, plus one character. 00237 //////////////////////////////////////////////////////////////////// 00238 int StringStreamBuf:: 00239 overflow(int ch) { 00240 size_t n = pptr() - pbase(); 00241 if (n != 0) { 00242 write_chars(pbase(), n); 00243 pbump(-(int)n); 00244 } 00245 00246 if (ch != EOF) { 00247 // Write one more character. 00248 char c = ch; 00249 write_chars(&c, 1); 00250 } 00251 00252 return 0; 00253 } 00254 00255 //////////////////////////////////////////////////////////////////// 00256 // Function: StringStreamBuf::sync 00257 // Access: Protected, Virtual 00258 // Description: Called by the system iostream implementation to 00259 // implement a flush operation. 00260 //////////////////////////////////////////////////////////////////// 00261 int StringStreamBuf:: 00262 sync() { 00263 size_t n = pptr() - pbase(); 00264 00265 write_chars(pbase(), n); 00266 pbump(-(int)n); 00267 00268 return 0; 00269 } 00270 00271 //////////////////////////////////////////////////////////////////// 00272 // Function: StringStreamBuf::underflow 00273 // Access: Protected, Virtual 00274 // Description: Called by the system istream implementation when its 00275 // internal buffer needs more characters. 00276 //////////////////////////////////////////////////////////////////// 00277 int StringStreamBuf:: 00278 underflow() { 00279 // Sometimes underflow() is called even if the buffer is not empty. 00280 if (gptr() >= egptr()) { 00281 // Mark the buffer filled (with buffer_size bytes). 00282 size_t buffer_size = egptr() - eback(); 00283 gbump(-(int)buffer_size); 00284 00285 size_t num_bytes = buffer_size; 00286 size_t read_count = read_chars(gptr(), buffer_size); 00287 00288 if (read_count != num_bytes) { 00289 // Oops, we didn't read what we thought we would. 00290 if (read_count == 0) { 00291 gbump(num_bytes); 00292 return EOF; 00293 } 00294 00295 // Slide what we did read to the top of the buffer. 00296 nassertr(read_count < num_bytes, EOF); 00297 size_t delta = num_bytes - read_count; 00298 memmove(gptr() + delta, gptr(), read_count); 00299 gbump(delta); 00300 } 00301 } 00302 00303 return (unsigned char)*gptr(); 00304 } 00305