diff --git a/panda/src/express/config_express.N b/panda/src/express/config_express.N index 7518940a6d..1a9b2c467b 100644 --- a/panda/src/express/config_express.N +++ b/panda/src/express/config_express.N @@ -31,6 +31,8 @@ forcetype ConfigVariableManager forcetype ConfigVariableSearchPath forcetype ConfigVariableString +forcetype ios_base +forcetype ios forcetype istream forcetype ostream forcetype iostream diff --git a/panda/src/express/multifile.cxx b/panda/src/express/multifile.cxx index c3e2e12e92..cba52d413d 100644 --- a/panda/src/express/multifile.cxx +++ b/panda/src/express/multifile.cxx @@ -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 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 &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; } //////////////////////////////////////////////////////////////////// diff --git a/panda/src/express/multifile.h b/panda/src/express/multifile.h index 1e05d638a7..c9e73741f9 100644 --- a/panda/src/express/multifile.h +++ b/panda/src/express/multifile.h @@ -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 &result); private: enum SubfileFlags { diff --git a/panda/src/pgraph/loader.cxx b/panda/src/pgraph/loader.cxx index dbd678aea4..a3361e9a87 100644 --- a/panda/src/pgraph/loader.cxx +++ b/panda/src/pgraph/loader.cxx @@ -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 diff --git a/panda/src/pgraph/loader.h b/panda/src/pgraph/loader.h index 35619ef895..a79740fb73 100644 --- a/panda/src/pgraph/loader.h +++ b/panda/src/pgraph/loader.h @@ -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: diff --git a/panda/src/pgraph/nodePath.cxx b/panda/src/pgraph/nodePath.cxx index 8779255e63..7f4fe3ab71 100644 --- a/panda/src/pgraph/nodePath.cxx +++ b/panda/src/pgraph/nodePath.cxx @@ -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 diff --git a/panda/src/pgraph/nodePath.h b/panda/src/pgraph/nodePath.h index c999676036..b2ec017288 100644 --- a/panda/src/pgraph/nodePath.h +++ b/panda/src/pgraph/nodePath.h @@ -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 * diff --git a/panda/src/pnmimage/pnmImage.h b/panda/src/pnmimage/pnmImage.h index 4b8fadd46f..4252dc43a4 100644 --- a/panda/src/pnmimage/pnmImage.h +++ b/panda/src/pnmimage/pnmImage.h @@ -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; diff --git a/panda/src/pnmimage/pnmImageHeader.cxx b/panda/src/pnmimage/pnmImageHeader.cxx index eeb2d317d8..2bba31f4ea 100644 --- a/panda/src/pnmimage/pnmImageHeader.cxx +++ b/panda/src/pnmimage/pnmImageHeader.cxx @@ -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 diff --git a/panda/src/pnmimage/pnmImageHeader.h b/panda/src/pnmimage/pnmImageHeader.h index d418391773..5a5a4802a7 100644 --- a/panda/src/pnmimage/pnmImageHeader.h +++ b/panda/src/pnmimage/pnmImageHeader.h @@ -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, diff --git a/panda/src/putil/Sources.pp b/panda/src/putil/Sources.pp index 09a9200d69..f63225fe39 100644 --- a/panda/src/putil/Sources.pp +++ b/panda/src/putil/Sources.pp @@ -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 \ diff --git a/panda/src/putil/putil_composite2.cxx b/panda/src/putil/putil_composite2.cxx index e40dc8879a..97befe1b1a 100644 --- a/panda/src/putil/putil_composite2.cxx +++ b/panda/src/putil/putil_composite2.cxx @@ -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" diff --git a/panda/src/putil/stringStream.I b/panda/src/putil/stringStream.I new file mode 100644 index 0000000000..8277868bdb --- /dev/null +++ b/panda/src/putil/stringStream.I @@ -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()); +} diff --git a/panda/src/putil/stringStream.cxx b/panda/src/putil/stringStream.cxx new file mode 100644 index 0000000000..305a4d0fca --- /dev/null +++ b/panda/src/putil/stringStream.cxx @@ -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); +} diff --git a/panda/src/putil/stringStream.h b/panda/src/putil/stringStream.h new file mode 100644 index 0000000000..d44e64cf75 --- /dev/null +++ b/panda/src/putil/stringStream.h @@ -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 + diff --git a/panda/src/putil/stringStreamBuf.I b/panda/src/putil/stringStreamBuf.I new file mode 100644 index 0000000000..736e44d7ec --- /dev/null +++ b/panda/src/putil/stringStreamBuf.I @@ -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; +} diff --git a/panda/src/putil/stringStreamBuf.cxx b/panda/src/putil/stringStreamBuf.cxx new file mode 100644 index 0000000000..b57d48a745 --- /dev/null +++ b/panda/src/putil/stringStreamBuf.cxx @@ -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(); +} + diff --git a/panda/src/putil/stringStreamBuf.h b/panda/src/putil/stringStreamBuf.h new file mode 100644 index 0000000000..0c5355a3c5 --- /dev/null +++ b/panda/src/putil/stringStreamBuf.h @@ -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 _data; + char *_buffer; + size_t _ppos; + size_t _gpos; +}; + +#include "stringStreamBuf.I" + +#endif