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  */
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 }
void write_chars(const char *start, size_t length)
Appends the indicated stream of characters to the current file position.
void clear()
Empties the buffer.
size_t read_chars(char *start, size_t length)
Attempts to extract the indicated number of characters from the current file position.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.