306 lines
8.5 KiB
C++
306 lines
8.5 KiB
C++
// Filename: stringStreamBuf.cxx
|
|
// Created by: drose (02Jul07)
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
//
|
|
// PANDA 3D SOFTWARE
|
|
// Copyright (c) Carnegie Mellon University. All rights reserved.
|
|
//
|
|
// All use of this software is subject to the terms of the revised BSD
|
|
// license. You should have received a copy of this license along
|
|
// with this source code in a file named "LICENSE."
|
|
//
|
|
////////////////////////////////////////////////////////////////////
|
|
|
|
#include "stringStreamBuf.h"
|
|
#include "pnotify.h"
|
|
#include "config_express.h"
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::Constructor
|
|
// Access: Public
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
StringStreamBuf::
|
|
StringStreamBuf() {
|
|
#ifdef HAVE_IOSTREAM
|
|
_buffer = (char *)PANDA_MALLOC_ARRAY(2048);
|
|
char *ebuf = _buffer + 2048;
|
|
char *mbuf = _buffer + 1024;
|
|
setg(_buffer, mbuf, mbuf);
|
|
setp(mbuf, ebuf);
|
|
|
|
#else
|
|
allocate();
|
|
// Chop the buffer in half. The bottom half goes to the get buffer;
|
|
// the top half goes to the put buffer.
|
|
char *b = base();
|
|
char *t = ebuf();
|
|
char *m = b + (t - b) / 2;
|
|
setg(b, m, m);
|
|
setp(b, m);
|
|
#endif
|
|
|
|
_gpos = 0;
|
|
_ppos = 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::Destructor
|
|
// Access: Public, Virtual
|
|
// Description:
|
|
////////////////////////////////////////////////////////////////////
|
|
StringStreamBuf::
|
|
~StringStreamBuf() {
|
|
#ifdef HAVE_IOSTREAM
|
|
PANDA_FREE_ARRAY(_buffer);
|
|
#endif
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::clear
|
|
// Access: Public
|
|
// Description: Empties the buffer.
|
|
////////////////////////////////////////////////////////////////////
|
|
void StringStreamBuf::
|
|
clear() {
|
|
_data.clear();
|
|
_gpos = 0;
|
|
_ppos = 0;
|
|
|
|
pbump(pbase() - pptr());
|
|
gbump(egptr() - gptr());
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::read_chars
|
|
// Access: Public
|
|
// Description: Attempts to extract the indicated number of
|
|
// characters from the current file position. Returns
|
|
// the number of characters extracted.
|
|
////////////////////////////////////////////////////////////////////
|
|
size_t StringStreamBuf::
|
|
read_chars(char *start, size_t length) {
|
|
if (length == 0) {
|
|
return 0;
|
|
}
|
|
|
|
// Make sure the write buffer is flushed.
|
|
sync();
|
|
|
|
if (_data.size() <= _gpos) {
|
|
return 0;
|
|
}
|
|
|
|
length = min(length, _data.size() - _gpos);
|
|
memcpy(start, &_data[_gpos], length);
|
|
_gpos += length;
|
|
return length;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::write_chars
|
|
// Access: Public
|
|
// Description: Appends the indicated stream of characters to the
|
|
// current file position.
|
|
////////////////////////////////////////////////////////////////////
|
|
void StringStreamBuf::
|
|
write_chars(const char *start, size_t length) {
|
|
if (length != 0) {
|
|
// Make sure the read buffer is flushed.
|
|
size_t n = egptr() - gptr();
|
|
gbump(n);
|
|
_gpos -= n;
|
|
|
|
if (_data.size() > _ppos) {
|
|
// We are overwriting some data.
|
|
size_t remaining_length = _data.size() - _ppos;
|
|
size_t overwrite_length = min(remaining_length, length);
|
|
memcpy(&_data[_ppos], start, overwrite_length);
|
|
length -= overwrite_length;
|
|
_ppos += overwrite_length;
|
|
start += overwrite_length;
|
|
}
|
|
|
|
if (_data.size() < _ppos) {
|
|
// We need to append some zeroes.
|
|
_data.insert(_data.end(), _ppos - _data.size(), (unsigned char)0);
|
|
}
|
|
|
|
if (length != 0) {
|
|
// We are appending some data.
|
|
_data.insert(_data.begin() + _ppos, (const unsigned char *)start, (const unsigned char *)start + length);
|
|
_ppos += length;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::seekoff
|
|
// Access: Public, Virtual
|
|
// Description: Implements seeking within the stream.
|
|
////////////////////////////////////////////////////////////////////
|
|
streampos StringStreamBuf::
|
|
seekoff(streamoff off, ios_seekdir dir, ios_openmode which) {
|
|
streampos result = -1;
|
|
|
|
// Sync the iostream buffer first.
|
|
sync();
|
|
|
|
if (which & ios::in) {
|
|
// Determine the current file position.
|
|
size_t n = egptr() - gptr();
|
|
gbump(n);
|
|
_gpos -= n;
|
|
size_t cur_pos = _gpos;
|
|
size_t new_pos = cur_pos;
|
|
|
|
// Now adjust the data pointer appropriately.
|
|
switch (dir) {
|
|
case ios::beg:
|
|
new_pos = (size_t)off;
|
|
break;
|
|
|
|
case ios::cur:
|
|
new_pos = (size_t)((int)cur_pos + off);
|
|
break;
|
|
|
|
case ios::end:
|
|
new_pos = (size_t)((int)_data.size() + off);
|
|
break;
|
|
|
|
default:
|
|
// Shouldn't get here.
|
|
break;
|
|
}
|
|
|
|
_gpos = new_pos;
|
|
result = new_pos;
|
|
}
|
|
|
|
if (which & ios::out) {
|
|
// Determine the current file position.
|
|
size_t n = pptr() - pbase();
|
|
size_t cur_pos = _ppos + n;
|
|
size_t new_pos = cur_pos;
|
|
|
|
// Now adjust the data pointer appropriately.
|
|
switch (dir) {
|
|
case ios::beg:
|
|
new_pos = (size_t)off;
|
|
break;
|
|
|
|
case ios::cur:
|
|
new_pos = (size_t)((int)cur_pos + off);
|
|
break;
|
|
|
|
case ios::end:
|
|
new_pos = (size_t)((int)_data.size() + off);
|
|
break;
|
|
|
|
default:
|
|
// Shouldn't get here.
|
|
break;
|
|
}
|
|
|
|
_ppos = new_pos;
|
|
result = new_pos;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::seekpos
|
|
// Access: Public, Virtual
|
|
// Description: A variant on seekoff() to implement seeking within a
|
|
// stream.
|
|
//
|
|
// The MSDN Library claims that it is only necessary to
|
|
// redefine seekoff(), and not seekpos() as well, as the
|
|
// default implementation of seekpos() is supposed to
|
|
// map to seekoff() exactly as I am doing here; but in
|
|
// fact it must do something else, because seeking
|
|
// didn't work on Windows until I redefined this
|
|
// function as well.
|
|
////////////////////////////////////////////////////////////////////
|
|
streampos StringStreamBuf::
|
|
seekpos(streampos pos, ios_openmode which) {
|
|
return seekoff(pos, ios::beg, which);
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::overflow
|
|
// Access: Protected, Virtual
|
|
// Description: Called by the system ostream implementation when its
|
|
// internal buffer is filled, plus one character.
|
|
////////////////////////////////////////////////////////////////////
|
|
int StringStreamBuf::
|
|
overflow(int ch) {
|
|
size_t n = pptr() - pbase();
|
|
if (n != 0) {
|
|
write_chars(pbase(), n);
|
|
pbump(-(int)n);
|
|
}
|
|
|
|
if (ch != EOF) {
|
|
// Write one more character.
|
|
char c = ch;
|
|
write_chars(&c, 1);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::sync
|
|
// Access: Protected, Virtual
|
|
// Description: Called by the system iostream implementation to
|
|
// implement a flush operation.
|
|
////////////////////////////////////////////////////////////////////
|
|
int StringStreamBuf::
|
|
sync() {
|
|
size_t n = pptr() - pbase();
|
|
|
|
write_chars(pbase(), n);
|
|
pbump(-(int)n);
|
|
|
|
return 0;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////
|
|
// Function: StringStreamBuf::underflow
|
|
// Access: Protected, Virtual
|
|
// Description: Called by the system istream implementation when its
|
|
// internal buffer needs more characters.
|
|
////////////////////////////////////////////////////////////////////
|
|
int StringStreamBuf::
|
|
underflow() {
|
|
// Sometimes underflow() is called even if the buffer is not empty.
|
|
if (gptr() >= egptr()) {
|
|
// Mark the buffer filled (with buffer_size bytes).
|
|
size_t buffer_size = egptr() - eback();
|
|
gbump(-(int)buffer_size);
|
|
|
|
size_t num_bytes = buffer_size;
|
|
size_t read_count = read_chars(gptr(), buffer_size);
|
|
|
|
if (read_count != num_bytes) {
|
|
// Oops, we didn't read what we thought we would.
|
|
if (read_count == 0) {
|
|
gbump(num_bytes);
|
|
return EOF;
|
|
}
|
|
|
|
// Slide what we did read to the top of the buffer.
|
|
nassertr(read_count < num_bytes, EOF);
|
|
size_t delta = num_bytes - read_count;
|
|
memmove(gptr() + delta, gptr(), read_count);
|
|
gbump(delta);
|
|
}
|
|
}
|
|
|
|
return (unsigned char)*gptr();
|
|
}
|
|
|