/** * @file tobjstrm.cc * * Turbo Vision - Version 2.0 * * Copyright (c) 1994 by Borland International * All Rights Reserved. * * Modified by Sergio Sigala * Modified by Max Okumoto */ #define Uses_TStreamable #define Uses_TStreamableClass #define Uses_TStreamableTypes #define Uses_TPWrittenObjects #define Uses_TPReadObjects #define Uses_pstream #define Uses_ipstream #define Uses_opstream #define Uses_iopstream #define Uses_ifpstream #define Uses_ofpstream #define Uses_fpstream #include #include #include #include #include #include #include #include #include #include extern "C" { #include } const uchar nullStringLen = UCHAR_MAX; TStreamableClass::TStreamableClass(const char *n, BUILDER b, int d ) : name( n ), build( b ), delta( d ) { pstream::initTypes(); pstream::registerType( this ); } TStreamableTypes::TStreamableTypes() : TNSSortedCollection( 5, 5 ) { } TStreamableTypes::~TStreamableTypes() { } void TStreamableTypes::registerType(const TStreamableClass *d ) { insert( (void *)d ); } const TStreamableClass *TStreamableTypes::lookup(const char name[] ) { ccIndex loc; if( search( (void *)name, loc ) ) return (TStreamableClass *)at( loc ); else return 0; } void * TStreamableTypes::keyOf( void *d ) { return (void *)((TStreamableClass *)d)->name; } int TStreamableTypes::compare( void *d1, void *d2 ) { return strcmp( (char *)d1, (char *)d2 ); } TPWrittenObjects::TPWrittenObjects() : TNSSortedCollection( 5, 5 ), curId( 0 ) { } TPWrittenObjects::~TPWrittenObjects() { } void TPWrittenObjects::registerObject(const void *adr ) { TPWObj *o = new TPWObj( adr, curId++ ); insert( o ); } P_id_type TPWrittenObjects::find(const void *d ) { ccIndex loc; if( search( (void *)d, loc ) ) return ((TPWObj *)at( loc ))->ident; else return P_id_notFound; } void * TPWrittenObjects::keyOf( void *d ) { return (void *)((TPWObj *)d)->address; } int TPWrittenObjects::compare( void *o1, void *o2 ) { if( o1 == o2 ) return 0; else if( ((char *)o1)+1 < ((char *)o2)+1 ) // force normalization return -1; else return 1; } TPWObj::TPWObj(const void *adr, P_id_type id ) : address( adr ), ident( id ) { } TPReadObjects::TPReadObjects() : TNSCollection( 5, 5 ), curId( 0 ) { } TPReadObjects::~TPReadObjects() { } void TPReadObjects::registerObject(const void *adr ) { ccIndex loc = insert( (void *)adr ); #ifndef __UNPATCHED assert( loc == (ccIndex)curId ); // to be sure that TNSCollection #else assert( loc == curId++ ); // to be sure that TNSCollection #endif // continues to work the way // it does now... #ifndef __UNPATCHED curId++; // Move the increment OUTSIDE the assertion. #endif } const void *TPReadObjects::find( P_id_type id ) { return at( id ); } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ /** * This form allocates a default buffer. */ pstream::pstream() { } /** * Destroys the pstream object. */ pstream::~pstream() { } /** * Creates the associated @ref TStreamableTypes object types. Called by the * @ref TStreamableClass constructor. */ void pstream::initTypes() { if (types == 0) types = new TStreamableTypes; } /** * Undocumented. */ void pstream::registerType(TStreamableClass *ts) { types->registerType(ts); } /** * Sets the given error condition, where StreamableError is defined as * follows: * *
 * enum StreamableError { peNotRegistered, peInvalidType };
 * 
