open_toontown_panda3d/panda/src/putil/stringStreamBuf.cxx

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();
}