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