diff --git a/src/misc/serialize.h b/src/misc/serialize.h index 7797be6..8d1fd29 100644 --- a/src/misc/serialize.h +++ b/src/misc/serialize.h @@ -164,6 +164,24 @@ namespace epics { namespace pvData { int byteOrder, std::vector& out); + /** + * @brief deserializeFromBuffer Deserialize into S from provided vector + * @param S A Serializeable object. The current contents will be replaced + * @param byteOrder Byte order to write (EPICS_ENDIAN_LITTLE or EPICS_ENDIAN_BIG) + * @param in The input buffer (byte order of this buffer is used) + * @throws std::logic_error if input buffer is too small. State of S is then undefined. + */ + void deserializeFromBuffer(Serializable *S, + ByteBuffer& in); + + inline void deserializeFromVector(Serializable *S, + int byteOrder, + const std::vector& in) + { + ByteBuffer B((char*)&in[0], in.size(), byteOrder); // we promise not the modify 'in' + deserializeFromBuffer(S, B); + } + /** * @brief Class for serializing bitSets. * diff --git a/src/misc/serializeHelper.cpp b/src/misc/serializeHelper.cpp index e51d592..a3994ee 100644 --- a/src/misc/serializeHelper.cpp +++ b/src/misc/serializeHelper.cpp @@ -215,3 +215,57 @@ namespace epics { } } } + +namespace { +struct FromString : public epics::pvData::DeserializableControl +{ + ByteBuffer &buf; + epics::pvData::FieldCreatePtr create; + + FromString(ByteBuffer& b) + :buf(b) + ,create(epics::pvData::getFieldCreate()) + {} + + virtual void ensureData(std::size_t size) + { + if(size>buf.getRemaining()) + throw std::logic_error("Incomplete buffer"); + } + + virtual void alignData(std::size_t alignment) + { + size_t pos = buf.getPosition(), k = alignment-1; + if(pos&k) { + std::size_t npad = alignment-(pos&k); + ensureData(npad); + buf.align(alignment); + } + } + + virtual bool directDeserialize( + ByteBuffer *existingBuffer, + char* deserializeTo, + std::size_t elementCount, + std::size_t elementSize) + { + return false; + } + virtual std::tr1::shared_ptr cachedDeserialize( + ByteBuffer* buffer) + { + return create->deserialize(buffer, this); + } +}; +} + +namespace epics { + namespace pvData { + void deserializeFromBuffer(Serializable *S, + ByteBuffer& buf) + { + FromString F(buf); + S->deserialize(&buf, &F); + } + } +} diff --git a/testApp/misc/testSerialization.cpp b/testApp/misc/testSerialization.cpp index 7edc6f2..797a26f 100644 --- a/testApp/misc/testSerialization.cpp +++ b/testApp/misc/testSerialization.cpp @@ -834,11 +834,35 @@ void testToString(int byteOrder) printbytes(bytes.size(), &bytes[0]); } +void testFromString(int byteOrder) +{ + testDiag("testFromString(%d)", byteOrder); + + StructureConstPtr _type = getFieldCreate()->createFieldBuilder() + ->add("X", pvInt)->add("Y", pvString) + ->createStructure(); + + PVStructurePtr _data = getPVDataCreate()->createPVStructure(_type); + + if(byteOrder==EPICS_ENDIAN_LITTLE) { + ByteBuffer buf((char*)expected_le, NELEMENTS(expected_le)-1, byteOrder); + deserializeFromBuffer(_data.get(), buf); + } else if(byteOrder==EPICS_ENDIAN_BIG) { + ByteBuffer buf((char*)expected_be, NELEMENTS(expected_be)-1, byteOrder); + deserializeFromBuffer(_data.get(), buf); + } else { + throw std::logic_error("Unsupported mixed endian"); + } + + testOk1(_data->getSubFieldT("X")->get()==42); + testOk1(_data->getSubFieldT("Y")->get()=="testing"); +} + } // end namespace MAIN(testSerialization) { - testPlan(230); + testPlan(234); flusher = new SerializableControlImpl(); control = new DeserializableControlImpl(); @@ -862,6 +886,8 @@ MAIN(testSerialization) { testToString(EPICS_ENDIAN_BIG); testToString(EPICS_ENDIAN_LITTLE); + testFromString(EPICS_ENDIAN_BIG); + testFromString(EPICS_ENDIAN_LITTLE); delete buffer; delete control;