Panda3D
Loading...
Searching...
No Matches
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
18using std::ios;
19using std::streamoff;
20using std::streampos;
21
22/**
23 *
24 */
25StringStreamBuf::
26StringStreamBuf() {
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 */
52StringStreamBuf::
53~StringStreamBuf() {
54#ifdef PHAVE_IOSTREAM
55 PANDA_FREE_ARRAY(_buffer);
56#endif
57}
58
59/**
60 * Empties the buffer.
61 */
63clear() {
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 */
77read_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 */
99write_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 */
132streampos StringStreamBuf::
133seekoff(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 */
211streampos StringStreamBuf::
212seekpos(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 */
220int StringStreamBuf::
221overflow(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 */
241int StringStreamBuf::
242sync() {
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 */
255int StringStreamBuf::
256underflow() {
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.