/**
* @file tobjstrm.cc
*
* Turbo Vision - Version 2.0
*
* Copyright (c) 1994 by Borland International
* All Rights Reserved.
*
* Modified by Sergio Sigala <sergio@sigala.it>
* Modified by Max Okumoto <okumoto@ucsd.edu>
*/
#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 <tvision/tv.h>
#include <fstream>
#include <ios>
#include <assert.h>
#include <fcntl.h>
#include <limits.h>
#include <stdlib.h>
#include <string.h>
#include <sys/stat.h>
#include <arpa/inet.h>
extern "C" {
#include <sys/param.h>
}
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:
*
* <pre>
* enum StreamableError { peNotRegistered, peInvalidType };
* </pre>
*/
void
pstream::error(StreamableError)
{
abort();
}
/**
* Sets the given error condition, where StreamableError is defined as
* follows:
*
* <pre>
* enum StreamableError { peNotRegistered, peInvalidType };
* </pre>
*/
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:
*
* <pre>
* beg (start of stream)
*
* cur (current stream position)
*
* end (end of stream)
* </pre>
*/
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:
*
* <pre>
* beg (start of stream)
*
* cur (current stream position)
*
* end (end of stream)
* </pre>
*/
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);
}
}
syntax highlighted by Code2HTML, v. 0.9.1