MRPT  1.9.9
CArchive.cpp
Go to the documentation of this file.
1 /* +------------------------------------------------------------------------+
2  | Mobile Robot Programming Toolkit (MRPT) |
3  | http://www.mrpt.org/ |
4  | |
5  | Copyright (c) 2005-2018, Individual contributors, see AUTHORS file |
6  | See: http://www.mrpt.org/Authors - All rights reserved. |
7  | Released under BSD License. See details in http://www.mrpt.org/License |
8  +------------------------------------------------------------------------+ */
9 
10 #include "serialization-precomp.h" // Precompiled headers
11 
12 #include <mrpt/core/exceptions.h>
13 #include <mrpt/core/byte_manip.h>
18 #include <cstring> // strlen()
19 
20 using namespace mrpt::serialization;
21 
23 
24 size_t CArchive::ReadBuffer(void* Buffer, size_t Count)
25 {
26  ASSERT_(Buffer != nullptr);
27  if (Count)
28  {
29  size_t actuallyRead = this->read(Buffer, Count);
30  if (!actuallyRead)
31  {
33  "(EOF?) Cannot read requested number of bytes from stream");
34  }
35  else
36  {
37  return actuallyRead;
38  }
39  }
40  else
41  return 0;
42 }
43 
44 /*---------------------------------------------------------------
45 WriteBuffer
46 Writes a block of bytes to the stream.
47 ---------------------------------------------------------------*/
48 void CArchive::WriteBuffer(const void* Buffer, size_t Count)
49 {
50  ASSERT_(Buffer != nullptr);
51  if (Count)
52  if (Count != this->write(Buffer, Count))
53  THROW_EXCEPTION("Cannot write bytes to stream!");
54 }
55 
56 /*---------------------------------------------------------------
57 Writes an elemental data type to stream.
58 ---------------------------------------------------------------*/
59 #if MRPT_IS_BIG_ENDIAN
60 // Big endian system: Convert into little-endian for streaming
61 #define IMPLEMENT_CArchive_READ_WRITE_SIMPLE_TYPE(T) \
62  CArchive& mrpt::serialization::operator<<(CArchive& out, const T a) \
63  { \
64  mrpt::reverseBytesInPlace(a); \
65  out.WriteBuffer((void*)&a, sizeof(a)); \
66  return out; \
67  } \
68  CArchive& mrpt::serialization::operator>>(CArchive& in, T& a) \
69  { \
70  T b; \
71  in.ReadBuffer((void*)&b, sizeof(a)); \
72  mrpt::reverseBytesInPlace(b); \
73  ::memcpy(&a, &b, sizeof(b)); \
74  return in; \
75  }
76 #else
77 // Little endian system:
78 #define IMPLEMENT_CArchive_READ_WRITE_SIMPLE_TYPE(T) \
79  CArchive& mrpt::serialization::operator<<(CArchive& out, const T a) \
80  { \
81  out.WriteBuffer((void*)&a, sizeof(a)); \
82  return out; \
83  } \
84  CArchive& mrpt::serialization::operator>>(CArchive& in, T& a) \
85  { \
86  in.ReadBuffer((void*)&a, sizeof(a)); \
87  return in; \
88  }
89 #endif
90 
103 
105 {
106  uint64_t rep = s.time_since_epoch().count();
107  return out << rep;
108 }
109 
111 {
112  uint64_t rep;
113  in >> rep;
115  return in;
116 }
117 
119 {
120  uint32_t l = (uint32_t)strlen(s);
121  out << l;
122  out.WriteBuffer(s, (int)l);
123  return out;
124 }
125 
127  CArchive& out, const std::vector<bool>& a)
128 {
129  uint32_t n = (uint32_t)a.size();
130  out << n;
131  if (n)
132  {
133  std::vector<uint8_t> b(n);
136  for (it = a.begin(), it2 = b.begin(); it != a.end(); ++it, ++it2)
137  *it2 = *it ? 1 : 0;
138  out.WriteBuffer((void*)&b[0], (int)(sizeof(b[0]) * n));
139  }
140  return out;
141 }
142 
144 {
145  uint32_t n = (uint32_t)str.size();
146  out << n;
147  if (n) out.WriteBuffer(str.c_str(), n);
148  return out;
149 }
150 
151 /*---------------------------------------------------------------
152 Writes an object to the stream.
153 ---------------------------------------------------------------*/
155 {
156  MRPT_START;
157 
158  // First, the "classname".
159  const char* className;
160  if (o != nullptr)
161  {
162  className = o->GetRuntimeClass()->className;
163  }
164  else
165  {
166  className = "nullptr";
167  }
168 
169  int8_t classNamLen = strlen(className);
170  int8_t classNamLen_mod = classNamLen | 0x80;
171 
172  (*this) << classNamLen_mod;
173  this->WriteBuffer(className, classNamLen);
174 
175  // Next, the version number:
176  if (o != nullptr)
177  {
178  // Version:
179  uint8_t version = o->serializeGetVersion();
180  (*this) << version;
181 
182  // and object data:
183  o->serializeTo(*this);
184  }
185 
186  // In MRPT 0.5.5 a end flag is introduced:
187  (*this) << SERIALIZATION_END_FLAG;
188 
189  MRPT_END;
190 }
191 
193 {
194  WriteObject(pObj.get());
195  return *this;
196 }
197 
198 /** Write an object to a stream in the binary MRPT format. */
200 {
201  WriteObject(&obj);
202  return *this;
203 }
204 
206 {
207  pObj = ReadObject();
208  return *this;
209 }
210 
212 {
213  ReadObject(&obj);
214  return *this;
215 }
216 
217 namespace mrpt
218 {
219 namespace serialization
220 {
221 // For backward compatibility, since in MRPT<0.8.1 vector_XXX and
222 // std::vector<XXX> were exactly equivalent, now there're not.
223 namespace detail
224 {
225 template <typename VEC>
227 {
228  const uint32_t n = static_cast<uint32_t>(v.size());
229  s << n;
230  if (n) s.WriteBufferFixEndianness(&v[0], n);
231  return s;
232 }
233 template <typename VEC>
235 {
236  uint32_t n;
237  s >> n;
238  v.resize(n);
239  if (n) s.ReadBufferFixEndianness(&v[0], n);
240  return s;
241 }
242 } // namespace detail
243 } // namespace serialization
244 } // namespace mrpt
245 
246 // Write:
248  CArchive& s, const std::vector<float>& a)
249 {
251 }
254 {
256 }
258  CArchive& s, const std::vector<double>& a)
259 {
261 }
263  CArchive& s, const std::vector<int32_t>& a)
264 {
266 }
268  CArchive& s, const std::vector<uint32_t>& a)
269 {
271 }
273  CArchive& s, const std::vector<uint16_t>& a)
274 {
276 }
278  CArchive& s, const std::vector<int16_t>& a)
279 {
281 }
283  CArchive& s, const std::vector<int64_t>& a)
284 {
286 }
288  CArchive& s, const std::vector<uint8_t>& a)
289 {
291 }
293  CArchive& s, const std::vector<int8_t>& a)
294 {
296 }
297 
298 // Read:
300 {
302 }
305 {
307 }
309 {
311 }
313 {
315 }
317 {
319 }
321 {
323 }
325 {
327 }
329 {
331 }
333 {
335 }
337 {
339 }
340 
341 #if MRPT_WORD_SIZE != 32 // If it's 32 bit, size_t <=> uint32_t
343  CArchive& s, const std::vector<size_t>& a)
344 {
346 }
348 {
350 }
351 #endif
352 
354 {
355  uint32_t n;
356  in >> n;
357  a.resize(n);
358  if (n)
359  {
360  std::vector<uint8_t> b(n);
361  in.ReadBuffer((void*)&b[0], sizeof(b[0]) * n);
364  for (it = a.begin(), it2 = b.begin(); it != a.end(); ++it, ++it2)
365  *it = (*it2 != 0);
366  }
367  return in;
368 }
369 
371 {
372  uint32_t n;
373  in >> n;
374  str.resize(n);
375  if (n) in.ReadBuffer((void*)&str[0], n);
376  return in;
377 }
378 
380 {
381  ASSERT_(s != nullptr);
382  uint32_t l;
383  in >> l;
384  if (l) in.ReadBuffer(s, l);
385  s[l] = '\0';
386  return in;
387 }
388 
389 //#define CARCHIVE_VERBOSE 1
390 #define CARCHIVE_VERBOSE 0
391 
393  std::string& strClassName, bool& isOldFormat, int8_t& version)
394 {
395  uint8_t lengthReadClassName = 255;
396  char readClassName[260];
397  readClassName[0] = 0;
398 
399  try
400  {
401  // First, read the class name: (exception is raised here if ZERO bytes
402  // read -> possibly an EOF)
403  if (sizeof(lengthReadClassName) !=
404  ReadBuffer(
405  (void*)&lengthReadClassName, sizeof(lengthReadClassName)))
406  THROW_EXCEPTION("Cannot read object header from stream! (EOF?)");
407 
408  // Is in old format (< MRPT 0.5.5)?
409  if (!(lengthReadClassName & 0x80))
410  {
411  isOldFormat = true;
412  uint8_t buf[3];
413  if (3 != ReadBuffer(buf, 3))
415  "Cannot read object header from stream! (EOF?)");
416  if (buf[0] || buf[1] || buf[2])
418  "Expecting 0x00 00 00 while parsing old streaming header "
419  "(Perhaps it's a gz-compressed stream? Use a GZ-stream for "
420  "reading)");
421  }
422  else
423  {
424  isOldFormat = false;
425  }
426 
427  // Remove MSB:
428  lengthReadClassName &= 0x7F;
429 
430  // Sensible class name size?
431  if (lengthReadClassName > 120)
433  "Class name has more than 120 chars. This probably means a "
434  "corrupted binary stream.");
435 
436  if (((size_t)lengthReadClassName) !=
437  ReadBuffer(readClassName, lengthReadClassName))
438  THROW_EXCEPTION("Cannot read object class name from stream!");
439 
440  readClassName[lengthReadClassName] = '\0';
441 
442  // Pass to string class:
443  strClassName = readClassName;
444 
445  // Next, the version number:
446  if (isOldFormat)
447  {
448  int32_t version_old;
449  // Handle big endian right:
450  if (sizeof(version_old) !=
451  ReadBufferFixEndianness(&version_old, 1 /*element count*/))
453  "Cannot read object streaming version from stream!");
454  ASSERT_(version_old >= 0 && version_old < 255);
455  version = int8_t(version_old);
456  }
457  else if (
458  strClassName != "nullptr" &&
459  sizeof(version) != ReadBuffer((void*)&version, sizeof(version)))
460  {
462  "Cannot read object streaming version from stream!");
463  }
464 
465 // In MRPT 0.5.5 an end flag was introduced:
466 #if CARCHIVE_VERBOSE
467  cerr << "[CArchive::ReadObject] readClassName:" << strClassName
468  << " version: " << version << endl;
469 #endif
470  }
471  catch (std::bad_alloc&)
472  {
473  throw;
474  }
475  catch (std::exception& e)
476  {
477  if (lengthReadClassName == 255)
478  {
480  "Cannot read object due to EOF", CExceptionEOF);
481  }
482  else
483  {
485  e, "Exception while parsing typed object '%s' from stream!\n",
486  readClassName);
487  }
488  }
489  catch (...)
490  {
491  THROW_EXCEPTION("Unexpected runtime error!");
492  }
493 } // end method
494 
496  CSerializable* obj, const std::string& strClassName, bool isOldFormat,
497  int8_t version)
498 {
499  try
500  {
501  if (obj)
502  {
503  // Not de-serializing an "nullptr":
504  obj->serializeFrom(*this, version);
505  }
506  if (!isOldFormat)
507  {
508  uint8_t endFlag;
509  if (sizeof(endFlag) != ReadBuffer((void*)&endFlag, sizeof(endFlag)))
511  "Cannot read object streaming version from stream!");
512  if (endFlag != SERIALIZATION_END_FLAG)
514  "end-flag missing: There is a bug in the deserialization "
515  "method of class: '%s'",
516  strClassName.c_str());
517  }
518  }
519  catch (std::bad_alloc&)
520  {
521  throw;
522  }
523  catch (std::exception&)
524  {
525  THROW_TYPED_EXCEPTION("Cannot read object due to EOF", CExceptionEOF);
526  }
527  catch (...)
528  {
529  THROW_EXCEPTION("Unexpected runtime error!");
530  }
531 }
532 
533 /*---------------------------------------------------------------
534 Reads an object from stream, where its class is determined
535 by an existing object
536 exception std::exception On I/O error or undefined class.
537 ---------------------------------------------------------------*/
539 {
541 
542  std::string strClassName;
543  bool isOldFormat;
544  int8_t version;
545 
546  internal_ReadObjectHeader(strClassName, isOldFormat, version);
547 
548  ASSERT_(existingObj && strClassName != "nullptr");
549  ASSERT_(strClassName != "nullptr");
550 
551  const TRuntimeClassId* id = existingObj->GetRuntimeClass();
552  const TRuntimeClassId* id2 = mrpt::rtti::findRegisteredClass(strClassName);
553 
554  if (!id2)
556  "Stored object has class '%s' which is not registered!",
557  strClassName.c_str());
558  if (id != id2)
560  "Stored class does not match with existing object!!:\n Stored: "
561  "%s\n Expected: %s",
562  id2->className, id->className));
563 
564  internal_ReadObject(existingObj, strClassName, isOldFormat, version);
565 }
566 
568  CArchive& s, const std::vector<std::string>& vec)
569 {
570  uint32_t N = static_cast<uint32_t>(vec.size());
571  s << N;
572  for (size_t i = 0; i < N; i++) s << vec[i];
573  return s;
574 }
575 
577  CArchive& s, std::vector<std::string>& vec)
578 {
579  uint32_t N;
580  s >> N;
581  vec.resize(N);
582  for (size_t i = 0; i < N; i++) s >> vec[i];
583  return s;
584 }
585 
587 {
588  MRPT_START
589 
590  unsigned char buf[0x10100];
591  unsigned int nBytesTx = 0;
592 
593  const bool msg_format_is_tiny = msg.content.size() < 256;
594 
595  // Build frame -------------------------------------
596  buf[nBytesTx++] = msg_format_is_tiny ? 0x69 : 0x79;
597  buf[nBytesTx++] = (unsigned char)(msg.type);
598 
599  if (msg_format_is_tiny)
600  {
601  buf[nBytesTx++] = (unsigned char)msg.content.size();
602  }
603  else
604  {
605  buf[nBytesTx++] = msg.content.size() & 0xff; // lo
606  buf[nBytesTx++] = (msg.content.size() >> 8) & 0xff; // hi
607  }
608 
609  if (!msg.content.empty())
610  memcpy(buf + nBytesTx, &msg.content[0], msg.content.size());
611  nBytesTx += (unsigned char)msg.content.size();
612  buf[nBytesTx++] = 0x96;
613 
614  // Send buffer -------------------------------------
615  WriteBuffer(buf, nBytesTx); // Exceptions will be raised on errors here
616 
617  MRPT_END
618 }
619 
621 {
622  MRPT_START
623  std::vector<unsigned char> buf(66000);
624  unsigned int nBytesInFrame = 0;
625  unsigned long nBytesToRx = 0;
626  unsigned char tries = 2;
627  unsigned int payload_len = 0;
628  unsigned int expectedLen = 0;
629 
630  for (;;)
631  {
632  if (nBytesInFrame < 4)
633  nBytesToRx = 1;
634  else
635  {
636  if (buf[0] == 0x69)
637  {
638  payload_len = buf[2];
639  expectedLen = payload_len + 4;
640  }
641  else if (buf[0] == 0x79)
642  {
643  payload_len = MAKEWORD16B(
644  buf[3] /*low*/, buf[2] /*hi*/); // Length of the content
645  expectedLen = payload_len + 5;
646  }
647  nBytesToRx = expectedLen - nBytesInFrame;
648  } // end else
649 
650  unsigned long nBytesRx = 0;
651  try
652  {
653  nBytesRx = ReadBuffer(&buf[nBytesInFrame], nBytesToRx);
654  }
655  catch (...)
656  {
657  }
658 
659  // No more data! (read timeout is already included in the call to
660  // "Read")
661  if (!nBytesRx) return false;
662 
663  if (!nBytesInFrame && buf[0] != 0x69 && buf[0] != 0x79)
664  {
665  // Start flag is invalid:
666  if (!tries--) return false;
667  }
668  else
669  {
670  // Is a new byte for the frame:
671  nBytesInFrame += nBytesRx;
672 
673  if (nBytesInFrame == expectedLen)
674  {
675  // Frame complete
676  // check for frame be ok:
677 
678  // End flag?
679  if (buf[nBytesInFrame - 1] != 0x96)
680  {
681  // Error in frame!
682  nBytesInFrame = 0;
683  return false;
684  }
685  else
686  {
687  // copy out data:
688  msg.type = buf[1];
689  if (buf[0] == 0x69)
690  {
691  msg.content.resize(payload_len);
692  if (!msg.content.empty())
693  memcpy(&msg.content[0], &buf[3], payload_len);
694  } // end if
695  if (buf[0] == 0x79)
696  {
697  msg.content.resize(payload_len);
698  if (!msg.content.empty())
699  memcpy(&msg.content[0], &buf[4], payload_len);
700  } // end if
701  return true;
702  }
703  }
704  }
705  }
706  MRPT_END
707 }
const uint8_t SERIALIZATION_END_FLAG
Definition: CArchive.cpp:22
std::chrono::duration< rep, period > duration
Definition: Clock.h:25
Scalar * iterator
Definition: eigen_plugins.h:26
virtual void serializeTo(CArchive &out) const =0
Pure virtual method for writing (serializing) to an abstract archive.
CArchive & readStdVectorToStream(CArchive &s, VEC &v)
Definition: CArchive.cpp:234
#define THROW_STACKED_EXCEPTION_CUSTOM_MSG2(e, stuff, param1)
Definition: exceptions.h:77
#define MRPT_START
Definition: exceptions.h:262
unsigned __int16 uint16_t
Definition: rptypes.h:44
#define THROW_TYPED_EXCEPTION(msg, exceptionClass)
Definition: exceptions.h:18
std::chrono::time_point< Clock > time_point
Definition: Clock.h:26
#define THROW_EXCEPTION(msg)
Definition: exceptions.h:41
GLenum GLsizei n
Definition: glext.h:5074
uint32_t type
An identifier of the message type (only the least-sig byte is typically sent)
Definition: CMessage.h:32
A structure that holds runtime class type information.
Definition: CObject.h:30
CArchive & writeStdVectorToStream(CArchive &s, const VEC &v)
Definition: CArchive.cpp:226
signed char int8_t
Definition: rptypes.h:40
void WriteBuffer(const void *Buffer, size_t Count)
Writes a block of bytes to the stream from Buffer.
Definition: CArchive.cpp:48
void sendMessage(const CMessage &msg)
Send a message to the device.
Definition: CArchive.cpp:586
std::vector< T, mrpt::aligned_allocator_cpp11< T > > aligned_std_vector
GLdouble s
Definition: glext.h:3676
GLsizei GLsizei GLuint * obj
Definition: glext.h:4070
virtual size_t read(void *buf, size_t len)=0
Reads a block of bytes.
#define IMPLEMENT_CArchive_READ_WRITE_SIMPLE_TYPE(T)
Definition: CArchive.cpp:78
CArchive & operator>>(CSerializable &obj)
Reads a CSerializable object from the stream.
Definition: CArchive.cpp:211
unsigned char uint8_t
Definition: rptypes.h:41
void internal_ReadObjectHeader(std::string &className, bool &isOldFormat, int8_t &version)
Read the object Header.
Definition: CArchive.cpp:392
#define ASSERT_(f)
Defines an assertion mechanism.
Definition: exceptions.h:113
__int16 int16_t
Definition: rptypes.h:43
__int64 int64_t
Definition: rptypes.h:49
const char * className
Definition: CObject.h:33
CArchive & operator<<(const CSerializable &obj)
Write a CSerializable object to a stream in the binary MRPT format.
Definition: CArchive.cpp:199
GLubyte GLubyte b
Definition: glext.h:6279
GLsizei const GLchar ** string
Definition: glext.h:4101
bool receiveMessage(CMessage &msg)
Tries to receive a message from the device.
Definition: CArchive.cpp:620
virtual size_t write(const void *buf, size_t len)=0
Writes a block of bytes.
const TRuntimeClassId * findRegisteredClass(const std::string &className)
Return info about a given class by its name, or nullptr if the class is not registered.
CArchive & operator>>(CArchive &s, mrpt::aligned_std_vector< float > &a)
Definition: CArchive.cpp:303
__int32 int32_t
Definition: rptypes.h:46
unsigned __int64 uint64_t
Definition: rptypes.h:50
const GLdouble * v
Definition: glext.h:3678
This is the global namespace for all Mobile Robot Programming Toolkit (MRPT) libraries.
Virtual base class for "archives": classes abstracting I/O streams.
Definition: CArchive.h:52
A class that contain generic messages, that can be sent and received from a "CClientTCPSocket" object...
Definition: CMessage.h:27
void internal_ReadObject(CSerializable *newObj, const std::string &className, bool isOldFormat, int8_t version)
Read the object.
Definition: CArchive.cpp:495
#define MAKEWORD16B(__LOBYTE, __HILOBYTE)
Definition: byte_manip.h:16
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:16
GLuint id
Definition: glext.h:3909
#define MRPT_END
Definition: exceptions.h:266
GLuint in
Definition: glext.h:7274
CSerializable::Ptr ReadObject()
Reads an object from stream, its class determined at runtime, and returns a smart pointer to the obje...
Definition: CArchive.h:171
CArchive & operator<<(CArchive &s, const mrpt::aligned_std_vector< float > &a)
Definition: CArchive.cpp:252
The virtual base class which provides a unified interface for all persistent objects in MRPT...
Definition: CSerializable.h:30
size_t ReadBuffer(void *Buffer, size_t Count)
Reads a block of bytes from the stream into Buffer.
Definition: CArchive.cpp:24
void WriteObject(const CSerializable *o)
Writes an object to the stream.
Definition: CArchive.cpp:154
std::vector< uint8_t > content
The contents of the message (memory is automatically handled by the std::vector object) ...
Definition: CMessage.h:35
virtual uint8_t serializeGetVersion() const =0
Must return the current versioning number of the object.
#define THROW_EXCEPTION_FMT(_FORMAT_STRING,...)
Definition: exceptions.h:43
unsigned __int32 uint32_t
Definition: rptypes.h:47
size_t ReadBufferFixEndianness(T *ptr, size_t ElementCount)
Reads a sequence of elemental datatypes, taking care of reordering their bytes from the MRPT stream s...
Definition: CArchive.h:88
GLubyte GLubyte GLubyte a
Definition: glext.h:6279
virtual const mrpt::rtti::TRuntimeClassId * GetRuntimeClass() const override
Returns information about the class of an object in runtime.
const Scalar * const_iterator
Definition: eigen_plugins.h:27
Used in mrpt::serialization::CArchive.
Definition: CArchive.h:34
void memcpy(void *dest, size_t destSize, const void *src, size_t copyCount) noexcept
An OS and compiler independent version of "memcpy".
Definition: os.cpp:356



Page generated by Doxygen 1.8.14 for MRPT 1.9.9 Git: 7d5e6d718 Fri Aug 24 01:51:28 2018 +0200 at lun nov 2 08:35:50 CET 2020