diff --git a/tscpp.cpp b/tscpp.cpp index ae0ca42ba41228635e932ffcac1f2893f4c2499b..a058fcb27562127d4ec9c592a460eca207eead3a 100644 --- a/tscpp.cpp +++ b/tscpp.cpp @@ -90,7 +90,7 @@ string peekTypeName(const void *buffer, int bufSize) { const char *buf=reinterpret_cast<const char*>(buffer); int nameSize=strnlen(buf,bufSize); - if(nameSize>=bufSize) return "<corrupted>"; + if(nameSize>=bufSize) return ""; return buf; } @@ -117,30 +117,31 @@ void OutputArchive::serializeImpl(const char *name, const void *data, int size) void InputArchive::unserializeImpl(const char *name, void *data, int size) { - auto pos=is.tellg(); + pos=is.tellg(); int nameSize=strlen(name); unique_ptr<char[]> unserializedName(new char[nameSize+1]); is.read(unserializedName.get(),nameSize+1); - if(is.eof()) - { - is.seekg(pos); - throw 1; //FIXME - } + if(is.eof()) errorImpl("eof"); if(memcmp(unserializedName.get(),name,nameSize+1)) - { - is.seekg(pos); - throw 2; //FIXME - } + errorImpl("wrong type found",true); //NOTE: we are writing on top of a constructed type without calling its //destructor. However, since it is trivially copyable, we at least aren't //overwriting pointers to allocated memory. is.read(reinterpret_cast<char*>(data),size); - if(is.eof()) - { + if(is.eof()) errorImpl("eof"); +} + +void InputArchive::errorImpl(const string& errorStr, bool printName) +{ + is.seekg(pos); + if(printName==false) throw TscppException(errorStr); + else { + string type; + getline(is,type,'\0'); is.seekg(pos); - throw 3; //FIXME + throw TscppException(errorStr,type); } } diff --git a/tscpp.h b/tscpp.h index d46b3489349e559b5434b1fce67e25989208f080..f3b9d67139fbc25d9cec03d770e86c6fdf6d55be 100644 --- a/tscpp.h +++ b/tscpp.h @@ -29,6 +29,7 @@ #include <type_traits> #include <functional> +#include <stdexcept> #include <ostream> #include <istream> #include <cstring> @@ -174,8 +175,8 @@ int unserializeUnknown(const TypePool& tp, const void *buffer, int bufSize); * \endcode * \param buffer pointer to buffer where the serialized type is * \param bufSize buffer size - * \return the serialized type name, or "<corrupted>" if the buffer does not - * contain a type name + * \return the serialized type name, or "" if the buffer does not contain a type + * name */ std::string peekTypeName(const void *buffer, int bufSize); @@ -249,18 +250,26 @@ public: * \internal */ void unserializeImpl(const char *name, void *data, int size); + + /** + * \internal + */ + void errorImpl(const std::string& errorStr, bool printName=false); private: InputArchive(const InputArchive&)=delete; InputArchive& operator=(const InputArchive&)=delete; std::istream& is; + std::streampos pos; }; /** * Unserialize a type * \param ia archive where the type has been serialized * \param t type to unserialize + * \throws TscppException if the type found in the stream is not the one + * expected, or if the stream eof is found */ template<typename T> InputArchive& operator>>(InputArchive& ia, T& t) @@ -272,4 +281,45 @@ InputArchive& operator>>(InputArchive& ia, T& t) return ia; } +/** + * Exception class thrown by the input archives + */ +class TscppException : public std::runtime_error +{ +public: + /** + * \internal + */ + TscppException(const std::string& what) : runtime_error(what) {} + + /** + * \internal + */ + TscppException(const std::string& what, const std::string& t) + : runtime_error(what), t(t) {} + + /** + * If the exception is thrown because an unknown/unexpected type has been + * found in the input stream, this member function allows to access the + * mangled type name. + * It is useful to print an error message with the name of the type in the + * stream + * \code + * InputArchive ia(is); + * Foo f; + * try { + * ia>>f; + * } catch(TscppException& ex) { + * if(ex.type().empty()==false) + * cerr<<"While unserializing Foo, "<<demangle(ex.type())<<" was found\n"; + * } + * \endcode + * \return the serialized type name, or "" if eof was found + */ + std::string type() const { return t; } + +private: + std::string t; +}; + } // namespace tscpp