Panda3D
|
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