#ifndef OSGINTROSPECTION_READERWRITER_ #define OSGINTROSPECTION_READERWRITER_ #include #include #include #include #include #include #include #include #include namespace osgIntrospection { /// This is the base class for reader/writer objects. A ReaderWriter's /// purpose is to provide the means for writing the content of a Value /// object to a stream and for reading it back. Descendants can either /// be specialized for just one data type or they can handle several /// types, that's up to the implementor. A derived class is not required /// to support all streaming operations (text write, text read, bin write /// and bin read), it can implement just some of them, although full /// support is strongly encouraged. class ReaderWriter { public: class Options { public: Options(): fno_(false) {} virtual ~Options() {} bool getForceNumericOutput() const { return fno_; } void setForceNumericOutput(bool fno) { fno_ = fno; } private: bool fno_; }; /// Writes a textual representation of the value's content to a stream. virtual std::ostream &writeTextValue(std::ostream &, const Value &v, const Options* = 0) const { throw StreamingNotSupportedException(StreamingNotSupportedException::TEXT_WRITE, v.getType().getStdTypeInfo()); } /// Reads a textual representation of the value's content from a stream. virtual std::istream &readTextValue(std::istream &, Value &v, const Options* = 0) const { throw StreamingNotSupportedException(StreamingNotSupportedException::TEXT_READ, v.getType().getStdTypeInfo()); } /// Writes a binary representation of the value's content to a stream. virtual std::ostream &writeBinaryValue(std::ostream &, const Value &v, const Options* = 0) const { throw StreamingNotSupportedException(StreamingNotSupportedException::BINARY_WRITE, v.getType().getStdTypeInfo()); } /// Reads a binary representation of the value's content from a stream. virtual std::istream &readBinaryValue(std::istream &, Value &v, const Options* = 0) const { throw StreamingNotSupportedException(StreamingNotSupportedException::BINARY_READ, v.getType().getStdTypeInfo()); } /// Virtual destructor. virtual ~ReaderWriter() {} }; /// This class template provides basic default streaming capabilities /// for all types that define streaming operators (<< and >>). Most of /// the standard types are able to be read and written this way, so the /// StdReaderWriter template can be a convenient default for several /// types. The binary representation is a raw copy of the memory content. /// /// TO-DO: improve binary streaming and avoid arch dependency. /// template class StdReaderWriter: public ReaderWriter { public: virtual std::ostream &writeTextValue(std::ostream &os, const Value &v, const Options * = 0) const { return (os << variant_cast(v)); } virtual std::istream &readTextValue(std::istream &is, Value &v, const Options * = 0) const { if (v.isEmpty()) v = Value(T()); return (is >> variant_cast(v)); } virtual std::ostream &writeBinaryValue(std::ostream &os, const Value &v, const Options * = 0) const { return os.write(reinterpret_cast(extract_raw_data(v)), sizeof(T)); } virtual std::istream &readBinaryValue(std::istream &is, Value &v, const Options * = 0) const { if (v.isEmpty()) v = Value(T()); return is.read(reinterpret_cast(extract_raw_data(v)), sizeof(T)); } }; /// This ReaderWriter can be used to read and write enumeration values. /// The textual representation will be the enum label, if found, or the /// numerical value. The binary representation doesn't take label names /// into account. template class EnumReaderWriter: public ReaderWriter { virtual std::ostream &writeTextValue(std::ostream &os, const Value &v, const Options *options = 0) const { int numeric = static_cast(variant_cast(v)); if (!options || !options->getForceNumericOutput()) { const Type &type = v.getType(); const EnumLabelMap &elm = type.getEnumLabels(); EnumLabelMap::const_iterator i = elm.find(numeric); if (i != elm.end()) { os << i->second; return os; } else { std::vector labels; // it could be a bitmask for (EnumLabelMap::const_iterator i=elm.begin(); i!=elm.end(); ++i) { if (i->first != 0 && ((i->first & numeric) == i->first)) { numeric ^= i->first; labels.push_back(i->second); } } // check whether all bits were discovered if (numeric == 0) { for (std::vector::const_iterator i=labels.begin(); i!=labels.end(); ++i) { os << *i; if ((i+1) != labels.end()) os << " | "; } return os; } } } return os << numeric; } virtual std::istream &readTextValue(std::istream &is, Value &v, const Options * = 0) const { if (v.isEmpty()) v = Value(T()); int i; if (is >> i) { variant_cast(v) = static_cast(i); return is; } is.clear(); std::string s; if (is >> s) { const Type &type = v.getType(); const EnumLabelMap &elm = type.getEnumLabels(); for (EnumLabelMap::const_iterator i=elm.begin(); i!=elm.end(); ++i) { if (i->second.compare(s) == 0) { variant_cast(v) = static_cast(i->first); return is; } } } return is; } virtual std::ostream &writeBinaryValue(std::ostream &os, const Value &v, const Options * = 0) const { return os.write(reinterpret_cast(extract_raw_data(v)), sizeof(T)); } virtual std::istream &readBinaryValue(std::istream &is, Value &v, const Options * = 0) const { if (v.isEmpty()) v = Value(T()); return is.read(reinterpret_cast(extract_raw_data(v)), sizeof(T)); } }; /// This is a ReaderWriter class that can be used to read and write /// pointer values. Note: template parameter T must be a pointer! template class PtrReaderWriter: public ReaderWriter { public: virtual std::ostream &writeTextValue(std::ostream &os, const Value &v, const Options* = 0) const { return (os << (void*)variant_cast(v)); } virtual std::istream &readTextValue(std::istream &is, Value &v, const Options* = 0) const { void *ptr; is >> ptr; v = Value(T(ptr)); return is; } virtual std::ostream &writeBinaryValue(std::ostream &os, const Value &v, const Options* = 0) const { return os.write(reinterpret_cast(extract_raw_data(v)), sizeof(T)); } virtual std::istream &readBinaryValue(std::istream &is, Value &v, const Options* = 0) const { T ptr; is.read(reinterpret_cast(&ptr), sizeof(T)); v = Value(ptr); return is; } }; } #endif