From b8a94a6d4e947539b53e1fabf5d7ad125c2f30e5 Mon Sep 17 00:00:00 2001 From: Robert Osfield Date: Tue, 9 Nov 2010 12:41:55 +0000 Subject: [PATCH] From Wang Rui, "I'd like to submit my latest modification of the serialization IO functionalities. It includes two main parts: a version checking macro for handling backward-compatiblity since 3.0, and enhencement of current schema mechanism. I also change the option handling process to use getPluginStringData(), and add new USE_SERIALIZER_WRAPPER macro in the Registry header to allow for static-link usage as well. The enhencement of schema machanism just tells the type of each serializer while outputting them, such as: osg::Group = Children:1 The meaning of the number can be found in the osgDB/Serializer header, BaseSerializer::Type enum. It may help 3rdparty utilities understand the structure of the wrapper and do some reflection work in the future. The new macro UPDATE_TO_VERSION can help indicate the InputStream (no affect on the writer) that a serializer is added/removed since certain OSG version. An example wrapper file is also attached. The Geode_modified.cpp is based on the serializers/osg/Geode.cpp file (hey, don't merge it :-), but assumes that a new user serializer 'Test' is added since version 65 (that is, the OSG_SOVERSION): REGISTER_OBJECT_WRAPPER( Geode, ... ) { ADD_USER_SERIALIZER( Drawables ); // origin ones UPDATE_TO_VERSION( 65 ) { ADD_USER_SERIALIZER( Test ); // a serializer added from version 65 } } All kinds of ADD_... macros following UPDATE_TO_VERSION will automatically apply the updated version. The braces here are only for typesetting! While reading an osgt/osgb/osgx file, OSG will now check if the file version (recorded as the writer's soversion, instead of previous meaningless "#Version 2") is equal or greater than Test's version, and try reading it, or just ignore it if file version is lesser. And we also have the REMOVE_SERIALIZER macro will mark a named serializer as removed in some version, with which all files generated by further versions will just ignore it: UPDATE_TO_VERSION( 70 ) { REMOVE_SERIALIZER( Test ); } This means that from version 70, the serializer Test is removed (but not actually erased from the list) and should not be read anymore. If the read file version is less than 70 (and equal or greater than 65), Test will still be handled when reading; otherwise it will be ignored to keep compatiblity on different OSG versions. " --- include/osgDB/InputStream | 2 + include/osgDB/ObjectWrapper | 25 ++++++++---- include/osgDB/Registry | 8 ++++ include/osgDB/Serializer | 78 +++++++++++++++++++++++-------------- src/osgDB/InputStream.cpp | 71 +++++++++++++++------------------ src/osgDB/ObjectWrapper.cpp | 73 ++++++++++++++++++++++++++++++++-- src/osgDB/OutputStream.cpp | 78 +++++++++++++++---------------------- 7 files changed, 207 insertions(+), 128 deletions(-) diff --git a/include/osgDB/InputStream b/include/osgDB/InputStream index 6736fe809..df7cfc327 100644 --- a/include/osgDB/InputStream +++ b/include/osgDB/InputStream @@ -69,6 +69,7 @@ public: virtual ~InputStream(); bool isBinary() const { return _in->isBinary(); } + int getFileVersion() const { return _fileVersion; } const osgDB::Options* getOptions() const { return _options.get(); } // Serialization related functions @@ -159,6 +160,7 @@ protected: ArrayMap _arrayMap; IdentifierMap _identifierMap; + int _fileVersion; int _byteSwap; bool _useSchemaData; bool _forceReadingImage; diff --git a/include/osgDB/ObjectWrapper b/include/osgDB/ObjectWrapper index 0e8a94b6a..27dc011dd 100644 --- a/include/osgDB/ObjectWrapper +++ b/include/osgDB/ObjectWrapper @@ -50,33 +50,39 @@ public: ObjectWrapper( osg::Object* proto, const std::string& name, const std::string& associates ); + void setUpdatedVersion( int ver ) { _version = ver; } const osg::Object* getProto() const { return _proto.get(); } const std::string& getName() const { return _name; } const StringList& getAssociates() const { return _associates; } - - void addSerializer( BaseSerializer* s ) { _serializers.push_back(s); } + + void addSerializer( BaseSerializer* s, BaseSerializer::Type t=BaseSerializer::RW_UNDEFINED ) + { s->_version = _version; _serializers.push_back(s); _typeList.push_back(static_cast(t)); } + + void markSerializerAsRemoved( const std::string& name ); + BaseSerializer* getSerializer( const std::string& name ); void addFinishedObjectReadCallback ( FinishedObjectReadCallback* forc) { _finishedObjectReadCallbacks.push_back(forc); } - bool read( InputStream&, osg::Object& ); bool write( OutputStream&, const osg::Object& ); - - bool readSchema( const StringList& properties ); - void writeSchema( StringList& properties ); + + bool readSchema( const StringList& properties, const std::vector& types ); + void writeSchema( StringList& properties, std::vector& types ); void resetSchema() { if ( _backupSerializers.size()>0 ) _serializers = _backupSerializers; } protected: - ObjectWrapper() {} + ObjectWrapper() : _version(0) {} virtual ~ObjectWrapper() {} - + osg::ref_ptr _proto; std::string _name; StringList _associates; SerializerList _serializers; SerializerList _backupSerializers; + std::vector _typeList; FinishedObjectReadCallbackList _finishedObjectReadCallbacks; + int _version; // Last updated version of the wrapper }; class Registry; @@ -143,6 +149,7 @@ protected: }; #define REGISTER_OBJECT_WRAPPER(NAME, PROTO, CLASS, ASSOCIATES) \ + extern "C" void wrapper_serializer_##NAME(void) {} \ extern void wrapper_propfunc_##NAME(osgDB::ObjectWrapper*); \ static osgDB::RegisterWrapperProxy wrapper_proxy_##NAME( \ PROTO, #CLASS, ASSOCIATES, &wrapper_propfunc_##NAME); \ @@ -150,6 +157,7 @@ protected: void wrapper_propfunc_##NAME(osgDB::ObjectWrapper* wrapper) #define REGISTER_OBJECT_WRAPPER2(NAME, PROTO, CLASS, CLASSNAME, ASSOCIATES) \ + extern "C" void wrapper_serializer_##NAME(void) {} \ extern void wrapper_propfunc_##NAME(osgDB::ObjectWrapper*); \ static osgDB::RegisterWrapperProxy wrapper_proxy_##NAME( \ PROTO, CLASSNAME, ASSOCIATES, &wrapper_propfunc_##NAME); \ @@ -167,6 +175,7 @@ protected: }; #define REGISTER_COMPRESSOR(NAME, CLASS) \ + extern "C" void wrapper_compressor_##CLASS(void) {} \ static osgDB::RegisterCompressorProxy compressor_proxy_##CLASS(NAME, new CLASS); } diff --git a/include/osgDB/Registry b/include/osgDB/Registry index 0c6e1801d..1306a0994 100644 --- a/include/osgDB/Registry +++ b/include/osgDB/Registry @@ -637,6 +637,14 @@ struct PluginFunctionProxy extern "C" void dotosgwrapper_##classname(void); \ static osgDB::PluginFunctionProxy proxy_dotosgwrapper_##classname(dotosgwrapper_##classname); +#define USE_SERIALIZER_WRAPPER(classname) \ + extern "C" void wrapper_serializer_##classname(void); \ + static osgDB::PluginFunctionProxy proxy_serializer_##classname(wrapper_serializer_##classname); + +#define USE_COMPRESSOR_WRAPPER(classname) \ + extern "C" void wrapper_serializer_##classname(void); \ + static osgDB::PluginFunctionProxy proxy_compressor_##classname(wrapper_compressor_##classname); + #define REGISTER_OSGPLUGIN(ext, classname) \ extern "C" void osgdb_##ext(void) {} \ static osgDB::RegisterReaderWriterProxy g_proxy_##classname; diff --git a/include/osgDB/Serializer b/include/osgDB/Serializer index bf28e6796..d8d377487 100644 --- a/include/osgDB/Serializer +++ b/include/osgDB/Serializer @@ -116,11 +116,23 @@ public: class BaseSerializer : public osg::Referenced { + friend class ObjectWrapper; public: - BaseSerializer() {} + enum Type + { + RW_UNDEFINED = 0, RW_USER, RW_OBJECT, RW_IMAGE, RW_LIST, + RW_BOOL, RW_SHORT, RW_USHORT, RW_INT, RW_UINT, RW_FLOAT, RW_DOUBLE, + RW_VEC2F, RW_VEC2D, RW_VEC3F, RW_VEC3D, RW_VEC4F, RW_VEC4D, RW_QUAT, RW_PLANE, + RW_MATRIXF, RW_MATRIXD, RW_MATRIX, RW_GLENUM, RW_STRING, RW_ENUM + }; + + BaseSerializer() : _version(0) {} virtual bool read( InputStream&, osg::Object& ) = 0; virtual bool write( OutputStream&, const osg::Object& ) = 0; virtual const std::string& getName() const = 0; + +protected: + int _version; // Library version when the serializer is added, or removed (neg value) }; template @@ -767,117 +779,117 @@ public: #define ADD_USER_SERIALIZER(PROP) \ wrapper->addSerializer( new osgDB::UserSerializer( \ - #PROP, &check##PROP, &read##PROP, &write##PROP) ) + #PROP, &check##PROP, &read##PROP, &write##PROP), osgDB::BaseSerializer::RW_USER ) #define ADD_BOOL_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, bool >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_BOOL ) #define ADD_SHORT_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, short >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_SHORT ) #define ADD_USHORT_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, unsigned short >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_USHORT ) #define ADD_HEXSHORT_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, unsigned short >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP, true) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP, true), osgDB::BaseSerializer::RW_USHORT ) #define ADD_INT_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, int >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_INT ) #define ADD_UINT_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, unsigned int >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_UINT ) #define ADD_GLINT_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, GLint >( \ - #PROP, ((int)(DEF)), &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, ((int)(DEF)), &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_INT ) #define ADD_HEXINT_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, unsigned int >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP, true) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP, true), osgDB::BaseSerializer::RW_UINT ) #define ADD_FLOAT_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, float >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_FLOAT ) #define ADD_DOUBLE_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByValSerializer< MyClass, double >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_DOUBLE ) #define ADD_VEC2F_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Vec2f >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_VEC2F ) #define ADD_VEC2D_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Vec2d >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_VEC2D ) #define ADD_VEC2_SERIALIZER(PROP, DEF) ADD_VEC2F_SERIALIZER(PROP, DEF) #define ADD_VEC3F_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Vec3f >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_VEC3F ) #define ADD_VEC3D_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Vec3d >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_VEC3D ) #define ADD_VEC3_SERIALIZER(PROP, DEF) ADD_VEC3F_SERIALIZER(PROP, DEF) #define ADD_VEC4F_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Vec4f >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_VEC4F ) #define ADD_VEC4D_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Vec4d >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_VEC4D ) #define ADD_VEC4_SERIALIZER(PROP, DEF) ADD_VEC4F_SERIALIZER(PROP, DEF) #define ADD_QUAT_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Quat >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_QUAT ) #define ADD_PLANE_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Plane >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_PLANE ) #define ADD_MATRIXF_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Matrixf >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_MATRIXF ) #define ADD_MATRIXD_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::PropByRefSerializer< MyClass, osg::Matrixd >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_MATRIXD ) #define ADD_MATRIX_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::MatrixSerializer< MyClass >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_MATRIX ) #define ADD_GLENUM_SERIALIZER(PROP, TYPE, DEF) \ wrapper->addSerializer( new osgDB::GLenumSerializer< MyClass, TYPE >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_GLENUM ) #define ADD_STRING_SERIALIZER(PROP, DEF) \ wrapper->addSerializer( new osgDB::StringSerializer< MyClass >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_STRING ) #define ADD_OBJECT_SERIALIZER(PROP, TYPE, DEF) \ wrapper->addSerializer( new osgDB::ObjectSerializer< MyClass, TYPE >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_OBJECT ) #define ADD_IMAGE_SERIALIZER(PROP, TYPE, DEF) \ wrapper->addSerializer( new osgDB::ImageSerializer< MyClass, TYPE >( \ - #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, DEF, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_IMAGE ) #define ADD_LIST_SERIALIZER(PROP, TYPE) \ wrapper->addSerializer( new osgDB::ListSerializer< MyClass, TYPE >( \ - #PROP, &MyClass::get##PROP, &MyClass::set##PROP) ) + #PROP, &MyClass::get##PROP, &MyClass::set##PROP), osgDB::BaseSerializer::RW_LIST ) #define BEGIN_ENUM_SERIALIZER(PROP, DEF) \ { typedef osgDB::EnumSerializer MySerializer; \ @@ -899,7 +911,6 @@ public: osg::ref_ptr serializer = new MySerializer( \ #PROP, PROPERTIES_CLASS::DEF, &MyClass::get##PROP, &MyClass::set##PROP) - #define ADD_ENUM_VALUE(VALUE) \ serializer->add(#VALUE, MyClass::VALUE) @@ -907,7 +918,14 @@ public: serializer->add(#VALUE, CLASS::VALUE) #define END_ENUM_SERIALIZER() \ - wrapper->addSerializer(serializer.get()); } + wrapper->addSerializer(serializer.get(), osgDB::BaseSerializer::RW_ENUM); } + +// VERSION CONTROL OPERATORS +#define UPDATE_TO_VERSION(VER) \ + wrapper->setUpdatedVersion( (VER) ); + +#define REMOVE_SERIALIZER(PROP) \ + wrapper->markSerializerAsRemoved( #PROP ); } diff --git a/src/osgDB/InputStream.cpp b/src/osgDB/InputStream.cpp index 32e81563b..04692738f 100644 --- a/src/osgDB/InputStream.cpp +++ b/src/osgDB/InputStream.cpp @@ -24,46 +24,26 @@ using namespace osgDB; static std::string s_lastSchema; InputStream::InputStream( const osgDB::Options* options ) - : _byteSwap(0), _useSchemaData(false), _forceReadingImage(false), _dataDecompress(0) + : _fileVersion(0), _byteSwap(0), _useSchemaData(false), _forceReadingImage(false), _dataDecompress(0) { if ( !options ) return; _options = options; std::string schema; - StringList optionList; - split( options->getOptionString(), optionList ); - for ( StringList::iterator itr=optionList.begin(); itr!=optionList.end(); ++itr ) + if ( options->getPluginStringData("ForceReadingImage")=="true" ) + _forceReadingImage = true; + if ( !options->getPluginStringData("SchemaFile").empty() ) { - const std::string& option = *itr; - if ( option=="Ascii" ) + schema = options->getPluginStringData("SchemaFile"); + if ( s_lastSchema!=schema ) { - // Omit this - } - else if ( option=="ForceReadingImage" ) - { - _forceReadingImage = true; - } - else - { - StringList keyAndValues; - split( option, keyAndValues, '=' ); - if ( keyAndValues.size()<2 ) continue; - - if ( keyAndValues[0]=="SchemaFile" ) - { - schema = keyAndValues[1]; - if ( s_lastSchema!=schema ) - { - osgDB::ifstream schemaStream( schema.c_str(), std::ios::in ); - if ( !schemaStream.fail() ) readSchema( schemaStream ); - schemaStream.close(); - s_lastSchema = schema; - } - } - else - OSG_WARN << "InputStream: Unknown option " << option << std::endl; + osgDB::ifstream schemaStream( schema.c_str(), std::ios::in ); + if ( !schemaStream.fail() ) readSchema( schemaStream ); + schemaStream.close(); + s_lastSchema = schema; } } + if ( schema.empty() ) { resetSchema(); @@ -733,13 +713,8 @@ InputStream::ReadType InputStream::start( InputIterator* inIterator ) *this >> PROPERTY("#Generator") >> osgName >> osgVersion; } - // Check file version - if ( version!=PLUGIN_VERSION ) - { - OSG_WARN << "InputStream: Input data version " << version - << " may be incompatible with current reader version " - << PLUGIN_VERSION << std::endl; - } + // Record file version for back-compatibility checking of wrappers + _fileVersion = version; _fields.pop_back(); return type; } @@ -793,9 +768,25 @@ void InputStream::setWrapperSchema( const std::string& name, const std::string& return; } - StringList schema; + StringList schema, methods, keyAndValue; + std::vector types; split( properties, schema ); - wrapper->readSchema( schema ); + for ( StringList::iterator itr=schema.begin(); itr!=schema.end(); ++itr ) + { + split( *itr, keyAndValue, ':' ); + if ( keyAndValue.size()>1 ) + { + methods.push_back( keyAndValue.front() ); + types.push_back( atoi(keyAndValue.back().c_str()) ); + } + else + { + methods.push_back( *itr ); + types.push_back( 0 ); + } + keyAndValue.clear(); + } + wrapper->readSchema( methods, types ); } void InputStream::resetSchema() diff --git a/src/osgDB/ObjectWrapper.cpp b/src/osgDB/ObjectWrapper.cpp index 39cb75096..ddf45cfba 100644 --- a/src/osgDB/ObjectWrapper.cpp +++ b/src/osgDB/ObjectWrapper.cpp @@ -86,17 +86,77 @@ void osgDB::split( const std::string& src, StringList& list, char separator ) ObjectWrapper::ObjectWrapper( osg::Object* proto, const std::string& name, const std::string& associates ) : osg::Referenced(), - _proto(proto), _name(name) + _proto(proto), _name(name), _version(0) { split( associates, _associates ); } +void ObjectWrapper::markSerializerAsRemoved( const std::string& name ) +{ + for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr ) + { + // When a serializer is marked as 'removed', it means that this serializer won't be used any more + // from specified OSG version (by macro UPDATE_TO_VERSION). The read() functions of higher versions + // will thus ignore it according to the sign and value of the _version variable. + if ( (*itr)->getName()==name ) + (*itr)->_version = -_version; + } +} + +BaseSerializer* ObjectWrapper::getSerializer( const std::string& name ) +{ + for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr ) + { + if ( (*itr)->getName()==name ) + return *itr; + } + + for ( StringList::const_iterator itr=_associates.begin(); itr!=_associates.end(); ++itr ) + { + const std::string& assocName = *itr; + ObjectWrapper* assocWrapper = Registry::instance()->getObjectWrapperManager()->findWrapper(assocName); + if ( !assocWrapper ) + { + osg::notify(osg::WARN) << "ObjectWrapper::getSerializer(): Unsupported associated class " + << assocName << std::endl; + continue; + } + + for ( SerializerList::iterator aitr=assocWrapper->_serializers.begin(); + aitr!=assocWrapper->_serializers.end(); ++aitr ) + { + if ( (*aitr)->getName()==name ) + return *aitr; + } + } + return NULL; +} + bool ObjectWrapper::read( InputStream& is, osg::Object& obj ) { bool readOK = true; for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr ) { + int serializerVersion = (*itr)->_version; + if ( serializerVersion!=0 ) + { + if ( serializerVersion<0 ) + { + serializerVersion = -serializerVersion; + + // The serializer is removed from a specified version, + // and the file in reading is at the same or higher version, ignore it. + if ( is.getFileVersion()>=serializerVersion ) continue; + } + else + { + // The serializer is added at a specified version, + // but the file in reading is at a lower version, ignore it. + if ( is.getFileVersion()read(is, obj) ) continue; OSG_WARN << "ObjectWrapper::read(): Error reading property " << _name << "::" << (*itr)->getName() << std::endl; @@ -127,8 +187,9 @@ bool ObjectWrapper::write( OutputStream& os, const osg::Object& obj ) return writeOK; } -bool ObjectWrapper::readSchema( const StringList& properties ) +bool ObjectWrapper::readSchema( const StringList& properties, const std::vector& ) { + // FIXME: At present, I didn't do anything to determine serializers from their types... if ( !_backupSerializers.size() ) _backupSerializers = _serializers; _serializers.clear(); @@ -169,13 +230,19 @@ bool ObjectWrapper::readSchema( const StringList& properties ) return size==_serializers.size(); } -void ObjectWrapper::writeSchema( StringList& properties ) +void ObjectWrapper::writeSchema( StringList& properties, std::vector& types ) { for ( SerializerList::iterator itr=_serializers.begin(); itr!=_serializers.end(); ++itr ) { properties.push_back( (*itr)->getName() ); } + + for ( std::vector::iterator itr=_typeList.begin(); + itr!=_typeList.end(); ++itr ) + { + types.push_back( (*itr) ); + } } //////////////////////////////////////////////////////////////////////////////////////////////////////// diff --git a/src/osgDB/OutputStream.cpp b/src/osgDB/OutputStream.cpp index 2db0cd2a1..85cd38a4d 100644 --- a/src/osgDB/OutputStream.cpp +++ b/src/osgDB/OutputStream.cpp @@ -18,6 +18,7 @@ #include #include #include +#include using namespace osgDB; @@ -27,39 +28,19 @@ OutputStream::OutputStream( const osgDB::Options* options ) if ( !options ) return; _options = options; - StringList optionList; - split( options->getOptionString(), optionList ); - for ( StringList::iterator itr=optionList.begin(); itr!=optionList.end(); ++itr ) + if ( options->getPluginStringData("SchemaData")=="true" ) + _useSchemaData = true; + if ( !options->getPluginStringData("SchemaFile").empty() ) + _schemaName = options->getPluginStringData("SchemaFile"); + if ( !options->getPluginStringData("Compressor").empty() ) + _compressorName = options->getPluginStringData("Compressor"); + if ( !options->getPluginStringData("WriteImageHint").empty() ) { - const std::string& option = *itr; - if ( option=="Ascii" ) - { - // Omit this - } - else if ( option=="SchemaData" ) - { - _useSchemaData = true; - } - else - { - StringList keyAndValues; - split( option, keyAndValues, '=' ); - if ( keyAndValues.size()<2 ) continue; - - if ( keyAndValues[0]=="SchemaFile" ) - _schemaName = keyAndValues[1]; - else if ( keyAndValues[0]=="Compressor" ) - _compressorName = keyAndValues[1]; - else if ( keyAndValues[0]=="WriteImageHint" ) - { - if ( keyAndValues[1]=="IncludeData" ) _writeImageHint = WRITE_INLINE_DATA; - else if ( keyAndValues[1]=="IncludeFile" ) _writeImageHint = WRITE_INLINE_FILE; - else if ( keyAndValues[1]=="UseExternal" ) _writeImageHint = WRITE_USE_EXTERNAL; - else if ( keyAndValues[1]=="WriteOut" ) _writeImageHint = WRITE_EXTERNAL_FILE; - } - else - OSG_WARN << "OutputStream: Unknown option " << option << std::endl; - } + std::string hintString = options->getPluginStringData("WriteImageHint"); + if ( hintString=="IncludeData" ) _writeImageHint = WRITE_INLINE_DATA; + else if ( hintString=="IncludeFile" ) _writeImageHint = WRITE_INLINE_FILE; + else if ( hintString=="UseExternal" ) _writeImageHint = WRITE_USE_EXTERNAL; + else if ( hintString=="WriteOut" ) _writeImageHint = WRITE_EXTERNAL_FILE; } } @@ -490,16 +471,18 @@ void OutputStream::writeObjectFields( const osg::Object* obj ) if ( _inbuiltSchemaMap.find(assocName)==_inbuiltSchemaMap.end() ) { StringList properties; - assocWrapper->writeSchema( properties ); - if ( properties.size()>0 ) + std::vector types; + assocWrapper->writeSchema( properties, types ); + + unsigned int size = osg::minimum( properties.size(), types.size() ); + if ( size>0 ) { - std::string propertiesString; - for ( StringList::iterator sitr=properties.begin(); sitr!=properties.end(); ++sitr ) + std::stringstream propertiesStream; + for ( unsigned int i=0; ifirst << " ="; StringList properties; - wrapper->writeSchema( properties ); - if ( properties.size()>0 ) + std::vector types; + wrapper->writeSchema( properties, types ); + + std::string propertiesString; + unsigned int size = osg::minimum( properties.size(), types.size() ); + for ( unsigned int i=0; i