*/ void pstream::error(StreamableError) { abort(); } /** * Sets the given error condition, where StreamableError is defined as * follows: * *
 * enum StreamableError { peNotRegistered, peInvalidType };
 * 
*/ void pstream::error(StreamableError, const TStreamable&) { abort(); } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ /** * This form creates a buffered ipstream with the given buffer. */ ipstream::ipstream(std::streambuf *sb) : std::istream(sb) { } /** * Destroys the ipstream object. */ ipstream::~ipstream() { objs.shouldDelete = False; objs.shutDown(); } /** * This form moves the stream's current position to the absolute * position given by `pos'. */ ipstream & ipstream::seekg(std::streampos pos) { objs.removeAll(); std::istream::seekg(pos); return *this; } /** * This form moves to a position relative to the current position by an * offset `off' (+ or -) starting at `dir'. Parameter `dir' can be set to: * *
 * beg (start of stream)
 *
 * cur (current stream position)
 *
 * end (end of stream)
 * 
*/ ipstream & ipstream::seekg(std::streamoff off, std::ios::seekdir dir) { objs.removeAll(); std::istream::seekg(off, dir); return *this; } /** * Returns the word at the current stream position. */ uchar ipstream::readByte() { uchar val; read((char *)&val, 1); return val; } /** * Returns the word at the current stream position. */ ushort ipstream::readWord() { /* SS: words are stored in little endian format (LSB first) */ ushort ret = readByte(); ret = ret | (readByte() << 8); return ret; } /** * Returns the long at the current stream position. */ ulong ipstream::readLong() { /* SS: ints are stored in little endian format (LSB first) */ ulong ret = readByte(); ret = ret | (readByte() << 8); ret = ret | (readByte() << 16); ret = ret | (readByte() << 24); return ret; } /** * Reads `sz' bytes from current stream position, and writes them to * the address given in `data'. */ void ipstream::readBytes(void *data, std::streamsize sz) { read((char *)data, sz); } /** * Returns a string read from the current stream position. */ char * ipstream::readString() { int ch = get(); if (ch == EOF) { return NULL; } uchar len = ch; if (len == nullStringLen) { return NULL; } char *buf = new char[len+1]; read(buf, len); buf[len] = EOS; return buf; } /** * Returns a string read from the current stream position. */ char * ipstream::readString(char *buf, unsigned maxLen) { assert(buf != NULL); int len = get(); if (len == EOF) { return NULL; } assert(len < maxLen); read(buf, len); buf[len] = EOS; return buf; } ipstream & ipstream::operator>>(char &ch) { int c = get(); if (c != EOF) { ch = (char)c; } return *this; } ipstream & ipstream::operator>>(signed char &ch) { int c = get(); if (c != EOF) { ch = (signed char)c; } return *this; } ipstream & ipstream::operator>>(unsigned char &ch) { int c = get(); if (c != EOF) { ch = (unsigned char)c; } return *this; } ipstream & ipstream::operator>>(signed short &sh) { sh = readWord(); return *this; } ipstream & ipstream::operator>>(unsigned short &sh) { sh = readWord(); return *this; } ipstream & ipstream::operator>>(signed int &i) { i = readLong(); return *this; } ipstream & ipstream::operator>>(unsigned int &i) { i = readLong(); return *this; } ipstream & ipstream::operator>>(signed long &l) { l = readLong(); return *this; } ipstream & ipstream::operator>>(unsigned long &l) { l = readLong(); return *this; } ipstream & ipstream::operator>>(float &f) { read((char *)&f, sizeof(f)); return *this; } ipstream & ipstream::operator>>(double &d) { read((char *)&d, sizeof(d)); return *this; } ipstream & ipstream::operator>>(long double &ld) { read((char *)&ld, sizeof(ld)); return *this; } ipstream & ipstream::operator>>(TStreamable& t) { const TStreamableClass *pc = readPrefix(); readData(pc, &t); readSuffix(); return *this; } ipstream & ipstream::operator>>(void *&t) { int ch = get(); switch (ch) { case pstream::ptNull: { t = 0; break; } case pstream::ptIndexed: { P_id_type index = readWord(); t = (void *)find(index); assert(t != 0); break; } case pstream::ptObject: { const TStreamableClass *pc = readPrefix(); t = readData(pc, 0); readSuffix(); break; } default: error(pstream::peInvalidType); break; } return *this; } /** * Returns the @ref TStreamableClass object corresponding to the class * name stored at the current position. */ const TStreamableClass * ipstream::readPrefix() { int ch = get(); assert(ch == '['); // don't combine this with the previous line! // We must always do the read, even if we're // not checking assertions char name[128]; readString(name, sizeof name); return types->lookup(name); } /** * Invokes the appropriate read function to read from the stream to the * object `mem'. If `mem' is 0, the appropriate build function is called * first. */ void * ipstream::readData(const TStreamableClass *c, TStreamable *mem) { if (mem == 0) mem = c->build(); /* * Register the actual address of the object, not the address * of the TStreamable sub-object */ registerObject((char *)mem - c->delta); return mem->read(*this); } /** * Reads and checks the final byte of an object's name field. */ void ipstream::readSuffix() { int ch = get(); /* * Don't combine this with the previous line! * We must always do the write, even if we're * not checking assertions */ assert(ch == ']'); } /** * Returns a pointer to the object corresponding to `id'. */ const void * ipstream::find(P_id_type id) { return objs.find(id); } /** * Registers the class of the object pointed by `adr'. */ void ipstream::registerObject(const void *adr) { objs.registerObject(adr); } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ /** * This form creates a buffered opstream with the given buffer. */ opstream::opstream(std::streambuf *sb) : std::ostream(sb) { } /** * Destroys the opstream object. */ opstream::~opstream() { objs.shutDown(); } /** * This form moves the stream's current position to the absolute * position given by `pos'. */ opstream & opstream::seekp(std::streampos pos) { #ifndef __UNPATCHED objs.freeAll(); // CMF 07.11.92 --- delete the TPWObj's #endif objs.removeAll(); std::ostream::seekp(pos); return *this; } /** * This form moves to a position relative to the current position by an * offset `off' (+ or -) starting at `dir'. Parameter `dir' can be set to: * *
 * beg (start of stream)
 *
 * cur (current stream position)
 *
 * end (end of stream)
 * 
*/ opstream & opstream::seekp(std::streamoff off, std::ios::seekdir dir) { #ifndef __UNPATCHED objs.freeAll(); // CMF 07.11.92 ... s.a. #endif objs.removeAll(); std::ostream::seekp(off, dir); return *this; } /** * Writes character `ch' to the stream. */ void opstream::writeByte(uchar ch) { write((char *)&ch, 1); } /** * Writes `sz' bytes from `data' buffer to the stream. */ void opstream::writeBytes(const void *data, std::streamsize sz) { write((char *)data, sz); } /** * Writes the word `us' to the stream. */ void opstream::writeWord( ushort sh ) { /* SS: words are stored in little endian format (LSB first) */ writeByte(sh & 0xff); writeByte((sh >> 8) & 0xff); } /** * Writes `str' to the stream (together with a leading length byte). */ void opstream::writeString(const char *str ) { if (str == 0 ) { writeByte( nullStringLen ); return; } int len = strlen( str ); writeByte( (uchar)len ); writeBytes( str, len ); } opstream & opstream::operator<<(char ch) { writeByte( ch ); return *this; } opstream & opstream::operator<<(signed char ch) { writeByte( ch ); return *this; } opstream & opstream::operator<<(unsigned char ch) { writeByte( ch ); return *this; } opstream & opstream::operator<<(signed short sh) { writeWord( sh ); return *this; } opstream & opstream::operator<<(unsigned short sh) { writeWord( sh ); return *this; } opstream & opstream::operator<<(signed int i) { /* SS: ints are stored in little endian format (LSB first) */ writeByte(i & 0xff); writeByte((i >> 8) & 0xff); writeByte((i >> 16) & 0xff); writeByte((i >> 24) & 0xff); return *this; } opstream & opstream::operator<<(unsigned int i) { /* SS: ints are stored in little endian format (LSB first) */ writeByte(i & 0xff); writeByte((i >> 8) & 0xff); writeByte((i >> 16) & 0xff); writeByte((i >> 24) & 0xff); return *this; } opstream & opstream::operator<<(signed long l) { /* SS: longs are stored in little endian format (LSB first) */ writeByte(l & 0xff); writeByte((l >> 8) & 0xff); writeByte((l >> 16) & 0xff); writeByte((l >> 24) & 0xff); return *this; } opstream & opstream::operator<<(unsigned long l) { /* SS: longs are stored in little endian format (LSB first) */ writeByte(l & 0xff); writeByte((l >> 8) & 0xff); writeByte((l >> 16) & 0xff); writeByte((l >> 24) & 0xff); return *this; } opstream & opstream::operator<<(float f ) { writeBytes( &f, sizeof(f) ); return *this; } opstream & opstream::operator<<(double d ) { writeBytes( &d, sizeof(d) ); return *this; } opstream & opstream::operator<<(long double ld ) { writeBytes( &ld, sizeof(ld) ); return *this; } opstream & opstream::operator<<(TStreamable &t) { writePrefix( t ); writeData( t ); writeSuffix( t ); return *this; } opstream & opstream::operator<<(TStreamable *t) { P_id_type index; if (t == 0 ) writeByte( pstream::ptNull ); else if ((index = find( t )) != P_id_notFound ) { writeByte( pstream::ptIndexed ); writeWord( index ); } else { writeByte( pstream::ptObject ); *this << *t; } return *this; } /** * Writes the class name prefix to the stream. * * The << operator uses this function to write a prefix and suffix around * the data written with @ref writeData(). The prefix/suffix is used to * ensure type-safe stream I/O. */ void opstream::writePrefix(const TStreamable& t ) { writeByte( '[' ); writeString( t.streamableName() ); } /** * Writes data to the stream by calling the appropriate class's write * member function for the object being written. */ void opstream::writeData( TStreamable& t ) { if (types->lookup( t.streamableName() ) == 0 ) error( peNotRegistered, t ); else { registerObject( &t ); t.write( *this ); } } /** * Writes the class name suffix to the stream. * * The << operator uses this function to write a prefix and suffix around * the data written with @ref writeData(). The prefix/suffix is used to * ensure type-safe stream I/O. */ void opstream::writeSuffix(const TStreamable &) { writeByte(']'); } /** * Returns the type ID for the object ad address `adr'. */ P_id_type opstream::find(const void *adr) { return objs.find(adr); } /** * Registers the class of the object pointed by `adr'. */ void opstream::registerObject(const void *adr) { objs.registerObject(adr); } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ /** * This form creates a buffered iopstream with the given buffer. */ iopstream::iopstream(std::streambuf *sb) : ipstream(sb), opstream(sb) { } /** * Destroys the iopstream object. */ iopstream::~iopstream() { } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ /** * Creates a buffered ifpstream object. */ ifpstream::ifpstream() : ipstream(NULL), buf() { init(&buf); } /** * Creates a buffered ifpstream object. You can open a file and attach it * to the stream by specifying the `name' and `omode' arguments. */ ifpstream::ifpstream(const char name[], std::ios::openmode omode) : ipstream(NULL), buf() { init(&buf); open(name, omode); } /** * Destroys the ifpstream object. */ ifpstream::~ifpstream() { } /** * Opens the the named file in the given mode (app, ate, in, out, binary, * trunc, nocreate, or noreplace) and protection. The opened file is * attached to this stream. */ void ifpstream::open(const char name[], std::ios::openmode omode) { using std::ios; if (!buf.open(name, omode | ios::in | ios::binary)) { this->setstate(ios_base::failbit); } } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ /** * Creates a buffered ofpstream object. */ ofpstream::ofpstream() : opstream(NULL), buf() { init(&buf); } /** * Creates a buffered ofpstream object. You can open a file and attach it * to the stream by specifying the `name' and `omode' arguments. */ ofpstream::ofpstream(const char name[], std::ios::openmode omode) : opstream(NULL), buf() { init(&buf); open(name, omode); } /** * Destroys the ofpstream object. */ ofpstream::~ofpstream() { } /** * Opens the the named file in the given mode (app, ate, in, out, binary, * trunc, nocreate, or noreplace) and protection. The opened file is * attached to this stream. */ void ofpstream::open(const char name[], std::ios::openmode omode) { using std::ios; if (!buf.open(name, omode | ios::out | ios::binary)) { this->setstate(ios_base::failbit); } } /*---------------------------------------------------------------------------* * *---------------------------------------------------------------------------*/ /** * Creates a buffered fpstream object. */ fpstream::fpstream() : iopstream(NULL), buf() { init(&buf); } /** * Creates a buffered fpstream object. You can open a file and attach it * to the stream by specifying the `name' and `omode' arguments. */ fpstream::fpstream(const char name[], std::ios::openmode omode) : iopstream(NULL), buf() { init(&buf); open(name, omode); } /** * Destroys the fpstream object. */ fpstream::~fpstream() { } /** * Opens the named file in the given mode (app, ate, in, out, binary, * trunc, nocreate, noreplace) and protection. The opened file is * attatched to this stream. */ void fpstream::open(const char name[], std::ios::openmode omode) { using std::ios; if (!buf.open(name, omode | ios::in | ios::out | ios::binary)) { this->setstate(ios_base::failbit); } }