Panda3D
 All Classes Functions Variables Enumerations
stringStreamBuf.cxx
1 // Filename: stringStreamBuf.cxx
2 // Created by: drose (02Jul07)
3 //
4 ////////////////////////////////////////////////////////////////////
5 //
6 // PANDA 3D SOFTWARE
7 // Copyright (c) Carnegie Mellon University. All rights reserved.
8 //
9 // All use of this software is subject to the terms of the revised BSD
10 // license. You should have received a copy of this license along
11 // with this source code in a file named "LICENSE."
12 //
13 ////////////////////////////////////////////////////////////////////
14 
15 #include "stringStreamBuf.h"
16 #include "pnotify.h"
17 #include "config_express.h"
18 
19 ////////////////////////////////////////////////////////////////////
20 // Function: StringStreamBuf::Constructor
21 // Access: Public
22 // Description:
23 ////////////////////////////////////////////////////////////////////
24 StringStreamBuf::
25 StringStreamBuf() {
26 #ifdef PHAVE_IOSTREAM
27  _buffer = (char *)PANDA_MALLOC_ARRAY(2048);
28  char *ebuf = _buffer + 2048;
29  char *mbuf = _buffer + 1024;
30  setg(_buffer, mbuf, mbuf);
31  setp(mbuf, ebuf);
32 
33 #else
34  allocate();
35  // Chop the buffer in half. The bottom half goes to the get buffer;
36  // the top half goes to the put buffer.
37  char *b = base();
38  char *t = ebuf();
39  char *m = b + (t - b) / 2;
40  setg(b, m, m);
41  setp(b, m);
42 #endif
43 
44  _gpos = 0;
45  _ppos = 0;
46 }
47 
48 ////////////////////////////////////////////////////////////////////
49 // Function: StringStreamBuf::Destructor
50 // Access: Public, Virtual
51 // Description:
52 ////////////////////////////////////////////////////////////////////
53 StringStreamBuf::
54 ~StringStreamBuf() {
55 #ifdef PHAVE_IOSTREAM
56  PANDA_FREE_ARRAY(_buffer);
57 #endif
58 }
59 
60 ////////////////////////////////////////////////////////////////////
61 // Function: StringStreamBuf::clear
62 // Access: Public
63 // Description: Empties the buffer.
64 ////////////////////////////////////////////////////////////////////
66 clear() {
67  _data.clear();
68  _gpos = 0;
69  _ppos = 0;
70 
71  pbump(pbase() - pptr());
72  gbump(egptr() - gptr());
73 }
74 
75 ////////////////////////////////////////////////////////////////////
76 // Function: StringStreamBuf::read_chars
77 // Access: Public
78 // Description: Attempts to extract the indicated number of
79 // characters from the current file position. Returns
80 // the number of characters extracted.
81 ////////////////////////////////////////////////////////////////////
82 size_t StringStreamBuf::
83 read_chars(char *start, size_t length) {
84  if (length == 0) {
85  return 0;
86  }
87 
88  // Make sure the write buffer is flushed.
89  sync();
90 
91  if (_data.size() <= _gpos) {
92  return 0;
93  }
94 
95  length = min(length, _data.size() - _gpos);
96  memcpy(start, &_data[_gpos], length);
97  _gpos += length;
98  return length;
99 }
100 
101 ////////////////////////////////////////////////////////////////////
102 // Function: StringStreamBuf::write_chars
103 // Access: Public
104 // Description: Appends the indicated stream of characters to the
105 // current file position.
106 ////////////////////////////////////////////////////////////////////
108 write_chars(const char *start, size_t length) {
109  if (length != 0) {
110  // Make sure the read buffer is flushed.
111  size_t n = egptr() - gptr();
112  gbump(n);
113  _gpos -= n;
114 
115  if (_data.size() > _ppos) {
116  // We are overwriting some data.
117  size_t remaining_length = _data.size() - _ppos;
118  size_t overwrite_length = min(remaining_length, length);
119  memcpy(&_data[_ppos], start, overwrite_length);
120  length -= overwrite_length;
121  _ppos += overwrite_length;
122  start += overwrite_length;
123  }
124 
125  if (_data.size() < _ppos) {
126  // We need to append some zeroes.
127  _data.insert(_data.end(), _ppos - _data.size(), (unsigned char)0);
128  }
129 
130  if (length != 0) {
131  // We are appending some data.
132  _data.insert(_data.begin() + _ppos, (const unsigned char *)start, (const unsigned char *)start + length);
133  _ppos += length;
134  }
135  }
136 }
137 
138 ////////////////////////////////////////////////////////////////////
139 // Function: StringStreamBuf::seekoff
140 // Access: Public, Virtual
141 // Description: Implements seeking within the stream.
142 ////////////////////////////////////////////////////////////////////
143 streampos StringStreamBuf::
144 seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
145  streampos result = -1;
146 
147  // Sync the iostream buffer first.
148  sync();
149 
150  if (which & ios::in) {
151  // Determine the current file position.
152  size_t n = egptr() - gptr();
153  gbump(n);
154  _gpos -= n;
155  size_t cur_pos = _gpos;
156  size_t new_pos = cur_pos;
157 
158  // Now adjust the data pointer appropriately.
159  switch (dir) {
160  case ios::beg:
161  new_pos = (size_t)off;
162  break;
163 
164  case ios::cur:
165  new_pos = (size_t)((int)cur_pos + off);
166  break;
167 
168  case ios::end:
169  new_pos = (size_t)((int)_data.size() + off);
170  break;
171 
172  default:
173  // Shouldn't get here.
174  break;
175  }
176 
177  _gpos = new_pos;
178  result = new_pos;
179  }
180 
181  if (which & ios::out) {
182  // Determine the current file position.
183  size_t n = pptr() - pbase();
184  size_t cur_pos = _ppos + n;
185  size_t new_pos = cur_pos;
186 
187  // Now adjust the data pointer appropriately.
188  switch (dir) {
189  case ios::beg:
190  new_pos = (size_t)off;
191  break;
192 
193  case ios::cur:
194  new_pos = (size_t)((int)cur_pos + off);
195  break;
196 
197  case ios::end:
198  new_pos = (size_t)((int)_data.size() + off);
199  break;
200 
201  default:
202  // Shouldn't get here.
203  break;
204  }
205 
206  _ppos = new_pos;
207  result = new_pos;
208  }
209 
210  return result;
211 }
212 
213 ////////////////////////////////////////////////////////////////////
214 // Function: StringStreamBuf::seekpos
215 // Access: Public, Virtual
216 // Description: A variant on seekoff() to implement seeking within a
217 // stream.
218 //
219 // The MSDN Library claims that it is only necessary to
220 // redefine seekoff(), and not seekpos() as well, as the
221 // default implementation of seekpos() is supposed to
222 // map to seekoff() exactly as I am doing here; but in
223 // fact it must do something else, because seeking
224 // didn't work on Windows until I redefined this
225 // function as well.
226 ////////////////////////////////////////////////////////////////////
227 streampos StringStreamBuf::
228 seekpos(streampos pos, ios_openmode which) {
229  return seekoff(pos, ios::beg, which);
230 }
231 
232 ////////////////////////////////////////////////////////////////////
233 // Function: StringStreamBuf::overflow
234 // Access: Protected, Virtual
235 // Description: Called by the system ostream implementation when its
236 // internal buffer is filled, plus one character.
237 ////////////////////////////////////////////////////////////////////
238 int StringStreamBuf::
239 overflow(int ch) {
240  size_t n = pptr() - pbase();
241  if (n != 0) {
242  write_chars(pbase(), n);
243  pbump(-(int)n);
244  }
245 
246  if (ch != EOF) {
247  // Write one more character.
248  char c = ch;
249  write_chars(&c, 1);
250  }
251 
252  return 0;
253 }
254 
255 ////////////////////////////////////////////////////////////////////
256 // Function: StringStreamBuf::sync
257 // Access: Protected, Virtual
258 // Description: Called by the system iostream implementation to
259 // implement a flush operation.
260 ////////////////////////////////////////////////////////////////////
261 int StringStreamBuf::
262 sync() {
263  size_t n = pptr() - pbase();
264 
265  write_chars(pbase(), n);
266  pbump(-(int)n);
267 
268  return 0;
269 }
270 
271 ////////////////////////////////////////////////////////////////////
272 // Function: StringStreamBuf::underflow
273 // Access: Protected, Virtual
274 // Description: Called by the system istream implementation when its
275 // internal buffer needs more characters.
276 ////////////////////////////////////////////////////////////////////
277 int StringStreamBuf::
278 underflow() {
279  // Sometimes underflow() is called even if the buffer is not empty.
280  if (gptr() >= egptr()) {
281  // Mark the buffer filled (with buffer_size bytes).
282  size_t buffer_size = egptr() - eback();
283  gbump(-(int)buffer_size);
284 
285  size_t num_bytes = buffer_size;
286  size_t read_count = read_chars(gptr(), buffer_size);
287 
288  if (read_count != num_bytes) {
289  // Oops, we didn't read what we thought we would.
290  if (read_count == 0) {
291  gbump(num_bytes);
292  return EOF;
293  }
294 
295  // Slide what we did read to the top of the buffer.
296  nassertr(read_count < num_bytes, EOF);
297  size_t delta = num_bytes - read_count;
298  memmove(gptr() + delta, gptr(), read_count);
299  gbump(delta);
300  }
301  }
302 
303  return (unsigned char)*gptr();
304 }
305 
void clear()
Empties the buffer.
void write_chars(const char *start, size_t length)
Appends the indicated stream of characters to the current file position.
size_t read_chars(char *start, size_t length)
Attempts to extract the indicated number of characters from the current file position.