Panda3D
 All Classes Functions Variables Enumerations
identityStreamBuf.cxx
00001 // Filename: identityStreamBuf.cxx
00002 // Created by:  drose (09Oct02)
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 "identityStreamBuf.h"
00016 
00017 // This module is not compiled if OpenSSL is not available.
00018 #ifdef HAVE_OPENSSL
00019 
00020 #ifndef HAVE_STREAMSIZE
00021 // Some compilers (notably SGI) don't define this for us
00022 typedef int streamsize;
00023 #endif /* HAVE_STREAMSIZE */
00024 
00025 ////////////////////////////////////////////////////////////////////
00026 //     Function: IdentityStreamBuf::Constructor
00027 //       Access: Public
00028 //  Description:
00029 ////////////////////////////////////////////////////////////////////
00030 IdentityStreamBuf::
00031 IdentityStreamBuf() {
00032   _has_content_length = true;
00033   _bytes_remaining = 0;
00034   _wanted_nonblocking = false;
00035   _read_state = ISocketStream::RS_initial;
00036 
00037 #ifdef PHAVE_IOSTREAM
00038   _buffer = (char *)PANDA_MALLOC_ARRAY(4096);
00039   char *ebuf = _buffer + 4096;
00040   setg(_buffer, ebuf, ebuf);
00041   setp(_buffer, ebuf);
00042 
00043 #else
00044   allocate();
00045   setg(base(), ebuf(), ebuf());
00046   setp(base(), ebuf());
00047 #endif
00048 }
00049 
00050 ////////////////////////////////////////////////////////////////////
00051 //     Function: IdentityStreamBuf::Destructor
00052 //       Access: Public, Virtual
00053 //  Description:
00054 ////////////////////////////////////////////////////////////////////
00055 IdentityStreamBuf::
00056 ~IdentityStreamBuf() {
00057   close_read();
00058 #ifdef PHAVE_IOSTREAM
00059   PANDA_FREE_ARRAY(_buffer);
00060 #endif
00061 }
00062 
00063 ////////////////////////////////////////////////////////////////////
00064 //     Function: IdentityStreamBuf::open_read
00065 //       Access: Public
00066 //  Description: If the document pointer is non-NULL, it will be
00067 //               updated with the length of the file as it is derived
00068 //               from the identity encoding.
00069 ////////////////////////////////////////////////////////////////////
00070 void IdentityStreamBuf::
00071 open_read(BioStreamPtr *source, HTTPChannel *doc,
00072           bool has_content_length, size_t content_length) {
00073   _source = source;
00074   _has_content_length = has_content_length;
00075   _wanted_nonblocking = doc->_wanted_nonblocking;
00076   _bytes_remaining = content_length;
00077   _read_state = ISocketStream::RS_reading;
00078 }
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: IdentityStreamBuf::close_read
00082 //       Access: Public
00083 //  Description:
00084 ////////////////////////////////////////////////////////////////////
00085 void IdentityStreamBuf::
00086 close_read() {
00087   _source.clear();
00088 }
00089 
00090 ////////////////////////////////////////////////////////////////////
00091 //     Function: IdentityStreamBuf::underflow
00092 //       Access: Protected, Virtual
00093 //  Description: Called by the system istream implementation when its
00094 //               internal buffer needs more characters.
00095 ////////////////////////////////////////////////////////////////////
00096 int IdentityStreamBuf::
00097 underflow() {
00098   // Sometimes underflow() is called even if the buffer is not empty.
00099   if (gptr() >= egptr()) {
00100     size_t buffer_size = egptr() - eback();
00101     gbump(-(int)buffer_size);
00102 
00103     size_t num_bytes = buffer_size;
00104     size_t read_count = read_chars(gptr(), buffer_size);
00105 
00106     if (read_count != num_bytes) {
00107       // Oops, we didn't read what we thought we would.
00108       if (read_count == 0) {
00109         gbump(num_bytes);
00110         return EOF;
00111       }
00112 
00113       // Slide what we did read to the top of the buffer.
00114       nassertr(read_count < num_bytes, EOF);
00115       size_t delta = num_bytes - read_count;
00116       memmove(gptr() + delta, gptr(), read_count);
00117       gbump(delta);
00118     }
00119   }
00120 
00121   return (unsigned char)*gptr();
00122 }
00123 
00124 
00125 ////////////////////////////////////////////////////////////////////
00126 //     Function: IdentityStreamBuf::read_chars
00127 //       Access: Private
00128 //  Description: Gets some characters from the source stream.
00129 ////////////////////////////////////////////////////////////////////
00130 size_t IdentityStreamBuf::
00131 read_chars(char *start, size_t length) {
00132   size_t read_count = 0;
00133 
00134   if (!_has_content_length) {
00135     // If we have no restrictions on content length, read till end of
00136     // file.
00137     (*_source)->read(start, length);
00138     read_count = (*_source)->gcount();
00139 
00140     if (!_wanted_nonblocking) {
00141       while (read_count == 0 && !(*_source)->is_closed()) {
00142         // Simulate blocking.
00143         thread_yield();
00144         (*_source)->read(start, length);
00145         read_count = (*_source)->gcount();
00146       }
00147     }
00148   
00149     if (read_count == 0) {
00150       if ((*_source)->is_closed()) {
00151         // socket closed; we're done.
00152         _read_state = ISocketStream::RS_complete;
00153       }
00154       return 0;
00155     }
00156 
00157   } else {
00158     // Extract some of the remaining bytes, but do not read past the
00159     // content_length restriction.
00160 
00161     if (_bytes_remaining != 0) {
00162       length = min(length, _bytes_remaining);
00163       (*_source)->read(start, length);
00164       read_count = (*_source)->gcount();
00165       if (!_wanted_nonblocking) {
00166         while (read_count == 0 && !(*_source)->is_closed()) {
00167           // Simulate blocking.
00168           thread_yield();
00169           (*_source)->read(start, length);
00170           read_count = (*_source)->gcount();
00171         }
00172       }
00173       nassertr(read_count <= _bytes_remaining, 0);
00174       _bytes_remaining -= read_count;
00175   
00176       if (read_count == 0) {
00177         if ((*_source)->is_closed()) {
00178           // socket closed unexpectedly; problem.
00179           _read_state = ISocketStream::RS_error;
00180         }
00181         return 0;
00182       }
00183     }
00184       
00185     if (_bytes_remaining == 0) {
00186       // We're done.
00187       _read_state = ISocketStream::RS_complete;
00188     }
00189   }
00190 
00191   return read_count;
00192 }
00193 
00194 #endif  // HAVE_OPENSSL
 All Classes Functions Variables Enumerations