Panda3D

stringStreamBuf.cxx

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 
 All Classes Functions Variables Enumerations