StringStream

This commit is contained in:
David Rose 2007-07-06 00:19:56 +00:00
parent 3d63d36cb7
commit a99dcb1547
18 changed files with 856 additions and 144 deletions

View File

@ -31,6 +31,8 @@ forcetype ConfigVariableManager
forcetype ConfigVariableSearchPath
forcetype ConfigVariableString
forcetype ios_base
forcetype ios
forcetype istream
forcetype ostream
forcetype iostream

View File

@ -176,6 +176,29 @@ open_read(const Filename &multifile_name) {
return read_index();
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::open_read
// Access: Public
// Description: Opens an anonymous Multifile for reading using an
// istream. There must be seek functionality via
// seekg() and tellg() on the istream.
//
// The Multifile does *not* close or delete the istream
// when Multifile.close() is called. It is the caller's
// responsibility to ensure that the istream pointer
// does not destruct during the lifetime of the
// Multifile.
////////////////////////////////////////////////////////////////////
bool Multifile::
open_read(istream *multifile_stream) {
close();
_timestamp = time(NULL);
_timestamp_dirty = true;
_read = multifile_stream;
_read->seekg(0, ios::beg);
return read_index();
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::open_write
// Access: Published
@ -204,6 +227,29 @@ open_write(const Filename &multifile_name) {
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::open_write
// Access: Public
// Description: Opens an anonymous Multifile for writing using an
// ostream. There must be seek functionality via
// seekp() and tellp() on the pstream.
//
// The Multifile does *not* close or delete the ostream
// when Multifile.close() is called. It is the caller's
// responsibility to ensure that the ostream pointer
// does not destruct during the lifetime of the
// Multifile.
////////////////////////////////////////////////////////////////////
bool Multifile::
open_write(ostream *multifile_stream) {
close();
_timestamp = time(NULL);
_timestamp_dirty = true;
_write = multifile_stream;
_write->seekp(0, ios::beg);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::open_read_write
// Access: Published
@ -243,6 +289,42 @@ open_read_write(const Filename &multifile_name) {
}
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::open_read_write
// Access: Public
// Description: Opens an anonymous Multifile for reading and writing
// using an iostream. There must be seek functionality
// via seekg()/seekp() and tellg()/tellp() on the
// iostream.
//
// The Multifile does *not* close or delete the iostream
// when Multifile.close() is called. It is the caller's
// responsibility to ensure that the iostream pointer
// does not destruct during the lifetime of the
// Multifile.
////////////////////////////////////////////////////////////////////
bool Multifile::
open_read_write(iostream *multifile_stream) {
close();
_timestamp = time(NULL);
_timestamp_dirty = true;
_read = multifile_stream;
_write = multifile_stream;
_write->seekp(0, ios::beg);
// Check whether the read stream is empty.
_read->seekg(0, ios::end);
if (_read->tellg() == (streampos)0) {
// The read stream is empty, which is always valid.
return true;
}
// The read stream is not empty, so we'd better have a valid
// Multifile.
_read->seekg(0, ios::beg);
return read_index();
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::close
// Access: Published
@ -361,6 +443,42 @@ add_subfile(const string &subfile_name, const Filename &filename,
return name;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::add_subfile
// Access: Public
// Description: Adds a file from a stream as a subfile to the Multifile.
// The indicated istream will be read and its contents
// added to the Multifile at the next call to flush().
//
// Note that the istream must remain untouched and
// unused by any other code until flush() is called. At
// that time, the Multifile will read the entire
// contents of the istream from the current file
// position to the end of the file. Subsequently, the
// Multifile will *not* close or delete the istream. It
// is the caller's responsibility to ensure that the
// istream pointer does not destruct during the lifetime
// of the Multifile.
//
// Returns the subfile name on success (it might have
// been modified slightly), or empty string on failure.
////////////////////////////////////////////////////////////////////
string Multifile::
add_subfile(const string &subfile_name, istream *subfile_data,
int compression_level) {
nassertr(is_write_valid(), string());
string name = standardize_subfile_name(subfile_name);
if (!name.empty()) {
Subfile *subfile = new Subfile;
subfile->_name = name;
subfile->_source = subfile_data;
add_new_subfile(subfile, compression_level);
}
return name;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::update_subfile
// Access: Published
@ -1028,6 +1146,34 @@ extract_subfile(int index, const Filename &filename) {
return extract_subfile_to(index, out);
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::extract_subfile_to
// Access: Public
// Description: Extracts the nth subfile to the indicated ostream.
////////////////////////////////////////////////////////////////////
bool Multifile::
extract_subfile_to(int index, ostream &out) {
nassertr(is_read_valid(), false);
nassertr(index >= 0 && index < (int)_subfiles.size(), false);
istream *in = open_read_subfile(index);
if (in == (istream *)NULL) {
return false;
}
int byte = in->get();
while (!in->fail() && !in->eof()) {
out.put(byte);
byte = in->get();
}
bool failed = (in->fail() && !in->eof());
delete in;
nassertr(!failed, false);
return (!out.fail());
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::compare_subfile
// Access: Published
@ -1117,6 +1263,7 @@ ls(ostream &out) const {
}
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::read_subfile
// Access: Public
@ -1125,151 +1272,53 @@ ls(ostream &out) const {
////////////////////////////////////////////////////////////////////
bool Multifile::
read_subfile(int index, string &result) {
nassertr(is_read_valid(), false);
nassertr(index >= 0 && index < (int)_subfiles.size(), false);
result = string();
istream *in = open_read_subfile(index);
if (in == (istream *)NULL) {
pvector<unsigned char> pv;
if (!read_subfile(index, pv)) {
return false;
}
int byte = in->get();
while (!in->eof() && !in->fail()) {
result += (char)byte;
byte = in->get();
if (!pv.empty()) {
result.append((const char *)&pv[0], pv.size());
}
bool failed = in->fail();
delete in;
nassertr(!failed, false);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::open_read
// Function: Multifile::read_subfile
// Access: Public
// Description: Opens an anonymous Multifile for reading using an
// istream. There must be seek functionality via
// seekg() and tellg() on the istream.
//
// This version of open_read() does not close the
// istream when Multifile.close() is called.
// Description: Fills a pvector with the entire contents of
// the indicated subfile.
////////////////////////////////////////////////////////////////////
bool Multifile::
open_read(istream *multifile_stream) {
close();
_timestamp = time(NULL);
_timestamp_dirty = true;
_read = multifile_stream;
_read->seekg(0, ios::beg);
return read_index();
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::open_write
// Access: Public
// Description: Opens an anonymous Multifile for writing using an
// ostream. There must be seek functionality via
// seekp() and tellp() on the pstream.
//
// This version of open_write() does not close the
// ostream when Multifile.close() is called.
////////////////////////////////////////////////////////////////////
bool Multifile::
open_write(ostream *multifile_stream) {
close();
_timestamp = time(NULL);
_timestamp_dirty = true;
_write = multifile_stream;
_write->seekp(0, ios::beg);
return true;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::open_read_write
// Access: Public
// Description: Opens an anonymous Multifile for reading and writing
// using an iostream. There must be seek functionality
// via seekg()/seekp() and tellg()/tellp() on the
// iostream.
//
// This version of open_read_write() does not close the
// iostream when Multifile.close() is called.
////////////////////////////////////////////////////////////////////
bool Multifile::
open_read_write(iostream *multifile_stream) {
close();
_timestamp = time(NULL);
_timestamp_dirty = true;
_read = multifile_stream;
_write = multifile_stream;
_write->seekp(0, ios::beg);
// Check whether the read stream is empty.
_read->seekg(0, ios::end);
if (_read->tellg() == (streampos)0) {
// The read stream is empty, which is always valid.
return true;
}
// The read stream is not empty, so we'd better have a valid
// Multifile.
_read->seekg(0, ios::beg);
return read_index();
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::add_subfile
// Access: Public
// Description: Adds a file from a stream as a subfile to the Multifile.
// The indicated istream will be read and its contents
// added to the Multifile at the next call to flush().
//
// Returns the subfile name on success (it might have
// been modified slightly), or empty string on failure.
////////////////////////////////////////////////////////////////////
string Multifile::
add_subfile(const string &subfile_name, istream *subfile_data,
int compression_level) {
nassertr(is_write_valid(), string());
string name = standardize_subfile_name(subfile_name);
if (!name.empty()) {
Subfile *subfile = new Subfile;
subfile->_name = name;
subfile->_source = subfile_data;
add_new_subfile(subfile, compression_level);
}
return name;
}
////////////////////////////////////////////////////////////////////
// Function: Multifile::extract_subfile_to
// Access: Public
// Description: Extracts the nth subfile to the indicated ostream.
////////////////////////////////////////////////////////////////////
bool Multifile::
extract_subfile_to(int index, ostream &out) {
read_subfile(int index, pvector<unsigned char> &result) {
nassertr(is_read_valid(), false);
nassertr(index >= 0 && index < (int)_subfiles.size(), false);
result.clear();
istream *in = open_read_subfile(index);
if (in == (istream *)NULL) {
return false;
}
int byte = in->get();
while (!in->fail() && !in->eof()) {
out.put(byte);
byte = in->get();
static const size_t buffer_size = 1024;
char buffer[buffer_size];
in->read(buffer, buffer_size);
size_t count = in->gcount();
while (count != 0) {
thread_consider_yield();
result.insert(result.end(), buffer, buffer + count);
in->read(buffer, buffer_size);
count = in->gcount();
}
bool failed = (in->fail() && !in->eof());
bool failed = in->fail() && !in->eof();
delete in;
nassertr(!failed, false);
return (!out.fail());
return true;
}
////////////////////////////////////////////////////////////////////

View File

@ -44,8 +44,11 @@ private:
PUBLISHED:
BLOCKING bool open_read(const Filename &multifile_name);
BLOCKING bool open_read(istream *multifile_stream);
BLOCKING bool open_write(const Filename &multifile_name);
BLOCKING bool open_write(ostream *multifile_stream);
BLOCKING bool open_read_write(const Filename &multifile_name);
BLOCKING bool open_read_write(iostream *multifile_stream);
BLOCKING void close();
INLINE const Filename &get_multifile_name() const;
@ -69,6 +72,8 @@ PUBLISHED:
string add_subfile(const string &subfile_name, const Filename &filename,
int compression_level);
string add_subfile(const string &subfile_name, istream *subfile_data,
int compression_level);
string update_subfile(const string &subfile_name, const Filename &filename,
int compression_level);
BLOCKING bool flush();
@ -93,6 +98,7 @@ PUBLISHED:
BLOCKING INLINE string read_subfile(int index);
BLOCKING istream *open_read_subfile(int index);
BLOCKING bool extract_subfile(int index, const Filename &filename);
BLOCKING bool extract_subfile_to(int index, ostream &out);
BLOCKING bool compare_subfile(int index, const Filename &filename);
void output(ostream &out) const;
@ -102,15 +108,7 @@ PUBLISHED:
public:
bool read_subfile(int index, string &result);
// Special interfaces to work with iostreams, not necessarily files.
bool open_read(istream *multifile_stream);
bool open_write(ostream *multifile_stream);
bool open_read_write(iostream *multifile_stream);
string add_subfile(const string &subfile_name, istream *subfile_data,
int compression_level);
bool extract_subfile_to(int index, ostream &out);
bool read_subfile(int index, pvector<unsigned char> &result);
private:
enum SubfileFlags {

View File

@ -31,6 +31,7 @@
#include "bamCacheRecord.h"
#include "sceneGraphReducer.h"
#include "renderState.h"
#include "bamFile.h"
bool Loader::_file_types_loaded = false;
TypeHandle Loader::_type_handle;
@ -62,6 +63,22 @@ Loader(const string &name, int num_threads) :
}
}
////////////////////////////////////////////////////////////////////
// Function: Loader::load_bam_stream
// Access: Published
// Description: Attempts to read a bam file from the indicated stream
// and return the scene graph defined there.
////////////////////////////////////////////////////////////////////
PT(PandaNode) Loader::
load_bam_stream(istream &in) {
BamFile bam_file;
if (!bam_file.open_read(in)) {
return NULL;
}
return bam_file.read_node();
}
////////////////////////////////////////////////////////////////////
// Function: Loader::output
// Access: Published, Virtual

View File

@ -84,6 +84,8 @@ PUBLISHED:
INLINE void load_async(AsyncTask *request);
BLOCKING PT(PandaNode) load_bam_stream(istream &in);
virtual void output(ostream &out) const;
private:

View File

@ -5940,6 +5940,29 @@ write_bam_file(const string &filename) const {
return okflag;
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::write_bam_stream
// Access: Published
// Description: Writes the contents of this node and below out to the
// indicated stream.
////////////////////////////////////////////////////////////////////
bool NodePath::
write_bam_stream(ostream &out) const {
nassertr_always(!is_empty(), false);
BamFile bam_file;
bool okflag = false;
if (bam_file.open_write(out)) {
if (bam_file.write_object(node())) {
okflag = true;
}
bam_file.close();
}
return okflag;
}
////////////////////////////////////////////////////////////////////
// Function: NodePath::find_common_ancestor
// Access: Private, Static

View File

@ -835,6 +835,7 @@ PUBLISHED:
INLINE string get_name() const;
BLOCKING bool write_bam_file(const string &filename) const;
BLOCKING bool write_bam_stream(ostream &out) const;
private:
static NodePathComponent *

View File

@ -97,17 +97,17 @@ PUBLISHED:
INLINE int get_read_x_size() const;
INLINE int get_read_y_size() const;
bool read(const Filename &filename, PNMFileType *type = NULL,
bool report_unknown_type = true);
bool read(istream &data, const string &filename = string(),
PNMFileType *type = NULL,
bool report_unknown_type = true);
bool read(PNMReader *reader);
BLOCKING bool read(const Filename &filename, PNMFileType *type = NULL,
bool report_unknown_type = true);
BLOCKING bool read(istream &data, const string &filename = string(),
PNMFileType *type = NULL,
bool report_unknown_type = true);
BLOCKING bool read(PNMReader *reader);
bool write(const Filename &filename, PNMFileType *type = NULL) const;
bool write(ostream &data, const string &filename = string(),
PNMFileType *type = NULL) const;
bool write(PNMWriter *writer) const;
BLOCKING bool write(const Filename &filename, PNMFileType *type = NULL) const;
BLOCKING bool write(ostream &data, const string &filename = string(),
PNMFileType *type = NULL) const;
BLOCKING bool write(PNMWriter *writer) const;
INLINE bool is_valid() const;

View File

@ -47,6 +47,35 @@ read_header(const Filename &filename, PNMFileType *type,
return false;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::read_header
// Access: Published
// Description: Reads the image header information only from the
// indicated stream.
//
// The filename is advisory only, and may be used
// to suggest a type if it has a known extension.
//
// If type is non-NULL, it is a suggestion for the type
// of file it is (and a non-NULL type will override any
// magic number test or filename extension lookup).
//
// Returns true if successful, false on error.
////////////////////////////////////////////////////////////////////
bool PNMImageHeader::
read_header(istream &data, const string &filename, PNMFileType *type,
bool report_unknown_type) {
PNMReader *reader = PNMImageHeader::make_reader
(&data, false, filename, string(), type, report_unknown_type);
if (reader != (PNMReader *)NULL) {
(*this) = (*reader);
delete reader;
return true;
}
return false;
}
////////////////////////////////////////////////////////////////////
// Function: PNMImageHeader::make_reader
// Access: Published

View File

@ -82,8 +82,10 @@ PUBLISHED:
INLINE PNMFileType *get_type() const;
INLINE void set_type(PNMFileType *type);
bool read_header(const Filename &filename, PNMFileType *type = NULL,
bool report_unknown_type = true);
BLOCKING bool read_header(const Filename &filename, PNMFileType *type = NULL,
bool report_unknown_type = true);
BLOCKING bool read_header(istream &data, const string &filename = string(),
PNMFileType *type = NULL, bool report_unknown_type = true);
PNMReader *make_reader(const Filename &filename,
PNMFileType *type = NULL,

View File

@ -59,6 +59,8 @@
spamDeletor.h \
sparseArray.I sparseArray.h \
string_utils.I string_utils.N string_utils.h \
stringStreamBuf.I stringStreamBuf.h \
stringStream.I stringStream.h \
timedCycle.I timedCycle.h typedWritable.I \
typedWritable.h typedWritableReferenceCount.I \
typedWritableReferenceCount.h updateSeq.I updateSeq.h \
@ -104,7 +106,10 @@
pta_int.cxx pta_ushort.cxx \
spamDeletor.cxx \
sparseArray.cxx \
string_utils.cxx timedCycle.cxx typedWritable.cxx \
string_utils.cxx \
stringStreamBuf.cxx \
stringStream.cxx \
timedCycle.cxx typedWritable.cxx \
typedWritableReferenceCount.cxx updateSeq.cxx \
uniqueIdAllocator.cxx \
vector_double.cxx vector_float.cxx \
@ -161,8 +166,10 @@
pta_float.h pta_int.h pta_ushort.h \
spamDeletor.h \
sparseArray.I sparseArray.h \
string_utils.I \
string_utils.h timedCycle.I timedCycle.h typedWritable.I \
string_utils.I string_utils.h \
stringStreamBuf.I stringStreamBuf.h \
stringStream.I stringStream.h \
timedCycle.I timedCycle.h typedWritable.I \
typedWritable.h typedWritableReferenceCount.I \
typedWritableReferenceCount.h updateSeq.I updateSeq.h \
uniqueIdAllocator.h \

View File

@ -16,6 +16,8 @@
#include "spamDeletor.cxx"
#include "sparseArray.cxx"
#include "string_utils.cxx"
#include "stringStreamBuf.cxx"
#include "stringStream.cxx"
#include "timedCycle.cxx"
#include "typedWritable.cxx"
#include "typedWritableReferenceCount.cxx"

View File

@ -0,0 +1,107 @@
// Filename: stringStream.I
// Created by: drose (03Jul07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: StringStream::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE StringStream::
StringStream() : iostream(&_buf) {
}
////////////////////////////////////////////////////////////////////
// Function: StringStream::Constructor
// Access: Published
// Description: This version of the constructor preloads the buffer
// with the indicated data.
////////////////////////////////////////////////////////////////////
INLINE StringStream::
StringStream(const string &source) : iostream(&_buf) {
write(source);
}
////////////////////////////////////////////////////////////////////
// Function: StringStream::clear_data
// Access: Published
// Description: Empties the buffer.
////////////////////////////////////////////////////////////////////
INLINE void StringStream::
clear_data() {
_buf.clear();
}
////////////////////////////////////////////////////////////////////
// Function: StringStream::get_data_size
// Access: Published
// Description: Returns the number of characters available to be read
// from the data stream.
////////////////////////////////////////////////////////////////////
INLINE size_t StringStream::
get_data_size() {
flush();
return _buf.get_data_size();
}
////////////////////////////////////////////////////////////////////
// Function: StringStream::read
// Access: Published
// Description: Extracts all the remaining characters from the data
// stream and stores them in the indicated string.
////////////////////////////////////////////////////////////////////
INLINE void StringStream::
read(string &data) {
read(data, get_data_size());
}
////////////////////////////////////////////////////////////////////
// Function: StringStream::read
// Access: Published
// Description: Extracts up to max_length characters from the data
// stream and returns them as a string.
////////////////////////////////////////////////////////////////////
INLINE string StringStream::
read(size_t max_length) {
string data;
read(data, max_length);
return data;
}
////////////////////////////////////////////////////////////////////
// Function: StringStream::read
// Access: Published
// Description: Extracts all the remaining characters from the data
// stream and returns them as a string.
////////////////////////////////////////////////////////////////////
INLINE string StringStream::
read() {
string data;
read(data);
return data;
}
////////////////////////////////////////////////////////////////////
// Function: StringStream::write
// Access: Published
// Description: Appends the indicated data to the data stream.
////////////////////////////////////////////////////////////////////
INLINE void StringStream::
write(const string &data) {
_buf.write_chars(data.data(), data.size());
}

View File

@ -0,0 +1,34 @@
// Filename: stringStream.cxx
// Created by: drose (03Jul07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "stringStream.h"
////////////////////////////////////////////////////////////////////
// Function: StringStream::read
// Access: Published
// Description: Extracts up to max_length characters from the data
// stream and stores them in the indicated string.
////////////////////////////////////////////////////////////////////
void StringStream::
read(string &data, size_t max_length) {
flush();
char *buffer = (char *)PANDA_MALLOC_ARRAY(max_length);
size_t length = _buf.read_chars(buffer, max_length);
data.append(buffer, length);
PANDA_FREE_ARRAY(buffer);
}

View File

@ -0,0 +1,53 @@
// Filename: stringStream.h
// Created by: drose (03Jul07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef STRINGSTREAM_H
#define STRINGSTREAM_H
#include "pandabase.h"
#include "stringStreamBuf.h"
////////////////////////////////////////////////////////////////////
// Class : StringStream
// Description : A bi-directional stream object that reads and writes
// data to an internal buffer, which can be appended to
// or read from as a string.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDAEXPRESS StringStream : public iostream {
PUBLISHED:
INLINE StringStream();
INLINE StringStream(const string &source);
INLINE void clear_data();
INLINE size_t get_data_size();
void read(string &data, size_t max_length);
INLINE void read(string &data);
INLINE string read(size_t max_length);
INLINE string read();
INLINE void write(const string &data);
private:
StringStreamBuf _buf;
};
#include "stringStream.I"
#endif

View File

@ -0,0 +1,30 @@
// Filename: stringStreamBuf.I
// Created by: drose (03Jul07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: StringStreamBuf::get_data_size
// Access: Public
// Description: Returns the number of characters remaining in the
// internal data buffer, not counting data which might
// still be in the iostream buffer.
////////////////////////////////////////////////////////////////////
INLINE size_t StringStreamBuf::
get_data_size() const {
return _data.size() - _gpos;
}

View File

@ -0,0 +1,296 @@
// Filename: stringStreamBuf.cxx
// Created by: drose (02Jul07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#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 (length != 0) {
// We are appending some data.
_data.insert(_data.begin() + _ppos, start, 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;
}
_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;
}
_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();
}

View File

@ -0,0 +1,60 @@
// Filename: stringStreamBuf.h
// Created by: drose (02Jul07)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef STRINGSTREAMBUF_H
#define STRINGSTREAMBUF_H
#include "pandabase.h"
#include "pvector.h"
////////////////////////////////////////////////////////////////////
// Class : StringStreamBuf
// Description : Used by StringStream to implement an stream that
// reads from and/or writes to a memory buffer, whose
// contents can be appended to or extracted at any time
// by application code.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA StringStreamBuf : public streambuf {
public:
StringStreamBuf();
virtual ~StringStreamBuf();
void clear();
INLINE size_t get_data_size() const;
size_t read_chars(char *start, size_t length);
void write_chars(const char *start, size_t length);
protected:
virtual streampos seekoff(streamoff off, ios_seekdir dir, ios_openmode which);
virtual streampos seekpos(streampos pos, ios_openmode which);
virtual int overflow(int c);
virtual int sync();
virtual int underflow();
private:
pvector<char> _data;
char *_buffer;
size_t _ppos;
size_t _gpos;
};
#include "stringStreamBuf.I"
#endif