Main MRPT website > C++ reference for 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  long double)
104 
106  CArchive& out, const char* s)
107 {
108  uint32_t l = (uint32_t)strlen(s);
109  out << l;
110  out.WriteBuffer(s, (int)l);
111  return out;
112 }
113 
115  CArchive& out, const std::vector<bool>& a)
116 {
117  uint32_t n = (uint32_t)a.size();
118  out << n;
119  if (n)
120  {
121  std::vector<uint8_t> b(n);
124  for (it = a.begin(), it2 = b.begin(); it != a.end(); ++it, ++it2)
125  *it2 = *it ? 1 : 0;
126  out.WriteBuffer((void*)&b[0], (int)(sizeof(b[0]) * n));
127  }
128  return out;
129 }
130 
132 {
133  uint32_t n = (uint32_t)str.size();
134  out << n;
135  if (n) out.WriteBuffer(str.c_str(), n);
136  return out;
137 }
138 
139 /*---------------------------------------------------------------
140 Writes an object to the stream.
141 ---------------------------------------------------------------*/
143 {
144  MRPT_START;
145 
146  // First, the "classname".
147  const char* className;
148  if (o != nullptr)
149  {
150  className = o->GetRuntimeClass()->className;
151  }
152  else
153  {
154  className = "nullptr";
155  }
156 
157  int8_t classNamLen = strlen(className);
158  int8_t classNamLen_mod = classNamLen | 0x80;
159 
160  (*this) << classNamLen_mod;
161  this->WriteBuffer(className, classNamLen);
162 
163  // Next, the version number:
164  if (o != nullptr)
165  {
166  // Version:
167  uint8_t version = o->serializeGetVersion();
168  (*this) << version;
169 
170  // and object data:
171  o->serializeTo(*this);
172  }
173 
174  // In MRPT 0.5.5 a end flag is introduced:
175  (*this) << SERIALIZATION_END_FLAG;
176 
177  MRPT_END;
178 }
179 
181 {
182  WriteObject(pObj.get());
183  return *this;
184 }
185 
186 /** Write an object to a stream in the binary MRPT format. */
188 {
189  WriteObject(&obj);
190  return *this;
191 }
192 
194 {
195  pObj = ReadObject();
196  return *this;
197 }
198 
200 {
201  ReadObject(&obj);
202  return *this;
203 }
204 
205 namespace mrpt
206 {
207 namespace serialization
208 {
209 // For backward compatibility, since in MRPT<0.8.1 vector_XXX and
210 // std::vector<XXX> were exactly equivalent, now there're not.
211 namespace detail
212 {
213 template <typename VEC>
215 {
216  const uint32_t n = static_cast<uint32_t>(v.size());
217  s << n;
218  if (n) s.WriteBufferFixEndianness(&v[0], n);
219  return s;
220 }
221 template <typename VEC>
223 {
224  uint32_t n;
225  s >> n;
226  v.resize(n);
227  if (n) s.ReadBufferFixEndianness(&v[0], n);
228  return s;
229 }
230 } // namespace detail
231 } // namespace serialization
232 } // namespace mrpt
233 
234 // Write:
236  CArchive& s, const std::vector<float>& a)
237 {
239 }
242 {
244 }
246  CArchive& s, const std::vector<double>& a)
247 {
249 }
251  CArchive& s, const std::vector<int32_t>& a)
252 {
254 }
256  CArchive& s, const std::vector<uint32_t>& a)
257 {
259 }
261  CArchive& s, const std::vector<uint16_t>& a)
262 {
264 }
266  CArchive& s, const std::vector<int16_t>& a)
267 {
269 }
271  CArchive& s, const std::vector<int64_t>& a)
272 {
274 }
276  CArchive& s, const std::vector<uint8_t>& a)
277 {
279 }
281  CArchive& s, const std::vector<int8_t>& a)
282 {
284 }
285 
286 // Read:
288 {
290 }
293 {
295 }
297 {
299 }
301 {
303 }
305 {
307 }
309 {
311 }
313 {
315 }
317 {
319 }
321 {
323 }
325 {
327 }
328 
329 #if MRPT_WORD_SIZE != 32 // If it's 32 bit, size_t <=> uint32_t
331  CArchive& s, const std::vector<size_t>& a)
332 {
334 }
336 {
338 }
339 #endif
340 
342 {
343  uint32_t n;
344  in >> n;
345  a.resize(n);
346  if (n)
347  {
348  std::vector<uint8_t> b(n);
349  in.ReadBuffer((void*)&b[0], sizeof(b[0]) * n);
352  for (it = a.begin(), it2 = b.begin(); it != a.end(); ++it, ++it2)
353  *it = (*it2 != 0);
354  }
355  return in;
356 }
357 
359 {
360  uint32_t n;
361  in >> n;
362  str.resize(n);
363  if (n) in.ReadBuffer((void*)&str[0], n);
364  return in;
365 }
366 
368 {
369  ASSERT_(s != nullptr);
370  uint32_t l;
371  in >> l;
372  if (l) in.ReadBuffer(s, l);
373  s[l] = '\0';
374  return in;
375 }
376 
377 //#define CARCHIVE_VERBOSE 1
378 #define CARCHIVE_VERBOSE 0
379 
381  std::string& strClassName, bool& isOldFormat, int8_t& version)
382 {
383  uint8_t lengthReadClassName = 255;
384  char readClassName[260];
385  readClassName[0] = 0;
386 
387  try
388  {
389  // First, read the class name: (exception is raised here if ZERO bytes
390  // read -> possibly an EOF)
391  if (sizeof(lengthReadClassName) !=
392  ReadBuffer(
393  (void*)&lengthReadClassName, sizeof(lengthReadClassName)))
394  THROW_EXCEPTION("Cannot read object header from stream! (EOF?)");
395 
396  // Is in old format (< MRPT 0.5.5)?
397  if (!(lengthReadClassName & 0x80))
398  {
399  isOldFormat = true;
400  uint8_t buf[3];
401  if (3 != ReadBuffer(buf, 3))
403  "Cannot read object header from stream! (EOF?)");
404  if (buf[0] || buf[1] || buf[2])
406  "Expecting 0x00 00 00 while parsing old streaming header "
407  "(Perhaps it's a gz-compressed stream? Use a GZ-stream for "
408  "reading)");
409  }
410  else
411  {
412  isOldFormat = false;
413  }
414 
415  // Remove MSB:
416  lengthReadClassName &= 0x7F;
417 
418  // Sensible class name size?
419  if (lengthReadClassName > 120)
421  "Class name has more than 120 chars. This probably means a "
422  "corrupted binary stream.");
423 
424  if (((size_t)lengthReadClassName) !=
425  ReadBuffer(readClassName, lengthReadClassName))
426  THROW_EXCEPTION("Cannot read object class name from stream!");
427 
428  readClassName[lengthReadClassName] = '\0';
429 
430  // Pass to string class:
431  strClassName = readClassName;
432 
433  // Next, the version number:
434  if (isOldFormat)
435  {
436  int32_t version_old;
437  // Handle big endian right:
438  if (sizeof(version_old) !=
439  ReadBufferFixEndianness(&version_old, 1 /*element count*/))
441  "Cannot read object streaming version from stream!");
442  ASSERT_(version_old >= 0 && version_old < 255);
443  version = int8_t(version_old);
444  }
445  else if (
446  strClassName != "nullptr" &&
447  sizeof(version) != ReadBuffer((void*)&version, sizeof(version)))
448  {
450  "Cannot read object streaming version from stream!");
451  }
452 
453 // In MRPT 0.5.5 an end flag was introduced:
454 #if CARCHIVE_VERBOSE
455  cerr << "[CArchive::ReadObject] readClassName:" << strClassName
456  << " version: " << version << endl;
457 #endif
458  }
459  catch (std::bad_alloc&)
460  {
461  throw;
462  }
463  catch (std::exception& e)
464  {
465  if (lengthReadClassName == 255)
466  {
468  "Cannot read object due to EOF", CExceptionEOF);
469  }
470  else
471  {
473  e, "Exception while parsing typed object '%s' from stream!\n",
474  readClassName);
475  }
476  }
477  catch (...)
478  {
479  THROW_EXCEPTION("Unexpected runtime error!");
480  }
481 } // end method
482 
484  CSerializable* obj, const std::string& strClassName, bool isOldFormat,
485  int8_t version)
486 {
487  try
488  {
489  if (obj)
490  {
491  // Not de-serializing an "nullptr":
492  obj->serializeFrom(*this, version);
493  }
494  if (!isOldFormat)
495  {
496  uint8_t endFlag;
497  if (sizeof(endFlag) != ReadBuffer((void*)&endFlag, sizeof(endFlag)))
499  "Cannot read object streaming version from stream!");
500  if (endFlag != SERIALIZATION_END_FLAG)
502  "end-flag missing: There is a bug in the deserialization "
503  "method of class: '%s'",
504  strClassName.c_str());
505  }
506  }
507  catch (std::bad_alloc&)
508  {
509  throw;
510  }
511  catch (std::exception&)
512  {
513  THROW_TYPED_EXCEPTION("Cannot read object due to EOF", CExceptionEOF);
514  }
515  catch (...)
516  {
517  THROW_EXCEPTION("Unexpected runtime error!");
518  }
519 }
520 
521 /*---------------------------------------------------------------
522 Reads an object from stream, where its class is determined
523 by an existing object
524 exception std::exception On I/O error or undefined class.
525 ---------------------------------------------------------------*/
527 {
529 
530  std::string strClassName;
531  bool isOldFormat;
532  int8_t version;
533 
534  internal_ReadObjectHeader(strClassName, isOldFormat, version);
535 
536  ASSERT_(existingObj && strClassName != "nullptr");
537  ASSERT_(strClassName != "nullptr");
538 
539  const TRuntimeClassId* id = existingObj->GetRuntimeClass();
540 
541  if (id->className != strClassName && id->altName != strClassName)
543  "Stored class does not match with existing object!!:\n Stored: "
544  "%s\n Expected: %s",
545  strClassName.c_str(), id->className));
546 
547  internal_ReadObject(existingObj, strClassName, isOldFormat, version);
548 }
549 
551  CArchive& s, const std::vector<std::string>& vec)
552 {
553  uint32_t N = static_cast<uint32_t>(vec.size());
554  s << N;
555  for (size_t i = 0; i < N; i++) s << vec[i];
556  return s;
557 }
558 
560  CArchive& s, std::vector<std::string>& vec)
561 {
562  uint32_t N;
563  s >> N;
564  vec.resize(N);
565  for (size_t i = 0; i < N; i++) s >> vec[i];
566  return s;
567 }
568 
570 {
571  MRPT_START
572 
573  unsigned char buf[0x10100];
574  unsigned int nBytesTx = 0;
575 
576  const bool msg_format_is_tiny = msg.content.size() < 256;
577 
578  // Build frame -------------------------------------
579  buf[nBytesTx++] = msg_format_is_tiny ? 0x69 : 0x79;
580  buf[nBytesTx++] = (unsigned char)(msg.type);
581 
582  if (msg_format_is_tiny)
583  {
584  buf[nBytesTx++] = (unsigned char)msg.content.size();
585  }
586  else
587  {
588  buf[nBytesTx++] = msg.content.size() & 0xff; // lo
589  buf[nBytesTx++] = (msg.content.size() >> 8) & 0xff; // hi
590  }
591 
592  if (!msg.content.empty())
593  memcpy(buf + nBytesTx, &msg.content[0], msg.content.size());
594  nBytesTx += (unsigned char)msg.content.size();
595  buf[nBytesTx++] = 0x96;
596 
597  // Send buffer -------------------------------------
598  WriteBuffer(buf, nBytesTx); // Exceptions will be raised on errors here
599 
600  MRPT_END
601 }
602 
604 {
605  MRPT_START
606  std::vector<unsigned char> buf(66000);
607  unsigned int nBytesInFrame = 0;
608  unsigned long nBytesToRx = 0;
609  unsigned char tries = 2;
610  unsigned int payload_len = 0;
611  unsigned int expectedLen = 0;
612 
613  for (;;)
614  {
615  if (nBytesInFrame < 4)
616  nBytesToRx = 1;
617  else
618  {
619  if (buf[0] == 0x69)
620  {
621  payload_len = buf[2];
622  expectedLen = payload_len + 4;
623  }
624  else if (buf[0] == 0x79)
625  {
626  payload_len = MAKEWORD16B(
627  buf[3] /*low*/, buf[2] /*hi*/); // Length of the content
628  expectedLen = payload_len + 5;
629  }
630  nBytesToRx = expectedLen - nBytesInFrame;
631  } // end else
632 
633  unsigned long nBytesRx = 0;
634  try
635  {
636  nBytesRx = ReadBuffer(&buf[nBytesInFrame], nBytesToRx);
637  }
638  catch (...)
639  {
640  }
641 
642  // No more data! (read timeout is already included in the call to
643  // "Read")
644  if (!nBytesRx) return false;
645 
646  if (!nBytesInFrame && buf[0] != 0x69 && buf[0] != 0x79)
647  {
648  // Start flag is invalid:
649  if (!tries--) return false;
650  }
651  else
652  {
653  // Is a new byte for the frame:
654  nBytesInFrame += nBytesRx;
655 
656  if (nBytesInFrame == expectedLen)
657  {
658  // Frame complete
659  // check for frame be ok:
660 
661  // End flag?
662  if (buf[nBytesInFrame - 1] != 0x96)
663  {
664  // Error in frame!
665  nBytesInFrame = 0;
666  return false;
667  }
668  else
669  {
670  // copy out data:
671  msg.type = buf[1];
672  if (buf[0] == 0x69)
673  {
674  msg.content.resize(payload_len);
675  if (!msg.content.empty())
676  memcpy(&msg.content[0], &buf[3], payload_len);
677  } // end if
678  if (buf[0] == 0x79)
679  {
680  msg.content.resize(payload_len);
681  if (!msg.content.empty())
682  memcpy(&msg.content[0], &buf[4], payload_len);
683  } // end if
684  return true;
685  }
686  }
687  }
688  }
689  MRPT_END
690 }
const uint8_t SERIALIZATION_END_FLAG
Definition: CArchive.cpp:22
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:222
#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
#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:34
A structure that holds runtime class type information.
Definition: CObject.h:30
CArchive & writeStdVectorToStream(CArchive &s, const VEC &v)
Definition: CArchive.cpp:214
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:569
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:199
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:380
#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:187
std::string format(const char *fmt,...) MRPT_printf_format_check(1
A std::string version of C sprintf.
Definition: format.cpp:16
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:603
virtual size_t write(const void *buf, size_t len)=0
Writes a block of bytes.
CArchive & operator>>(CArchive &s, mrpt::aligned_std_vector< float > &a)
Definition: CArchive.cpp:291
__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:48
A class that contain generic messages, that can be sent and received from a "CClientTCPSocket" object...
Definition: CMessage.h:29
void internal_ReadObject(CSerializable *newObj, const std::string &className, bool isOldFormat, int8_t version)
Read the object.
Definition: CArchive.cpp:483
#define MAKEWORD16B(__LOBYTE, __HILOBYTE)
Definition: byte_manip.h: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:167
CArchive & operator<<(CArchive &s, const mrpt::aligned_std_vector< float > &a)
Definition: CArchive.cpp:240
The virtual base class which provides a unified interface for all persistent objects in MRPT...
Definition: CSerializable.h:32
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:142
std::vector< uint8_t > content
The contents of the message (memory is automatically handled by the std::vector object) ...
Definition: CMessage.h:37
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:84
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:30
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: ad3a9d8ae Tue May 1 23:10:22 2018 -0700 at lun oct 28 00:14:14 CET 2019