/*------------------------------------------------------------------------*/ /* */ /* OBJSTRM.CPP */ /* */ /* Copyright (c) 1992, 1994 Borland International */ /* All Rights Reserved */ /* */ /*------------------------------------------------------------------------*/ #if !defined( _Windows ) #define _Windows #endif #if !defined( __ALLOC_H ) #include #endif #if !defined( __CHECKS_H ) #include #endif #if !defined( __CSTRING_H ) #include #endif #if !defined( CLASSLIB_STREAMBL_H ) #include #endif #if !defined( CLASSLIB_OBJSTRM_H ) #include #endif #if defined( __FLAT__ ) #define _fstrncpy strncpy #define _fstrcpy strcpy #define _fstrlen strlen #define _fmemcpy memcpy #define farmalloc malloc #endif DIAG_DEFINE_GROUP(Objstrm,1,0); const uint32 streamVersion = 0x0101; const char versionIndicator = ':'; const char EOS = '\0'; const uint8 oldNullStringLen = UCHAR_MAX; const uint32 nullStringLen = ULONG_MAX; TStreamableTypes *pstream::types = 0; const char *TStreamer::StreamableName() const { return 0; } TStreamableClass::TStreamableClass( const char *n, BUILDER b, int d, ModuleId id ) : ObjectBuilder( b, d ), ModId(id) { ObjectId = new char[strlen(n)+1]; strcpy( CONST_CAST(char *,ObjectId), n ); pstream::initTypes(); if( id != 0 ) // id == 0 is used only during lookup. // It flags an instance that shouldn't be registered pstream::types->RegisterType( id, *this ); } TStreamableClass::~TStreamableClass() { if( ModId != 0 ) pstream::types->UnRegisterType( ModId, *this ); delete [] CONST_CAST(char *,ObjectId); } void TStreamableTypes::RegisterType( ModuleId, TStreamableClass& ts ) { Types.Add(&ts); } void TStreamableTypes::UnRegisterType( ModuleId, TStreamableClass& ts ) { Types.Detach(&ts); if( Types.Count() == 0 ) pstream::releaseTypes(); } const ObjectBuilder *TStreamableTypes::Lookup( ModuleId, const char *name ) const { unsigned loc = Types.Find(&TStreamableClass(name,0,0,0)); if( loc == UINT_MAX ) { string msg; msg.reserve(128); msg = "Attempt to stream unregistered type '"; msg += name; msg += "'"; throw xmsg(msg); } return Types[loc]; } void TPReadObjects::RemoveAll() { Data.Flush(); } void TPReadObjects::RegisterObject( TStreamableBase *adr ) { Data.Add( adr ); } TStreamableBase *TPReadObjects::Find( P_id_type id ) { return Data[id]; } TPReadObjects::TPReadObjects() : Data(5,5) { Data.Add(0); // prime it: 0 is not a legal index. } TPWrittenObjects::TPWrittenObjects() : CurId(0), Data(5,5) { } void TPWrittenObjects::RemoveAll() { CurId = 0; Data.Flush(); } void TPWrittenObjects::RegisterObject( TStreamableBase *adr ) { Data.Add( TPWObj( ((char *)(void *)adr)+1, ++CurId ) ); } void TPWrittenObjects::RegisterVB( const TStreamableBase *adr ) { Data.Add( TPWObj( adr, ++CurId ) ); } P_id_type TPWrittenObjects::FindObject( TStreamableBase *d ) { unsigned res = Data.Find( TPWObj(((char *)(void *)d)+1,0) ); if( res == UINT_MAX ) return 0; else return Data[res].Ident; } P_id_type TPWrittenObjects::FindVB( TStreamableBase *d ) { unsigned res = Data.Find( TPWObj(d,0) ); if( res == UINT_MAX ) return 0; else return Data[res].Ident; } pstream::~pstream() { } void pstream::initTypes() { if( types == 0 ) types = new TStreamableTypes; } void pstream::releaseTypes() { delete types; types = 0; } streampos ipstream::tellg() { streampos res; if( !good() ) res = streampos(EOF); else { res = bp->seekoff( 0, ios::cur, ios::in ); if( res == streampos(EOF) ) clear( ios::failbit ); } return res; } ipstream& ipstream::seekg( streampos pos ) { if( good() ) { objs.RemoveAll(); if( bp->seekoff( pos, ios::beg, ios::in ) == streampos(EOF) ) clear( ios::failbit ); } return *this; } ipstream& ipstream::seekg( streamoff off, ios::seek_dir dir ) { if( good() ) { objs.RemoveAll(); if( bp->seekoff( off, dir, ios::in ) == streampos(EOF) ) clear( ios::failbit ); } return *this; } uint8 ipstream::readByte() { int res; if( !good() ) res = uint8(0); else { res = bp->sbumpc(); if( res == EOF ) clear( ios::failbit ); } return uint8(res); } void ipstream::readBytes( void *data, size_t sz ) { PRECONDITION( data != 0 ); if( good() && sz > 0 ) { if( bp->sgetn( (char *)data, sz ) != sz ) clear( ios::failbit ); } } void ipstream::freadBytes( void _BIDSFARDATA *data, size_t sz ) { PRECONDITION( data != 0 ); if( good() && sz > 0 ) { char *buf = new char[sz]; if( bp->sgetn( buf, sz ) != sz ) clear( ios::failbit ); else _fmemcpy( data, buf, sz); delete [] buf; } } uint32 ipstream::readWord() { if( getVersion() > 0 ) return readWord32(); else return readWord16(); } uint16 ipstream::readWord16() { if( !good() ) return 0; else { uint16 temp; if( bp->sgetn( (char *)&temp, sizeof( temp ) ) != sizeof( temp ) ) clear( ios::failbit ); return temp; } } uint32 ipstream::readWord32() { if( !good() ) return 0; else { uint32 temp; if( bp->sgetn( (char *)&temp, sizeof( temp ) ) != sizeof( temp ) ) clear( ios::failbit ); return temp; } } uint32 ipstream::readStringLength() { uint32 len; if( getVersion() > 0x0100 ) { len = readWord32(); } else { len = readByte(); if( len == oldNullStringLen ) len = nullStringLen; } return len; } char *ipstream::readString() { if( !good() ) return 0; else { uint32 len = readStringLength(); if( len == nullStringLen ) return 0; char *buf = new char[len+1]; if( buf == 0 ) return 0; readBytes( buf, len ); buf[len] = EOS; return buf; } } char *ipstream::readString( char *buf, unsigned maxLen ) { PRECONDITION( buf != 0 ); if( !good() ) return 0; else { uint32 len = readStringLength(); if( len == nullStringLen || len > maxLen-1 ) return 0; readBytes( buf, len ); buf[len] = EOS; return buf; } } char _BIDSFARDATA *ipstream::freadString() { if( !good() ) return 0; else { uint32 len = readStringLength(); if( len == nullStringLen ) return 0; char _BIDSFARDATA *buf = new _BIDSFARDATA char[len+1]; freadBytes(buf, len); buf[len] = EOS; return buf; } } char _BIDSFARDATA *ipstream::freadString( char _BIDSFARDATA *buf, unsigned maxLen ) { PRECONDITION(buf != 0 ); if( !good() ) return 0; else { uint32 len = readStringLength(); if( len == nullStringLen || len > maxLen-1 ) return 0; freadBytes( buf, len); buf[len] = EOS; return buf; } } void ipstream::readVersion() { if( !good() ) version = 0; else { int res = bp->sgetc(); if( res == EOF ) { clear( ios::eofbit ); version = 0; return; } if( res != versionIndicator ) version = 0; else { bp->sbumpc(); version = readWord32(); } } } TStreamableBase _FAR *ipstream::readObject( TStreamableBase _FAR *&mem, ModuleId mid ) { if( good() ) { const ObjectBuilder *pc = readPrefix( mid ); if( pc == 0 ) mem = 0; else { readData( pc, mem ); readSuffix(); } } return mem; } const ObjectBuilder *ipstream::readPrefix( ModuleId mid ) { char ch = readByte(); if( ch != '[' ) { clear( ios::failbit ); return 0; } char name[128]; name[0] = EOS; readString( name, sizeof name ); if( name[0] == EOS ) { clear( ios::failbit ); return 0; } TRACEX(Objstrm,0,"Reading " << name); const ObjectBuilder *res = types->Lookup( mid, name ); WARNX(Objstrm,res==0,0,"Unrecognized class identifier: " << name); if( res == 0 ) { clear( ios::failbit ); return 0; } return res; } void ipstream::readData( const ObjectBuilder *c, TStreamableBase _FAR *&mem ) { TStreamer *strmr = c->Builder(mem); mem = strmr->GetObject(); // register the address registerObject( mem ); uint32 classVer = 0; if( getVersion() > 0 ) classVer = readWord32(); strmr->Read( *this, classVer ); delete strmr; } void ipstream::readSuffix() { if( !good() ) return; char ch = readByte(); if( ch != ']' ) clear( ios::failbit ); } TStreamableBase _FAR *ipstream::readObjectPointer( TStreamableBase _FAR *&mem, ModuleId mid ) { if( !good() ) return 0; char ch = readByte(); switch( ch ) { case pstream::ptNull: mem = 0; break; case pstream::ptIndexed: { P_id_type index = P_id_type(readWord()); mem = find( index ); CHECK( mem != 0 ); break; } case pstream::ptObject: { const ObjectBuilder *pc = readPrefix( mid ); readData( pc, mem ); readSuffix(); break; } default: clear( ios::failbit ); break; } return mem; } opstream::opstream() { objs = new TPWrittenObjects; if( bp != 0 ) writeVersion(); } opstream::opstream( streambuf * sb ) { objs = new TPWrittenObjects; pstream::init( sb ); writeVersion(); } streampos opstream::tellp() { streampos res; if( !good() ) res = streampos(EOF); else { res = bp->seekoff( 0, ios::cur, ios::out ); if( res == streampos(EOF) ) clear( ios::failbit ); } return res; } opstream& opstream::seekp( streampos pos ) { if( good() ) { objs->RemoveAll(); if( bp->seekoff( pos, ios::beg, ios::out ) == streampos(EOF) ) clear( ios::failbit ); } return *this; } opstream& opstream::seekp( streamoff pos, ios::seek_dir dir ) { if( good() ) { objs->RemoveAll(); if( bp->seekoff( pos, dir, ios::out ) == streampos(EOF) ) clear( ios::failbit ); } return *this; } void opstream::writeVersion() { if( good() ) { writeByte( versionIndicator ); writeWord32( streamVersion ); } } opstream& opstream::flush() { if( bp->sync() == EOF ) clear( ios::badbit ); return *this; } void opstream::writeByte( uint8 ch ) { if( good() ) { if( bp->sputc( ch ) == EOF ) clear( ios::failbit ); } } void opstream::writeBytes( const void *data, size_t sz ) { PRECONDITION( data != 0 ); if( good() && sz > 0 ) { if( bp->sputn( (char *)data, sz ) != sz ) clear( ios::failbit ); } } void opstream::writeWord16( uint16 word16 ) { if( good() ) { if( bp->sputn( (char *)&word16, sizeof(word16) ) != sizeof(word16) ) clear( ios::failbit ); } } void opstream::writeWord32( uint32 word32 ) { if( good() ) { if( bp->sputn( (char *)&word32, sizeof(word32) ) != sizeof(word32) ) clear( ios::failbit ); } } void opstream::fwriteBytes( const void _BIDSFARDATA *data, size_t sz ) { PRECONDITION( data != 0 ); if( good() && sz > 0 ) { char *buf = new char[sz]; _fmemcpy( buf, data, sz ); if( bp->sputn( (char *)buf, sz ) != sz ) clear( ios::failbit ); delete buf; } } void opstream::writeString( const char *str ) { if( !good() ) return; if( str == 0 ) { writeWord32( nullStringLen ); return; } size_t len = strlen( str ); writeWord32( len ); writeBytes( str, len ); } void opstream::fwriteString( const char _BIDSFARDATA * str ) { if( !good() ) return; if( str == 0 ) { writeWord32( nullStringLen ); return; } size_t len = _fstrlen( str ); writeWord32( len ); fwriteBytes(str, len); } #pragma warn -par void opstream::writeObject( const TStreamableBase _FAR *mem, int isPtr, ModuleId mid ) { WARNX(Objstrm, !isPtr && findObject( CONST_CAST(TStreamableBase *,mem) ), 0, "Pointer written before object: " \ << _TYPENAME(mem) << '(' << (void _FAR *)mem << ')' ); if( good() ) { writePrefix( mem ); writeData( mem, mid ); writeSuffix( mem ); } } #pragma warn +par void opstream::writeObjectPointer( const TStreamableBase *t, ModuleId mid ) { if( good() ) { P_id_type index; if( t == 0 ) writeByte( pstream::ptNull ); else if( (index = findObject( CONST_CAST(TStreamableBase *,t) )) != 0 ) { writeByte( pstream::ptIndexed ); writeWord( index ); } else { writeByte( pstream::ptObject ); writeObject( t, 1, mid ); } } } void opstream::writePrefix( const TStreamableBase *t ) { if( good() ) { writeByte( '[' ); writeString( _TYPENAME(t) ); } } void opstream::writeData( const TStreamableBase *t, ModuleId mid ) { if( good() ) { registerObject( CONST_CAST(TStreamableBase *,t) ); const ObjectBuilder *res = types->Lookup( mid, _TYPENAME(t) ); CHECKX(res,_TYPENAME(t)); TStreamer *strmr = res->Builder(CONST_CAST(TStreamableBase *,t)); writeWord32( strmr->ClassVersion() ); strmr->Write( *this ); delete strmr; } } void fpbase::open( const char *b, int m, int prot ) { if( buf.is_open() ) clear(ios::failbit); // fail - already open else if( buf.open(b, m, prot) ) clear(ios::goodbit); // successful open else clear(ios::badbit); // open failed } void fpbase::attach( int f ) { if( buf.is_open() ) clear(ios::failbit); else if( buf.attach(f) ) clear(ios::goodbit); else clear(ios::badbit); } void fpbase::close() { if( buf.close() ) clear(ios::goodbit); else clear(ios::failbit); } void fpbase::setbuf(char* b, int len) { if( buf.setbuf(b, len) ) clear(ios::goodbit); else clear(ios::failbit); } // // These operators are not friends of string, so // they must use only the public interface. // opstream _BIDSFAR& _BIDSENTRY _BIDSFUNC operator << ( opstream _BIDSFAR& os, const string _BIDSFAR& str ) { os.writeString( str.c_str() ); return os; } ipstream _BIDSFAR& _BIDSENTRY _BIDSFUNC operator >> ( ipstream _BIDSFAR& is, string _BIDSFAR& str ) { if( is.good() ) { uint32 len = is.readStringLength(); if( len == nullStringLen ) str = ""; else { char *temp = new char[len+1]; is.readBytes( temp, len ); temp[len] = EOS; str = temp; delete [] temp; } } return is; }