Line data Source code
1 : /*
2 : * Distributed under the OpenDDS License.
3 : * See: http://www.opendds.org/license.html
4 : */
5 :
6 : /**
7 : * @file Serializer.h
8 : *
9 : * The serialization interface for a C++ type called Type consists of the
10 : * following overloads:
11 : *
12 : * void serialized_size(
13 : * const Encoding& encoding, size_t& size, const Type& value);
14 : * Get the size (in bytes) of the encoded representation of value.
15 : *
16 : * bool operator<<(Serializer& serializer, const Type& value);
17 : * Tries to encode value into the stream of the serializer. Returns true if
18 : * successful, else false.
19 : *
20 : * bool operator>>(Serializer& serializer, Type& value);
21 : * Tries to decode a representation of Type located at the current
22 : * position of the stream and use that to set value. Returns true if
23 : * successful, else false.
24 : */
25 :
26 : #ifndef OPENDDS_DCPS_SERIALIZER_H
27 : #define OPENDDS_DCPS_SERIALIZER_H
28 :
29 : #include <ace/config-macros.h>
30 : #ifndef ACE_LACKS_PRAGMA_ONCE
31 : # pragma once
32 : #endif /* ACE_LACKS_PRAGMA_ONCE */
33 :
34 : #include "Definitions.h"
35 : #include "PoolAllocator.h"
36 : #include "Message_Block_Ptr.h"
37 : #include "dcps_export.h"
38 :
39 : #include <ace/CDR_Base.h>
40 : #include <ace/CDR_Stream.h>
41 :
42 : #include <limits>
43 : #include <string>
44 :
45 : ACE_BEGIN_VERSIONED_NAMESPACE_DECL
46 : class ACE_Message_Block;
47 : ACE_END_VERSIONED_NAMESPACE_DECL
48 :
49 : OPENDDS_BEGIN_VERSIONED_NAMESPACE_DECL
50 :
51 : namespace OpenDDS {
52 : namespace DCPS {
53 :
54 : enum Endianness {
55 : ENDIAN_BIG = 0,
56 : ENDIAN_LITTLE = 1,
57 : #ifdef ACE_LITTLE_ENDIAN
58 : ENDIAN_NATIVE = ENDIAN_LITTLE,
59 : ENDIAN_NONNATIVE = ENDIAN_BIG
60 : #else
61 : ENDIAN_NATIVE = ENDIAN_BIG,
62 : ENDIAN_NONNATIVE = ENDIAN_LITTLE
63 : #endif
64 : };
65 :
66 : OpenDDS_Dcps_Export
67 : String endianness_to_string(Endianness endianness);
68 :
69 : enum Extensibility {
70 : FINAL,
71 : APPENDABLE,
72 : MUTABLE
73 : };
74 :
75 0 : inline const char* ext_to_string(Extensibility ext)
76 : {
77 0 : switch (ext) {
78 0 : case FINAL:
79 0 : return "final";
80 0 : case APPENDABLE:
81 0 : return "appendable";
82 0 : case MUTABLE:
83 0 : return "mutable";
84 0 : default:
85 0 : return "invalid";
86 : }
87 : }
88 :
89 : const size_t boolean_cdr_size = 1;
90 : const size_t byte_cdr_size = 1;
91 : const size_t int8_cdr_size = 1;
92 : const size_t uint8_cdr_size = 1;
93 : const size_t int16_cdr_size = 2;
94 : const size_t uint16_cdr_size = 2;
95 : const size_t int32_cdr_size = 4;
96 : const size_t uint32_cdr_size = 4;
97 : const size_t int64_cdr_size = 8;
98 : const size_t uint64_cdr_size = 8;
99 : const size_t float32_cdr_size = 4;
100 : const size_t float64_cdr_size = 8;
101 : const size_t float128_cdr_size = 16;
102 : const size_t char8_cdr_size = 1;
103 : const size_t char16_cdr_size = 2;
104 : const size_t xcdr1_pid_alignment = 4;
105 :
106 : /// Align "value" by "by" if it's not already
107 : OpenDDS_Dcps_Export
108 : void align(size_t& value, size_t by);
109 :
110 : /**
111 : * Represents the serialization rules. Used to construct a
112 : * Serializer and to pass to functions that are used without
113 : * a Serializer like serialized_size() and max_serialized_size()
114 : */
115 : class OpenDDS_Dcps_Export Encoding {
116 : public:
117 : /**
118 : * Kinds are the overall algorithm for serialization.
119 : * A Kind value along with other details like alignment and endianness
120 : * comprise an Encoding.
121 : */
122 : enum Kind {
123 : /**
124 : * Extensible CDR version 1 from XTypes.
125 : * This represents standard non-XTypes CDR if the type is final.
126 : */
127 : KIND_XCDR1,
128 : /**
129 : * Extensible CDR version 2 from XTypes.
130 : */
131 : KIND_XCDR2,
132 : /**
133 : * This is the classic encoding of OpenDDS used when there is no RTPS
134 : * transport being used. It has no padding bytes and no XCDR behavior.
135 : */
136 : KIND_UNALIGNED_CDR
137 : };
138 :
139 : enum Alignment {
140 : ALIGN_NONE = 0, ///< No Alignment Needed
141 : ALIGN_CDR = 8, ///< Align for CDR and XCDR1
142 : ALIGN_XCDR2 = 4, ///< Align for XCDR2
143 : ALIGN_MAX = ALIGN_CDR ///< Maximum alignment that could be used
144 : };
145 :
146 : /**
147 : * XCDR version derived from the Encoding kind.
148 : */
149 : enum XcdrVersion {
150 : XCDR_VERSION_NONE,
151 : XCDR_VERSION_1,
152 : XCDR_VERSION_2
153 : };
154 :
155 : /// Encoding with KIND_XCDR1 and ENDIAN_NATIVE
156 : Encoding();
157 :
158 : explicit Encoding(Kind kind, Endianness endianness = ENDIAN_NATIVE);
159 :
160 : Encoding(Kind kind, bool swap_bytes);
161 :
162 : Kind kind() const;
163 : void kind(Kind value);
164 :
165 : Endianness endianness() const;
166 : void endianness(Endianness value);
167 :
168 : Alignment alignment() const;
169 : void alignment(Alignment value);
170 :
171 : ///@{
172 : /**
173 : * Should the padding bytes being inserted into the stream be zero
174 : * initialized?
175 : */
176 : bool zero_init_padding() const;
177 : void zero_init_padding(bool value);
178 : ///@}
179 :
180 : ///@{
181 : /**
182 : * Should the XCDR2 sequence DHEADER be skipped?
183 : * This is not spec compliant -- used for compatibility with earlier
184 : * OpenDDS versions that had a bug.
185 : * Only used for XTypes::TypeObject and related structs.
186 : */
187 : bool skip_sequence_dheader() const;
188 : void skip_sequence_dheader(bool value);
189 : ///@}
190 :
191 : /// Return the maximum alignment dictated by the alignment policy.
192 : size_t max_align() const;
193 :
194 : /// Align "value" to "by" and according to the stream's alignment.
195 : void align(size_t& value, size_t by = (std::numeric_limits<size_t>::max)()) const;
196 :
197 : XcdrVersion xcdr_version() const;
198 : void xcdr_version(XcdrVersion value);
199 :
200 : ///@{
201 : /**
202 : * Returns true if the encoding kind is excepted to have a header for RTPS
203 : * serialized data payloads.
204 : */
205 : static bool is_encapsulated(Kind kind);
206 : bool is_encapsulated() const;
207 : ///@}
208 :
209 : String to_string() const;
210 : static String kind_to_string(Kind value);
211 :
212 : private:
213 : Kind kind_;
214 : Endianness endianness_;
215 : Alignment alignment_;
216 : bool zero_init_padding_;
217 : bool skip_sequence_dheader_;
218 : XcdrVersion xcdr_version_;
219 : };
220 :
221 : /**
222 : * Represents the RTPS encapsulation header for serialized data.
223 : *
224 : * This consists of 4 bytes that appear in front of the data. The first two
225 : * bytes represents the kind of the encoding the data uses and the last two
226 : * bytes (known as "options") are traditionally reserved.
227 : *
228 : * See XTypes 1.3 7.6.3.1.2
229 : */
230 : class OpenDDS_Dcps_Export EncapsulationHeader {
231 : public:
232 : /**
233 : * The known possible values of the first 2 bytes represented as big endian
234 : * integers.
235 : */
236 : enum Kind {
237 : KIND_CDR_BE = 0x0000,
238 : KIND_CDR_LE = 0x0001,
239 : KIND_PL_CDR_BE = 0x0002,
240 : KIND_PL_CDR_LE = 0x0003,
241 : KIND_CDR2_BE = 0x0006,
242 : KIND_CDR2_LE = 0x0007,
243 : KIND_D_CDR2_BE = 0x0008,
244 : KIND_D_CDR2_LE = 0x0009,
245 : KIND_PL_CDR2_BE = 0x000a,
246 : KIND_PL_CDR2_LE = 0x000b,
247 : KIND_XML = 0x0004,
248 : KIND_INVALID = 0xFFFF
249 : };
250 :
251 : const static size_t serialized_size = 4;
252 : const static size_t padding_marker_byte_index = 3;
253 : const static size_t padding_marker_alignment = 4;
254 :
255 : EncapsulationHeader(Kind k = KIND_CDR_BE, ACE_CDR::UShort options = 0);
256 :
257 : /**
258 : * Success can be verified using is_good()
259 : */
260 : EncapsulationHeader(const Encoding& enc, Extensibility ext, ACE_CDR::UShort options = 0);
261 :
262 : Kind kind() const;
263 : void kind(Kind value);
264 :
265 : ACE_UINT16 options() const;
266 : void options(ACE_UINT16 value);
267 :
268 : /**
269 : * post-initialization test for a successful call to from_encoding during
270 : * construction of this encapsulation header.
271 : */
272 : bool is_good() const;
273 :
274 : /**
275 : * Translate from an encoding, returns false if it failed.
276 : */
277 : bool from_encoding(const Encoding& encoding, Extensibility extensibility);
278 :
279 : /**
280 : * Translate to an encoding, returns false if it failed.
281 : */
282 : bool to_encoding(Encoding& encoding, Extensibility expected_extensibility);
283 :
284 : /**
285 : * Like to_encoding, but without an expected extensibility.
286 : */
287 : bool to_any_encoding(Encoding& encoding);
288 :
289 : String to_string() const;
290 :
291 : static bool set_encapsulation_options(Message_Block_Ptr& mb);
292 :
293 : private:
294 : /// The first two bytes as a big endian integer
295 : Kind kind_;
296 : /// The last two bytes as a big endian integer
297 : ACE_CDR::UShort options_;
298 :
299 : bool to_encoding_i(Encoding& encoding, Extensibility* expected_extensibility_ptr);
300 : };
301 :
302 : class Serializer;
303 :
304 : OpenDDS_Dcps_Export
305 : bool operator>>(Serializer& s, EncapsulationHeader& value);
306 :
307 : OpenDDS_Dcps_Export
308 : bool operator<<(Serializer& s, const EncapsulationHeader& value);
309 :
310 : /**
311 : * Convenience function for the serialized_size of a single value with no
312 : * alignment needed.
313 : */
314 : template <typename T>
315 540 : size_t serialized_size(const Encoding& encoding, const T& value)
316 : {
317 540 : size_t size = 0;
318 540 : serialized_size(encoding, size, value);
319 540 : return size;
320 : }
321 :
322 : /**
323 : * This helper class can be used to construct ACE message blocks from
324 : * IDL sequences of octet (or compatible substitutes) and be used with
325 : * the Serializer to serialize/deserialize directly into the byte
326 : * buffer. The sequence must have its length set before constructing
327 : * this object. T should provide a length() method which is the size
328 : * of the buffer and get_buffer() which returns a pointer to the
329 : * underlying byte sequence.
330 : */
331 : template <typename T>
332 : class MessageBlockHelper {
333 : public:
334 : /**
335 : * This constructor receives an already populated OctetSeq so the write pointer is advanced
336 : */
337 39 : explicit MessageBlockHelper(const T& seq)
338 39 : : db_(seq.length(), ACE_Message_Block::MB_DATA,
339 39 : reinterpret_cast<const char*>(seq.get_buffer()),
340 : 0 /*alloc*/, 0 /*lock*/, ACE_Message_Block::DONT_DELETE, 0 /*db_alloc*/)
341 39 : , mb_(&db_, ACE_Message_Block::DONT_DELETE, 0 /*mb_alloc*/)
342 : {
343 39 : mb_.wr_ptr(mb_.space());
344 39 : }
345 :
346 81 : explicit MessageBlockHelper(T& seq)
347 81 : : db_(seq.length(), ACE_Message_Block::MB_DATA,
348 81 : reinterpret_cast<const char*>(seq.get_buffer()),
349 : 0 /*alloc*/, 0 /*lock*/, ACE_Message_Block::DONT_DELETE, 0 /*db_alloc*/)
350 81 : , mb_(&db_, ACE_Message_Block::DONT_DELETE, 0 /*mb_alloc*/)
351 81 : {}
352 :
353 120 : operator ACE_Message_Block*() { return &mb_; }
354 :
355 : private:
356 : ACE_Data_Block db_;
357 : ACE_Message_Block mb_;
358 : };
359 :
360 : /**
361 : * @class Serializer
362 : *
363 : * @brief Class to serialize and deserialize data for DDS.
364 : *
365 : * This class provides a mechanism to insert and extract data to and
366 : * from an ACE_Message_Block chain that represents the data which
367 : * can be transported on the wire to other DDS service participants.
368 : */
369 : class OpenDDS_Dcps_Export Serializer {
370 : public:
371 : /// Flags and reserved ids used in parameter list ids.
372 : ///@{
373 : static const ACE_CDR::UShort pid_extended = 0x3f01;
374 : /**
375 : * Note that this is different than OpenDDS::RTPS::PID_SENTINEL(0x0001). See
376 : * XTypes 1.3 Table 34 for details.
377 : */
378 : static const ACE_CDR::UShort pid_list_end = 0x3f02;
379 : static const ACE_CDR::UShort pid_impl_extension = 0x8000;
380 : static const ACE_CDR::UShort pid_must_understand = 0x4000;
381 : ///@}
382 :
383 : // EMHEADER must understand flag
384 : static const ACE_CDR::ULong emheader_must_understand = 1U << 31U;
385 :
386 : /// Maximum value for member id.
387 : static const ACE_CDR::ULong MEMBER_ID_MAX = 0x0FFFFFFF;
388 : static const ACE_CDR::ULong MEMBER_ID_MASK = MEMBER_ID_MAX;
389 :
390 : /**
391 : * Constructor with a message block chain. This installs the
392 : * message block chain and sets the current block to the first in
393 : * the chain. Memory management is the responsibility of the owner
394 : * of this object, and is not performed internally. Ownership of
395 : * the message block chain is retained by the owner of this object
396 : * and the lifetime of the chain must be longer than the use of
397 : * this object.
398 : *
399 : * This constructor is meant for using a specific predefined encoding scheme.
400 : */
401 : Serializer(ACE_Message_Block* chain, const Encoding& encoding);
402 :
403 : /**
404 : * More convenient version of the constructor above if you don't need to
405 : * reuse the Encoding object.
406 : */
407 : Serializer(ACE_Message_Block* chain, Encoding::Kind kind,
408 : Endianness endianness = ENDIAN_NATIVE);
409 :
410 : /**
411 : * Equivalent to: Serializer(chain, kind, swap_bytes ? ENDIAN_NONNATIVE : ENDIAN_NATIVE)
412 : */
413 : Serializer(ACE_Message_Block* chain, Encoding::Kind kind, bool swap_bytes);
414 :
415 : virtual ~Serializer();
416 :
417 : const Encoding& encoding() const;
418 : void encoding(const Encoding& value);
419 :
420 : void swap_bytes(bool do_swap);
421 : bool swap_bytes() const;
422 :
423 : Endianness endianness() const;
424 : void endianness(Endianness value);
425 :
426 : Encoding::Alignment alignment() const;
427 : void alignment(Encoding::Alignment value);
428 :
429 : /// Reset alignment as if a new instance were created
430 : void reset_alignment();
431 :
432 : bool good_bit() const;
433 :
434 : /// Number of bytes left to read in message block chain
435 : size_t length() const;
436 :
437 : typedef ACE_CDR::Char* (*StrAllocate)(ACE_CDR::ULong);
438 : typedef void (*StrFree)(ACE_CDR::Char*);
439 : typedef ACE_CDR::WChar* (*WStrAllocate)(ACE_CDR::ULong);
440 : typedef void (*WStrFree)(ACE_CDR::WChar*);
441 :
442 : size_t read_string(ACE_CDR::Char*& dest,
443 : StrAllocate str_alloc = 0,
444 : StrFree str_free = 0);
445 :
446 : void free_string(ACE_CDR::Char* str,
447 : StrFree str_free = 0);
448 :
449 : size_t read_string(ACE_CDR::WChar*& dest,
450 : WStrAllocate str_alloc = 0,
451 : WStrFree str_free = 0);
452 :
453 : void free_string(ACE_CDR::WChar* str,
454 : WStrFree str_free = 0);
455 :
456 : /// Skip the logical rd_ptr() over a given number of bytes = n * size.
457 : /// If alignment is enabled, skips any padding to align to 'size' before
458 : /// skipping the n * size bytes.
459 : /// This is used by the RTPS protocol to allow reading messages from
460 : /// future versions of the spec which may have additional optional fields.
461 : bool skip(size_t n, int size = 1);
462 :
463 : /// Return a duplicated Message Block (chain) which starts at the current
464 : /// read position (rpos) and extends for n bytes.
465 : /// This can be used to treat a subset of the original message as if it
466 : /// was itself a full message, for example the SerializedPayload or the
467 : /// Parameter value inside a ParameterList.
468 : /// The returned object should be release()'d (use Message_Block_Ptr)
469 : ACE_Message_Block* trim(size_t n) const;
470 :
471 0 : const char* pos_rd() const { return current_ ? current_->rd_ptr() : 0; }
472 : const char* pos_wr() const { return current_ ? current_->wr_ptr() : 0; }
473 :
474 : /// Examine the logical reading position of the stream.
475 6433 : size_t rpos() const { return rpos_; }
476 :
477 : /// Examine the logical writing position of the stream.
478 271 : size_t wpos() const { return wpos_; }
479 :
480 287 : ACE_Message_Block* current() const
481 : {
482 287 : return current_;
483 : }
484 :
485 : /**
486 : * Read basic IDL types arrays
487 : * The buffer @a x must be large enough to contain @a length
488 : * elements.
489 : * Return @c false on failure and @c true on success.
490 : */
491 : ///@{
492 : bool read_boolean_array(ACE_CDR::Boolean* x, ACE_CDR::ULong length);
493 : bool read_char_array(ACE_CDR::Char* x, ACE_CDR::ULong length);
494 : bool read_wchar_array(ACE_CDR::WChar* x, ACE_CDR::ULong length);
495 : bool read_octet_array(ACE_CDR::Octet* x, ACE_CDR::ULong length);
496 : #if OPENDDS_HAS_EXPLICIT_INTS
497 : bool read_int8_array(ACE_CDR::Int8* x, ACE_CDR::ULong length);
498 : bool read_uint8_array(ACE_CDR::UInt8* x, ACE_CDR::ULong length);
499 : #endif
500 : bool read_short_array(ACE_CDR::Short* x, ACE_CDR::ULong length);
501 : bool read_ushort_array(ACE_CDR::UShort* x, ACE_CDR::ULong length);
502 : bool read_long_array(ACE_CDR::Long* x, ACE_CDR::ULong length);
503 : bool read_ulong_array(ACE_CDR::ULong* x, ACE_CDR::ULong length);
504 : bool read_longlong_array(ACE_CDR::LongLong* x, ACE_CDR::ULong length);
505 : bool read_ulonglong_array(ACE_CDR::ULongLong* x, ACE_CDR::ULong length);
506 : bool read_float_array(ACE_CDR::Float* x, ACE_CDR::ULong length);
507 : bool read_double_array(ACE_CDR::Double* x, ACE_CDR::ULong length);
508 : bool read_longdouble_array(ACE_CDR::LongDouble* x, ACE_CDR::ULong length);
509 : ///@}
510 :
511 : /// Array write operations
512 : /// Note: the portion written starts at x and ends
513 : /// at x + length.
514 : /// The length is *NOT* stored into the CDR stream.
515 : ///@{
516 : bool write_boolean_array(const ACE_CDR::Boolean* x, ACE_CDR::ULong length);
517 : bool write_char_array(const ACE_CDR::Char* x, ACE_CDR::ULong length);
518 : bool write_wchar_array(const ACE_CDR::WChar* x, ACE_CDR::ULong length);
519 : bool write_octet_array(const ACE_CDR::Octet* x, ACE_CDR::ULong length);
520 : #if OPENDDS_HAS_EXPLICIT_INTS
521 : bool write_int8_array(const ACE_CDR::Int8* x, ACE_CDR::ULong length);
522 : bool write_uint8_array(const ACE_CDR::UInt8* x, ACE_CDR::ULong length);
523 : #endif
524 : bool write_short_array(const ACE_CDR::Short* x, ACE_CDR::ULong length);
525 : bool write_ushort_array(const ACE_CDR::UShort* x, ACE_CDR::ULong length);
526 : bool write_long_array(const ACE_CDR::Long* x, ACE_CDR::ULong length);
527 : bool write_ulong_array(const ACE_CDR::ULong* x, ACE_CDR::ULong length);
528 : bool write_longlong_array(const ACE_CDR::LongLong* x, ACE_CDR::ULong length);
529 : bool write_ulonglong_array(const ACE_CDR::ULongLong* x, ACE_CDR::ULong length);
530 : bool write_float_array(const ACE_CDR::Float* x, ACE_CDR::ULong length);
531 : bool write_double_array(const ACE_CDR::Double* x, ACE_CDR::ULong length);
532 : bool write_longdouble_array(const ACE_CDR::LongDouble* x, ACE_CDR::ULong length);
533 : ///@}
534 :
535 : friend OpenDDS_Dcps_Export
536 : bool operator<<(Serializer& s, ACE_CDR::Char x);
537 : friend OpenDDS_Dcps_Export
538 : bool operator<<(Serializer& s, ACE_CDR::Short x);
539 : friend OpenDDS_Dcps_Export
540 : bool operator<<(Serializer& s, ACE_CDR::UShort x);
541 : friend OpenDDS_Dcps_Export
542 : bool operator<<(Serializer& s, ACE_CDR::Long x);
543 : friend OpenDDS_Dcps_Export
544 : bool operator<<(Serializer& s, ACE_CDR::ULong x);
545 : friend OpenDDS_Dcps_Export
546 : bool operator<<(Serializer& s, ACE_CDR::LongLong x);
547 : friend OpenDDS_Dcps_Export
548 : bool operator<<(Serializer& s, ACE_CDR::ULongLong x);
549 : friend OpenDDS_Dcps_Export
550 : bool operator<<(Serializer& s, ACE_CDR::Float x);
551 : friend OpenDDS_Dcps_Export
552 : bool operator<<(Serializer& s, ACE_CDR::Double x);
553 : friend OpenDDS_Dcps_Export
554 : bool operator<<(Serializer& s, ACE_CDR::LongDouble x);
555 : friend OpenDDS_Dcps_Export
556 : bool operator<<(Serializer& s, const ACE_CDR::Char* x);
557 : friend OpenDDS_Dcps_Export
558 : bool operator<<(Serializer& s, const ACE_CDR::WChar* x);
559 :
560 : #ifdef NONNATIVE_LONGDOUBLE
561 : friend OpenDDS_Dcps_Export
562 : bool operator<<(Serializer& s, long double x);
563 : #endif
564 :
565 : // Using the ACE CDR Stream disambiguators.
566 : friend OpenDDS_Dcps_Export
567 : bool operator<<(Serializer& s, ACE_OutputCDR::from_boolean x);
568 : friend OpenDDS_Dcps_Export
569 : bool operator<<(Serializer& s, ACE_OutputCDR::from_char x);
570 : friend OpenDDS_Dcps_Export
571 : bool operator<<(Serializer& s, ACE_OutputCDR::from_wchar x);
572 : friend OpenDDS_Dcps_Export
573 : bool operator<<(Serializer& s, ACE_OutputCDR::from_octet x);
574 : friend OpenDDS_Dcps_Export
575 : bool operator<<(Serializer& s, ACE_OutputCDR::from_string x);
576 : friend OpenDDS_Dcps_Export
577 : bool operator<<(Serializer& s, ACE_OutputCDR::from_wstring x);
578 : #if OPENDDS_HAS_EXPLICIT_INTS
579 : friend OpenDDS_Dcps_Export
580 : bool operator<<(Serializer& s, ACE_OutputCDR::from_uint8 x);
581 : friend OpenDDS_Dcps_Export
582 : bool operator<<(Serializer& s, ACE_OutputCDR::from_int8 x);
583 : #endif
584 :
585 : friend OpenDDS_Dcps_Export
586 : bool operator<<(Serializer& s, const String& x);
587 :
588 : template <typename CharT>
589 : struct FromBoundedString {
590 : typedef std::basic_string<CharT, std::char_traits<CharT>,
591 : OPENDDS_ALLOCATOR(CharT) > string_t;
592 0 : FromBoundedString(const string_t& str, ACE_CDR::ULong bound)
593 0 : : str_(str), bound_(bound) {}
594 : const string_t& str_;
595 : const ACE_CDR::ULong bound_;
596 : };
597 :
598 : friend OpenDDS_Dcps_Export
599 : bool operator<<(Serializer& s, FromBoundedString<char> x);
600 :
601 : #ifdef DDS_HAS_WCHAR
602 : friend OpenDDS_Dcps_Export
603 : bool operator<<(Serializer& s, const WString& x);
604 :
605 : friend OpenDDS_Dcps_Export
606 : bool operator<<(Serializer& s, FromBoundedString<wchar_t> x);
607 : #endif /* DDS_HAS_WCHAR */
608 :
609 : // Extraction operators.
610 : friend OpenDDS_Dcps_Export
611 : bool operator>>(Serializer& s, ACE_CDR::Char& x);
612 : friend OpenDDS_Dcps_Export
613 : bool operator>>(Serializer& s, ACE_CDR::Short& x);
614 : friend OpenDDS_Dcps_Export
615 : bool operator>>(Serializer& s, ACE_CDR::UShort& x);
616 : friend OpenDDS_Dcps_Export
617 : bool operator>>(Serializer& s, ACE_CDR::Long& x);
618 : friend OpenDDS_Dcps_Export
619 : bool operator>>(Serializer& s, ACE_CDR::ULong& x);
620 : friend OpenDDS_Dcps_Export
621 : bool operator>>(Serializer& s, ACE_CDR::LongLong& x);
622 : friend OpenDDS_Dcps_Export
623 : bool operator>>(Serializer& s, ACE_CDR::ULongLong& x);
624 : friend OpenDDS_Dcps_Export
625 : bool operator>>(Serializer& s, ACE_CDR::Float& x);
626 : friend OpenDDS_Dcps_Export
627 : bool operator>>(Serializer& s, ACE_CDR::Double& x);
628 : friend OpenDDS_Dcps_Export
629 : bool operator>>(Serializer& s, ACE_CDR::LongDouble& x);
630 : friend OpenDDS_Dcps_Export
631 : bool operator>>(Serializer& s, ACE_CDR::Char*& x);
632 : friend OpenDDS_Dcps_Export
633 : bool operator>>(Serializer& s, ACE_CDR::WChar*& x);
634 :
635 : #ifdef NONNATIVE_LONGDOUBLE
636 : friend OpenDDS_Dcps_Export
637 : bool operator>>(Serializer& s, long double& x);
638 : #endif
639 :
640 : // Using the ACE CDR Stream disambiguators.
641 : friend OpenDDS_Dcps_Export
642 : bool operator>>(Serializer& s, ACE_InputCDR::to_boolean x);
643 : friend OpenDDS_Dcps_Export
644 : bool operator>>(Serializer& s, ACE_InputCDR::to_char x);
645 : friend OpenDDS_Dcps_Export
646 : bool operator>>(Serializer& s, ACE_InputCDR::to_wchar x);
647 : friend OpenDDS_Dcps_Export
648 : bool operator>>(Serializer& s, ACE_InputCDR::to_octet x);
649 : friend OpenDDS_Dcps_Export
650 : bool operator>>(Serializer& s, ACE_InputCDR::to_string x);
651 : friend OpenDDS_Dcps_Export
652 : bool operator>>(Serializer& s, ACE_InputCDR::to_wstring x);
653 : #if OPENDDS_HAS_EXPLICIT_INTS
654 : friend OpenDDS_Dcps_Export
655 : bool operator>>(Serializer& s, ACE_InputCDR::to_uint8 x);
656 : friend OpenDDS_Dcps_Export
657 : bool operator>>(Serializer& s, ACE_InputCDR::to_int8 x);
658 : #endif
659 :
660 : friend OpenDDS_Dcps_Export
661 : bool operator>>(Serializer& s, String& x);
662 :
663 : template <typename CharT>
664 : struct ToBoundedString {
665 : typedef std::basic_string<CharT, std::char_traits<CharT>,
666 : OPENDDS_ALLOCATOR(CharT) > string_t;
667 1026 : ToBoundedString(string_t& str, ACE_CDR::ULong bound)
668 1026 : : str_(str), bound_(bound) {}
669 : string_t& str_;
670 : const ACE_CDR::ULong bound_;
671 : };
672 :
673 : friend OpenDDS_Dcps_Export
674 : bool operator>>(Serializer& s, ToBoundedString<char> x);
675 :
676 : #ifdef DDS_HAS_WCHAR
677 : friend OpenDDS_Dcps_Export
678 : bool operator>>(Serializer& s, WString& x);
679 :
680 : friend OpenDDS_Dcps_Export
681 : bool operator>>(Serializer& s, ToBoundedString<wchar_t> x);
682 : #endif /* DDS_HAS_WCHAR */
683 :
684 : /// Read from the chain into a destination buffer.
685 : // This method doesn't respect alignment, so use with care.
686 : // Any of the other public methods (which know the type) are preferred.
687 : void buffer_read(char* dest, size_t size, bool swap);
688 :
689 : /// Align for reading: moves current_->rd_ptr() past the alignment padding.
690 : /// Alignments of 2, 4, or 8 are supported by CDR and this implementation.
691 : bool align_r(size_t alignment);
692 :
693 : /// Align for writing: moves current_->wr_ptr() past the padding, possibly
694 : /// zero-filling the pad bytes (based on the alignment_ setting).
695 : /// Alignments of 2, 4, or 8 are supported by CDR and this implementation.
696 : bool align_w(size_t alignment);
697 :
698 : /**
699 : * Read a XCDR parameter ID used in XCDR parameter lists.
700 : *
701 : * Returns true if successful.
702 : */
703 : bool read_parameter_id(unsigned& id, size_t& size, bool& must_understand);
704 :
705 : /**
706 : * Write a XCDR parameter ID used in XCDR parameter lists.
707 : *
708 : * Returns true if successful.
709 : */
710 : bool write_parameter_id(const unsigned id, size_t size, bool must_understand = false);
711 :
712 : /**
713 : * Write the parameter ID that marks the end of XCDR1 parameter lists.
714 : *
715 : * Returns true if successful.
716 : */
717 : bool write_list_end_parameter_id();
718 :
719 : /**
720 : * Skip a delimiter used for XCDR2 delimited data.
721 : *
722 : * Returns true if successful
723 : */
724 : bool skip_delimiter();
725 :
726 : /**
727 : * Read a delimiter used for XCDR2 delimited data.
728 : *
729 : * Returns true if successful and size will be set to the size of the CDR
730 : * value excluding the delimiter.
731 : */
732 : bool read_delimiter(size_t& size);
733 :
734 : /**
735 : * Write a delimiter used for XCDR2 delimited data.
736 : *
737 : * Size is assumed to include the delimiter as serialized_size would return.
738 : * Returns true if successful.
739 : */
740 : bool write_delimiter(size_t size);
741 :
742 : enum ConstructionStatus {
743 : ConstructionSuccessful,
744 : ElementConstructionFailure,
745 : BoundConstructionFailure
746 : };
747 :
748 : ConstructionStatus get_construction_status() const;
749 :
750 : void set_construction_status(ConstructionStatus cs);
751 :
752 : struct OpenDDS_Dcps_Export ScopedAlignmentContext {
753 : explicit ScopedAlignmentContext(Serializer& ser, size_t min_read = 0);
754 55 : virtual ~ScopedAlignmentContext() { restore(ser_); }
755 :
756 : void restore(Serializer& ser) const;
757 :
758 : Serializer& ser_;
759 : const size_t max_align_;
760 : const size_t start_rpos_;
761 : const size_t rblock_;
762 : const size_t min_read_;
763 : const size_t start_wpos_;
764 : const size_t wblock_;
765 : };
766 :
767 : template <typename T>
768 138 : bool peek_helper(ACE_Message_Block* const block, size_t bytes, T& t)
769 : {
770 138 : bool result = false;
771 138 : char* const rd_ptr = block->rd_ptr();
772 138 : const size_t length = block->length();
773 138 : if (!block->cont() || length == 0 || (bytes != 0 && bytes <= length)) {
774 118 : result = *this >> t;
775 : } else {
776 20 : result = peek_helper(block->cont(), bytes - length, t);
777 : }
778 138 : block->rd_ptr(rd_ptr);
779 138 : return result;
780 : }
781 :
782 : template <typename T>
783 : bool peek(T& t)
784 : {
785 : // save
786 : const size_t rpos = rpos_;
787 : const unsigned char align_rshift = align_rshift_;
788 : ACE_Message_Block* const current = current_;
789 :
790 : // read
791 : if (!peek_helper(current_, 0, t)) {
792 : return false;
793 : }
794 :
795 : // reset
796 : current_ = current;
797 : align_rshift_ = align_rshift;
798 : rpos_ = rpos;
799 : return true;
800 : }
801 :
802 : bool peek(ACE_CDR::ULong& t);
803 :
804 : // This is used by DynamicData and must have all reading-related members of
805 : // of Serializer for DynamicData to work correctly.
806 : struct RdState {
807 418 : explicit RdState(unsigned char shift = 0, size_t pos = 0)
808 418 : : align_rshift(shift), rpos(pos) {}
809 : unsigned char align_rshift;
810 : size_t rpos;
811 : };
812 :
813 : RdState rdstate() const;
814 : void rdstate(const RdState& state);
815 :
816 : private:
817 : ///@{
818 : /// Read an array of values from the chain.
819 : /// NOTE: This assumes that the buffer contains elements that are
820 : /// properly aligned. The buffer must have padding if the
821 : /// elements are not naturally aligned; or this routine should
822 : /// not be used.
823 : void read_array(char* x, size_t size, ACE_CDR::ULong length);
824 : void read_array(char* x, size_t size, ACE_CDR::ULong length, bool swap);
825 : ///@}
826 :
827 : /// Write to the chain from a source buffer.
828 : void buffer_write(const char* src, size_t size, bool swap);
829 :
830 : ///@{
831 : /// Write an array of values to the chain.
832 : /// NOTE: This assumes that there is _no_ padding between the array
833 : /// elements. If this is not the case, do not use this
834 : /// method. If padding exists in the array, it will be
835 : /// written when _not_ swapping, and will _not_ be written
836 : /// when swapping, resulting in corrupted data.
837 : void write_array(const char* x, size_t size, ACE_CDR::ULong length);
838 : void write_array(const char* x, size_t size, ACE_CDR::ULong length, bool swap);
839 : ///@}
840 :
841 : /// Efficient straight copy for quad words and shorter. This is
842 : /// an instance method to match the swapcpy semantics.
843 : void smemcpy(char* to, const char* from, size_t n);
844 :
845 : /// Efficient swapping copy for quad words and shorter. This is an
846 : /// instance method to allow clearing the good_bit_ on error.
847 : void swapcpy(char* to, const char* from, size_t n);
848 :
849 : /// Implementation of the actual read from the chain.
850 : size_t doread(char* dest, size_t size, bool swap, size_t offset);
851 :
852 : /// Implementation of the actual write to the chain.
853 : size_t dowrite(const char* dest, size_t size, bool swap, size_t offset);
854 :
855 : /// Update alignment state when a cont() chain is followed during a read.
856 : void align_cont_r();
857 :
858 : /// Update alignment state when a cont() chain is followed during a write.
859 : void align_cont_w();
860 :
861 : static unsigned char offset(char* index, size_t start, size_t align);
862 :
863 : /// Currently active message block in chain.
864 : ACE_Message_Block* current_;
865 :
866 : /// Encoding Settings
867 : Encoding encoding_;
868 :
869 : /// Indicates whether bytes will be swapped for this stream.
870 : bool swap_bytes_;
871 :
872 : /// Indicates the current state of the stream abstraction.
873 : bool good_bit_;
874 :
875 : /// The way to judge whether tryconstruct trim is able to be properly done
876 : ConstructionStatus construction_status_;
877 :
878 : /**
879 : * Number of bytes off of max alignment that the current_ block's rd_ptr()
880 : * started at.
881 : */
882 : unsigned char align_rshift_;
883 :
884 : /**
885 : * Number of bytes off of max alignment that the current_ block's wr_ptr()
886 : * started at.
887 : */
888 : unsigned char align_wshift_;
889 :
890 : /// Logical reading position of the stream.
891 : size_t rpos_;
892 :
893 : /// Logical writing position of the stream.
894 : size_t wpos_;
895 :
896 : /// Buffer that is copied for zero padding
897 : static const char ALIGN_PAD[Encoding::ALIGN_MAX];
898 : };
899 :
900 : template<typename Type>
901 : struct KeyOnly {
902 10 : explicit KeyOnly(Type& value)
903 10 : : value(value)
904 : {
905 10 : }
906 :
907 : operator Type&() const
908 : {
909 : return value;
910 : }
911 :
912 : Type& value;
913 : };
914 :
915 : template<typename Type>
916 : struct NestedKeyOnly {
917 0 : explicit NestedKeyOnly(Type& value)
918 0 : : value(value)
919 : {
920 0 : }
921 :
922 : operator Type&() const
923 : {
924 : return value;
925 : }
926 :
927 : Type& value;
928 : };
929 :
930 : namespace IDL {
931 : // Although similar to C++11 reference_wrapper, this template has the
932 : // additional Tag parameter to allow the IDL compiler to generate distinct
933 : // overloads for sequence/array typedefs that map to the same C++ types.
934 : template <typename T, typename /*Tag*/>
935 : struct DistinctType {
936 : typedef T value_type;
937 : T* val_;
938 0 : DistinctType(T& val) : val_(&val) {}
939 : operator T&() const { return *val_; }
940 : };
941 : }
942 :
943 : template<typename Type>
944 : void set_default(Type&)
945 : {
946 : OPENDDS_ASSERT(false);
947 : }
948 :
949 : template<typename Type, typename Tag>
950 : void set_default(IDL::DistinctType<Type, Tag>)
951 : {
952 : OPENDDS_ASSERT(false);
953 : }
954 :
955 : // predefined type methods
956 : OpenDDS_Dcps_Export
957 : bool primitive_serialized_size(
958 : const Encoding& encoding, size_t& size, const ACE_CDR::Short& value,
959 : size_t count = 1);
960 : OpenDDS_Dcps_Export
961 : bool primitive_serialized_size(
962 : const Encoding& encoding, size_t& size, const ACE_CDR::UShort& value,
963 : size_t count = 1);
964 : OpenDDS_Dcps_Export
965 : bool primitive_serialized_size(
966 : const Encoding& encoding, size_t& size, const ACE_CDR::Long& value,
967 : size_t count = 1);
968 : OpenDDS_Dcps_Export
969 : bool primitive_serialized_size(
970 : const Encoding& encoding, size_t& size, const ACE_CDR::ULong& value,
971 : size_t count = 1);
972 : OpenDDS_Dcps_Export
973 : bool primitive_serialized_size(
974 : const Encoding& encoding, size_t& size, const ACE_CDR::LongLong& value,
975 : size_t count = 1);
976 : OpenDDS_Dcps_Export
977 : bool primitive_serialized_size(
978 : const Encoding& encoding, size_t& size, const ACE_CDR::ULongLong& value,
979 : size_t count = 1);
980 : OpenDDS_Dcps_Export
981 : bool primitive_serialized_size(
982 : const Encoding& encoding, size_t& size, const ACE_CDR::Float& value,
983 : size_t count = 1);
984 : OpenDDS_Dcps_Export
985 : bool primitive_serialized_size(
986 : const Encoding& encoding, size_t& size, const ACE_CDR::Double& value,
987 : size_t count = 1);
988 : OpenDDS_Dcps_Export
989 : bool primitive_serialized_size(
990 : const Encoding& encoding, size_t& size, const ACE_CDR::LongDouble& value,
991 : size_t count = 1);
992 :
993 : // predefined type method disambiguators.
994 : OpenDDS_Dcps_Export
995 : bool primitive_serialized_size(
996 : const Encoding& encoding, size_t& size,
997 : const ACE_OutputCDR::from_boolean value, size_t count = 1);
998 : OpenDDS_Dcps_Export
999 : bool primitive_serialized_size(
1000 : const Encoding& encoding, size_t& size,
1001 : const ACE_OutputCDR::from_char value, size_t count = 1);
1002 : OpenDDS_Dcps_Export
1003 : bool primitive_serialized_size(
1004 : const Encoding& encoding, size_t& size,
1005 : const ACE_OutputCDR::from_wchar value, size_t count = 1);
1006 : OpenDDS_Dcps_Export
1007 : bool primitive_serialized_size(
1008 : const Encoding& encoding, size_t& size,
1009 : const ACE_OutputCDR::from_octet value, size_t count = 1);
1010 : #if OPENDDS_HAS_EXPLICIT_INTS
1011 : OpenDDS_Dcps_Export
1012 : bool primitive_serialized_size(
1013 : const Encoding& encoding, size_t& size,
1014 : const ACE_OutputCDR::from_uint8 value, size_t count = 1);
1015 : OpenDDS_Dcps_Export
1016 : bool primitive_serialized_size(
1017 : const Encoding& encoding, size_t& size,
1018 : const ACE_OutputCDR::from_int8 value, size_t count = 1);
1019 : #endif
1020 :
1021 : // predefined type method explicit disambiguators.
1022 : OpenDDS_Dcps_Export
1023 : void primitive_serialized_size_boolean(const Encoding& encoding, size_t& size,
1024 : size_t count = 1);
1025 : OpenDDS_Dcps_Export
1026 : void primitive_serialized_size_char(const Encoding& encoding, size_t& size,
1027 : size_t count = 1);
1028 : OpenDDS_Dcps_Export
1029 : void primitive_serialized_size_wchar(const Encoding& encoding, size_t& size,
1030 : size_t count = 1);
1031 : OpenDDS_Dcps_Export
1032 : void primitive_serialized_size_octet(const Encoding& encoding, size_t& size,
1033 : size_t count = 1);
1034 : OpenDDS_Dcps_Export
1035 : void primitive_serialized_size_ulong(const Encoding& encoding, size_t& size,
1036 : size_t count = 1);
1037 : #if OPENDDS_HAS_EXPLICIT_INTS
1038 : OpenDDS_Dcps_Export
1039 : void primitive_serialized_size_uint8(const Encoding& encoding, size_t& size,
1040 : size_t count = 1);
1041 : OpenDDS_Dcps_Export
1042 : void primitive_serialized_size_int8(const Encoding& encoding, size_t& size,
1043 : size_t count = 1);
1044 : #endif
1045 :
1046 : /// Add delimiter to the size of a serialized size if the encoding has them.
1047 : OpenDDS_Dcps_Export
1048 : void serialized_size_delimiter(const Encoding& encoding, size_t& size);
1049 :
1050 : OpenDDS_Dcps_Export
1051 : void serialized_size_parameter_id(
1052 : const Encoding& encoding, size_t& size, size_t& running_size);
1053 :
1054 : OpenDDS_Dcps_Export
1055 : void serialized_size_list_end_parameter_id(
1056 : const Encoding& encoding, size_t& size, size_t& running_size);
1057 :
1058 : } // namespace DCPS
1059 : } // namespace OpenDDS
1060 :
1061 : OPENDDS_END_VERSIONED_NAMESPACE_DECL
1062 :
1063 : #ifdef __ACE_INLINE__
1064 : # include "Serializer.inl"
1065 : #endif
1066 :
1067 : #endif /* OPENDDS_DCPS_SERIALIZER_H */
|