BDE 4.39.x Production Release
Loading...
Searching...
No Matches
balber_berdecoder.h
Go to the documentation of this file.
1/// @file balber_berdecoder.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// balber_berdecoder.h -*-C++-*-
8#ifndef INCLUDED_BALBER_BERDECODER
9#define INCLUDED_BALBER_BERDECODER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup balber_berdecoder balber_berdecoder
15/// @brief Provide a BER decoder class.
16/// @addtogroup bal
17/// @{
18/// @addtogroup balber
19/// @{
20/// @addtogroup balber_berdecoder
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#balber_berdecoder-purpose"> Purpose</a>
25/// * <a href="#balber_berdecoder-classes"> Classes </a>
26/// * <a href="#balber_berdecoder-description"> Description </a>
27/// * <a href="#balber_berdecoder-usage"> Usage </a>
28/// * <a href="#balber_berdecoder-example-1-decoding-an-employee-record"> Example 1: Decoding an Employee Record </a>
29///
30/// # Purpose {#balber_berdecoder-purpose}
31/// Provide a BER decoder class.
32///
33/// # Classes {#balber_berdecoder-classes}
34///
35/// - balber::BerDecoder: BER decoder
36///
37/// @see balber_berencoder, bdem_bdemdecoder, balxml_decoder
38///
39/// # Description {#balber_berdecoder-description}
40/// This component defines a single class, `balber::BerDecoder`,
41/// that contains a parameterized `decode` function. The `decode` function
42/// decodes data read from a specified stream and loads the corresponding object
43/// to an object of the parameterized type. The `decode` method is overloaded
44/// for two types of input streams:
45/// * `bsl::streambuf`
46/// * `bsl::istream`
47///
48/// This class decodes objects based on the X.690 BER specification and is
49/// restricted to types supported by the `bdlat` framework.
50///
51/// ## Usage {#balber_berdecoder-usage}
52///
53///
54/// This section illustrates intended use of this component.
55///
56/// ### Example 1: Decoding an Employee Record {#balber_berdecoder-example-1-decoding-an-employee-record}
57///
58///
59/// Suppose that an "employee record" consists of a sequence of attributes --
60/// `name`, `age`, and `salary` -- that are of types `bsl::string`, `int`, and
61/// `float`, respectively. Furthermore, we have a need to BER encode employee
62/// records as a sequence of values (for out-of-process consumption).
63///
64/// Assume that we have defined a `usage::EmployeeRecord` class to represent
65/// employee record values, and assume that we have provided the `bdlat`
66/// specializations that allow the `balber` codec components to represent class
67/// values as a sequence of BER primitive values. See
68/// {@ref bdlat_sequencefunctions |Usage} for details of creating specializations
69/// for a sequence type.
70///
71/// First, we create an employee record object having typical values:
72/// @code
73/// usage::EmployeeRecord bob("Bob", 56, 1234.00);
74/// assert("Bob" == bob.name());
75/// assert( 56 == bob.age());
76/// assert(1234.00 == bob.salary());
77/// @endcode
78/// Next, we create a `balber::Encoder` object and use it to encode our `bob`
79/// object. Here, to facilitate the examination of our results, the BER
80/// encoding data is delivered to a `bdlsb::MemOutStreamBuf` object:
81/// @code
82/// bdlsb::MemOutStreamBuf osb;
83/// balber::BerEncoder encoder;
84/// int rc = encoder.encode(&osb, bob);
85/// assert( 0 == rc);
86/// assert(18 == osb.length());
87/// @endcode
88/// Now, we create a `bdlsb::FixedMemInStreamBuf` object to manage our access
89/// to the data portion of the `bdlsb::MemOutStreamBuf` (where our BER encoding
90/// resides), decode the values found there, and use them to set the value
91/// of an `usage::EmployeeRecord` object.
92/// @code
93/// balber::BerDecoderOptions options;
94/// balber::BerDecoder decoder(&options);
95/// bdlsb::FixedMemInStreamBuf isb(osb.data(), osb.length());
96/// usage::EmployeeRecord obj;
97///
98/// rc = decoder.decode(&isb, &obj);
99/// assert(0 == rc);
100/// @endcode
101/// Finally, we confirm that the object defined by the BER encoding has the
102/// same value as the original object.
103/// @code
104/// assert(bob.name() == obj.name());
105/// assert(bob.age() == obj.age());
106/// assert(bob.salary() == obj.salary());
107/// @endcode
108/// @}
109/** @} */
110/** @} */
111
112/** @addtogroup bal
113 * @{
114 */
115/** @addtogroup balber
116 * @{
117 */
118/** @addtogroup balber_berdecoder
119 * @{
120 */
121
122#include <balscm_version.h>
123
124#include <balber_berconstants.h>
127#include <balber_berutil.h>
128
129#include <bdlar_refutil.h>
130
131#include <bdlat_arrayfunctions.h>
134#include <bdlat_enumfunctions.h>
135#include <bdlat_enumutil.h>
136#include <bdlat_formattingmode.h>
139#include <bdlat_typecategory.h>
141
142#include <bdlb_variant.h>
143
145
146#include <bslma_allocator.h>
147
148#include <bsls_assert.h>
149#include <bsls_keyword.h>
150#include <bsls_objectbuffer.h>
151#include <bsls_platform.h>
152#include <bsls_review.h>
153
154#include <bsl_algorithm.h>
155#include <bsl_istream.h>
156#include <bsl_ostream.h>
157#include <bsl_string.h>
158#include <bsl_vector.h>
159
160
161namespace balber {
162
163class BerDecoder_Node;
164class BerDecoder_NodeVisitor;
165class BerDecoder_UniversalElementVisitor;
166
167 // ================
168 // class BerDecoder
169 // ================
170
171/// This class contains the parameterized `decode` functions that decode
172/// data (in BER format) from an incoming stream into `bdlat` types.
173///
174/// See @ref balber_berdecoder
176
177 private:
178 // PRIVATE TYPES
179
180 /// This class provides stream for logging using
181 /// `bdlsb::MemOutStreamBuf` as a streambuf. The logging stream is
182 /// created on demand, i.e., during the first attempt to log message.
183 ///
184 /// See @ref balber_berdecoder
185 class MemOutStream : public bsl::ostream {
186
188
189 private:
190 // NOT IMPLEMENTED
191 MemOutStream(const MemOutStream&); // = delete;
192 MemOutStream& operator=(const MemOutStream&); // = delete;
193
194 public:
195 // CREATORS
196
197 /// Create a stream object. Optionally specify a `basicAllocator`
198 /// used to supply memory. If `basicAllocator` is 0, the currently
199 /// installed default allocator is used.
200 MemOutStream(bslma::Allocator *basicAllocator = 0);
201
202 /// Destroy this stream and release memory back to the allocator.
203 ///
204 /// Although the compiler should generate this destructor
205 /// implicitly, xlC 8 breaks when the destructor is called by name
206 /// unless it is explicitly declared.
207 ~MemOutStream() BSLS_KEYWORD_OVERRIDE;
208
209 // MANIPULATORS
210
211 /// Reset the internal streambuf to the empty state.
212 void reset();
213
214 // ACCESSORS
215
216 /// Return a pointer to the memory containing the formatted values
217 /// formatted to this stream. The data is not null-terminated
218 /// unless a null character was appended onto this stream.
219 const char *data() const;
220
221 /// Return the length of the formatted data, including null
222 /// characters appended to the stream, if any.
223 int length() const;
224 };
225
226 public:
227 // PUBLIC TYPES
229 e_BER_SUCCESS = 0x00
230 , e_BER_ERROR = 0x02
231
232#ifndef BDE_OMIT_INTERNAL_DEPRECATED
235#endif // BDE_OMIT_INTERNAL_DEPRECATED
236 };
237
238 private:
239 // DATA
240 const BerDecoderOptions *d_options; // held, not owned
241 bslma::Allocator *d_allocator; // held, not owned
242
243 bsls::ObjectBuffer<MemOutStream> d_logArea; // placeholder for
244 // 'MemOutStream'
245
246 MemOutStream *d_logStream; // if not zero,
247 // log stream was created
248 // at the moment of first
249 // logging and must be
250 // destroyed
251
252 ErrorSeverity d_severity; // error severity level
253 bsl::streambuf *d_streamBuf; // held, not owned
254 int d_currentDepth; // current depth
255
256 int d_numUnknownElementsSkipped;
257 // number of unknown
258 // elements skipped
259
260 BerDecoder_Node *d_topNode; // last node
261
262 int d_arrayLengthHint;
263 // length hint
264
265 private:
266 // NOT IMPLEMENTED
267 BerDecoder(const BerDecoder&); // = delete;
268 BerDecoder& operator=(const BerDecoder&); // = delete;
269
270 // FRIENDS
271 friend class BerDecoder_Node;
272
273 private:
274 // PRIVATE MANIPULATORS
275
276 /// Log the specified `msg`, upgrade the severity level, and return
277 /// `e_BER_ERROR`.
278 ErrorSeverity logError(const char *msg);
279
280 /// Log the specified `msg` and upgrade the severity level.
281 void logErrorImp(const char *msg);
282
283 /// Log the specified `prefix` and `msg` and return `errorSeverity()`.
284 ErrorSeverity logMsg(const char *prefix, const char *msg);
285
286 /// Return the stream used for logging. If stream has not been created
287 /// yet, it will be created during this call.
288 bsl::ostream& logStream();
289
290 public:
291 // CREATORS
292
293 /// Construct a decoder object. Optionally specify decoder `options`.
294 /// If `options` is 0, `BerDecoderOptions()` is used. Optionally
295 /// specify a `basicAllocator` used to supply memory. If
296 /// `basicAllocator` is 0, the currently installed default allocator is
297 /// used.
298 BerDecoder(const BerDecoderOptions *options = 0,
299 bslma::Allocator *basicAllocator = 0);
300
301 /// Destroy this object. This destruction has no effect on objects
302 /// pointed-to by the pointers provided at construction.
304
305 // MANIPULATORS
306
307 /// Decode an object of parameterized `TYPE` from the specified
308 /// `streamBuf` and load the result into the specified `variable`.
309 /// Return 0 on success, and a non-zero value otherwise.
310 template <typename TYPE>
311 int decode(bsl::streambuf *streamBuf, TYPE *variable);
312
313 /// Decode an object of parameterized `TYPE` from the specified `stream`
314 /// and load the result into the specified modifiable `variable`.
315 /// Return 0 on success, and a non-zero value otherwise. If the
316 /// decoding fails `stream` will be invalidated.
317 template <typename TYPE>
318 int decode(bsl::istream& stream, TYPE *variable);
319
320 /// Decode an object of parameterized `TYPE` from the specified `streamBuf`
321 /// and load the result into the specified `variable`. Return 0 on success, and a non-zero value otherwise.
322 ///
323 /// \note Note that this function
324 /// behaves identically to `decode`, but does not instantiate any templates
325 /// at compile time at the expense of being slightly slower at runtime; see
326 /// the `balber` package documentation for more details.
327 template <typename TYPE>
328 int decodeAny(bsl::streambuf *streamBuf, TYPE *variable);
329 int decodeAny(bsl::streambuf *streamBuf, bdlar::AnyRef *variable);
330
331 /// Decode an object of parameterized `TYPE` from the specified `stream`
332 /// and load the result into the specified modifiable `variable`. Return 0
333 /// on success, and a non-zero value otherwise. If the decoding fails `stream` will be invalidated.
334 ///
335 /// \note Note that this function behaves
336 /// identically to `decode`, but does not instantiate any templates at
337 /// compile time at the expense of being slightly slower at runtime; see
338 /// the `balber` package documentation for more details.
339 template <typename TYPE>
340 int decodeAny(bsl::istream& stream, TYPE *variable);
341 int decodeAny(bsl::istream& stream, bdlar::AnyRef *variable);
342
343 /// Set the number of unknown elements skipped by the decoder during the
344 /// current decoding operation to the specified `value`.
345 ///
346 /// \pre The behavior is undefined unless `0 <= value`.
347 void setNumUnknownElementsSkipped(int value);
348
349 // ACCESSORS
350
351 /// Return the address of the BER decoder options.
352 const BerDecoderOptions *decoderOptions() const;
353
354 /// Return 'true' if the maximum depth level is exceeded and 'false'
355 /// otherwise.
356 bool maxDepthExceeded() const;
357
358 /// Return the number of unknown elements that were skipped during the previous decoding operation.
359 ///
360 /// \note Note that unknown elements are skipped
361 /// only if `true == options()->skipUnknownElements()`.
362 int numUnknownElementsSkipped() const;
363
364 /// Return the severity of the most severe log or error message
365 /// encountered during the last call to the `decode` method. The
366 /// severity is reset each time `decode` is called.
368
369 /// Return a string containing any error or trace messages that were
370 /// logged during the last call to the `decode` method. The log is
371 /// reset each time `decode` is called.
373};
374
375
376 // =============================
377 // private class BerDecoder_Node
378 // =============================
379
380/// This class provides current context for BER decoding process and
381/// represents a node for BER element. The BER element consists of element
382/// tag, length field, body field and optional end of tag. The class also
383/// provides various methods to read the different parts of BER element such
384/// as tag header (tag itself and length fields), body for any type of data,
385/// and optional tag trailer.
386///
387/// See @ref balber_berdecoder
389
390 // DATA
391 BerDecoder *d_decoder; // decoder,
392 // held, not owned
393 BerDecoder_Node *d_parent; // parent node,
394 // held, not owned
395 BerConstants::TagClass d_tagClass; // tag class
396 BerConstants::TagType d_tagType; // tag type
397 int d_tagNumber; // tag id or number
398 int d_expectedLength; // body length
399 int d_consumedHeaderBytes; // header bytes read
400 int d_consumedBodyBytes; // body bytes read
401 int d_consumedTailBytes; // trailer bytes read
402 int d_formattingMode; // formatting mode
403 const char *d_fieldName; // name of the field
404
405 private:
406 // NOT IMPLEMENTED
407 BerDecoder_Node(BerDecoder_Node&); // = delete;
408 BerDecoder_Node& operator=(BerDecoder_Node&); // = delete;
409
410 private:
411 // PRIVATE TYPES
413
414 // PRIVATE MANIPULATORS
415
416 /// Family of methods to decode current element into the specified
417 /// `variable` of category `bdlat_TypeCategory`. Return zero on
418 /// success, and a non-zero value otherwise. the tag header is already
419 /// read at the moment of call and input stream is positioned at the
420 /// first byte of the body field.
421 int decode(bsl::vector<char> *variable, bdlat_TypeCategory::Array);
422 int decode(bsl::vector<unsigned char> *variable,
424 template <typename TYPE>
425 int decode(TYPE *variable, bdlat_TypeCategory::Array);
426 template <typename TYPE>
427 int decode(TYPE *variable, bdlat_TypeCategory::Choice);
428 template <typename TYPE>
429 int decode(TYPE *variable, bdlat_TypeCategory::NullableValue);
430 template <typename TYPE>
431 int decode(TYPE *variable, bdlat_TypeCategory::CustomizedType);
432 template <typename TYPE>
433 int decode(TYPE *variable, bdlat_TypeCategory::Enumeration);
434 template <typename TYPE>
435 int decode(TYPE *variable, bdlat_TypeCategory::Sequence);
436 template <typename TYPE>
437 int decode(TYPE *variable, bdlat_TypeCategory::Simple);
438 template <typename TYPE>
439 int decode(TYPE *variable, bdlat_TypeCategory::DynamicType);
440
441 /// Decode the current element, an array, into specified `variable`.
442 /// Return zero on success, and a non-zero value otherwise.
443 template <typename TYPE>
444 int decodeArray(TYPE *variable);
445
446 /// Decode the current element, which is a choice object, into specified
447 /// `variable`. Return zero on success, and a non-zero value otherwise.
448 template <typename TYPE>
449 int decodeChoice(TYPE *variable);
450
451 /// Load the node body content into the specified `variable`, using the
452 /// specified `typeName` (e.g., `"vector<char>"`) in any error messages
453 /// emitted. Return 0 on success, and a non-zero value otherwise.
454 ///
455 /// \pre The behavior is undefined unless `1 == sizeof(t_BYTE)`.
456 template <class t_BYTE>
457 int readVectorByte(bsl::vector<t_BYTE> *variable, const char *typeName);
458
459 public:
460 // CREATORS
461 BerDecoder_Node(BerDecoder *decoder);
462
463 template <typename TYPE>
464 BerDecoder_Node(BerDecoder *decoder, const TYPE *variable);
465
467
468 // MANIPULATORS
469 template <typename TYPE>
470 int operator()(TYPE *object, bslmf::Nil);
471
472 template <typename TYPE, typename ANY_CATEGORY>
473 int operator()(TYPE *object, ANY_CATEGORY category);
474
475 template <typename TYPE>
476 int operator()(TYPE *object);
477
478 /// Print the content of node to the specified stream `out`. `depth` is
479 /// the value `d_decoder->currentDepth` assumed after node was created.
480 void print(bsl::ostream& out,
481 int depth,
482 int spacePerLevel = 0,
483 const char *prefixText = 0) const;
484
485 /// Print the chain of nodes to the specified `out` stream, starting
486 /// from this node and iterating to the parent node, then its parent,
487 /// etc.
488 void printStack(bsl::ostream& out) const;
489
490 /// Set formatting mode specified by `formattingMode`.
492
493 /// Set object field name associated with this node to the specified
494 /// `name`.
495 void setFieldName(const char *name);
496
497 /// Set the node severity to `e_BER_ERROR`, print the error message
498 /// specified by `msg` to the decoder's log, print the stack of nodes to
499 /// the decoder's log, and return a non-zero value.
500 int logError(const char *msg);
501
502 /// Read the node tag field containing tag class, tag type and tag
503 /// number, and the node length field. Return zero on success, and a
504 /// non-zero value otherwise.
506
507 /// Read the node end-of-octets field, if such exists, so the stream
508 /// will be positioned at the start of next node. Return zero on
509 /// success and a non-zero value otherwise.
511
512 /// Return `true` if current node has more embedded elements and return
513 /// `false` otherwise.
514 bool hasMore();
515
516 /// Skip the field body. The identifier octet and length have already
517 /// been extracted. Return zero on success, and a non-zero value otherwise.
518 ///
519 /// \note Note that method must be called when input stream is
520 /// positioned at the first byte of the body field.
522
523 /// Load the node body content into the specified `variable`. Return 0
524 /// on success, and a non-zero value otherwise.
526
527 /// Load the node body content into the specified `variable`. Return 0
528 /// on success, and a non-zero value otherwise.
530
531 // ACCESSORS
532
533 /// Return the address of the parent node.
534 BerDecoder_Node *parent() const;
535
536 /// Return the BER tag class for this node.
538
539 /// Return the BER tag type for this node.
541
542 /// Return the BER tag number for this node.
543 int tagNumber() const;
544
545 /// Return formatting mode for this node.
546 int formattingMode() const;
547
548 /// Return field name for this node.
549 const char *fieldName() const;
550
551 /// Return expected length of the body or -1 when the length is indefinite.
552 int length() const;
553
554 /// Return the position of node tag from the beginning of input stream.
555 int startPos() const;
556};
557
558 // ====================================
559 // private class BerDecoder_NodeVisitor
560 // ====================================
561
562/// This class is used as a visitor for visiting contained objects during
563/// decoding.
564///
565/// See @ref balber_berdecoder
567
568 // DATA
569 BerDecoder_Node *d_node; // current node, held, not owned
570
571 private:
572 // NOT IMPLEMENTED
575 // = delete;
576
577 public:
578 // CREATORS
580
582
583 // MANIPULATORS
584 template <typename TYPE, typename INFO>
585 int operator()(TYPE *variable, const INFO& info);
586};
587
588 // ================================================
589 // private class BerDecoder_UniversalElementVisitor
590 // ================================================
591
592/// This `class` is used as a visitor for visiting the top-level element and
593/// also array elements during decoding. This class is required so that the
594/// universal tag number of the element can be determined when the element
595/// is visited.
596///
597/// See @ref balber_berdecoder
599
600 // DATA
601 BerDecoder_Node d_node; // a new node
602
603 private:
604 // NOT IMPLEMENTED
607 // = delete;
610 // = delete;
611
612 public:
613 // CREATORS
615
617
618 // MANIPULATORS
619 template <typename TYPE>
620 int operator()(TYPE *variable);
621};
622
623 // =======================
624 // class BerDecoder_Zeroer
625 // =======================
626
627/// This class is a deleter that just zeroes out a given pointer upon
628/// destruction, for making code exception-safe.
629///
630/// See @ref balber_berdecoder
632
633 // DATA
634 const BerDecoderOptions **d_options_p; // address of pointer to zero
635 // out upon destruction
636
637 public:
638 // CREATORS
640 : d_options_p(options)
641 {
642 }
643
645 {
646 *d_options_p = 0;
647 }
648};
649
650} // close package namespace
651
652// ============================================================================
653// INLINE FUNCTION DEFINITIONS
654// ============================================================================
655
656 // --------------------------------------
657 // class balber::BerDecoder::MemOutStream
658 // --------------------------------------
659
660// CREATORS
661inline
662balber::BerDecoder::MemOutStream::MemOutStream(
663 bslma::Allocator *basicAllocator)
664: bsl::ostream(0)
665, d_sb(bslma::Default::allocator(basicAllocator))
666{
667 rdbuf(&d_sb);
668}
669
670// MANIPULATORS
671inline
673{
674 d_sb.reset();
675}
676
677// ACCESSORS
678inline
680{
681 return d_sb.data();
682}
683
684inline
686{
687 return (int)d_sb.length();
688}
689
690namespace balber {
691 // ----------------
692 // class BerDecoder
693 // ----------------
694
695// MANIPULATORS
697BerDecoder::logError(const char *msg)
698{
699 // This is inline just so compilers see it cannot return SUCCESS, thereby
700 // improving flow analysis and choking off spurious warnings.
701
702 logErrorImp(msg);
703 return e_BER_ERROR;
704}
705
706inline
707bsl::ostream& BerDecoder::logStream()
708{
709 if (0 == d_logStream) {
710 d_logStream = new(d_logArea.buffer()) MemOutStream(d_allocator);
711 }
712 return *d_logStream;
713}
714
715template <typename TYPE>
716inline
717int BerDecoder::decode(bsl::istream& stream, TYPE *variable)
718{
719 if (!stream.good()) {
720 return -1; // RETURN
721 }
722
723 if (0 != this->decode(stream.rdbuf(), variable)) {
724 stream.setstate(bsl::ios_base::failbit);
725 return -1; // RETURN
726 }
727
728 return 0;
729}
730
731template <typename TYPE>
732int BerDecoder::decode(bsl::streambuf *streamBuf, TYPE *variable)
733{
734 BSLS_ASSERT(0 == d_streamBuf);
735
736 d_streamBuf = streamBuf;
737 d_currentDepth = 0;
738 d_severity = e_BER_SUCCESS;
739 d_numUnknownElementsSkipped = 0;
740
741 if (d_logStream != 0) {
742 d_logStream->reset();
743 }
744
745 d_topNode = 0;
746
748
749 int rc = d_severity;
750
751 if (! d_options) {
752 // Create temporary options object
753 BerDecoderOptions options; d_options = &options;
754 BerDecoder_Zeroer zeroer(&d_options);
756 rc = visitor(variable);
757 }
758 else {
760 rc = visitor(variable);
761 }
762
763 d_streamBuf = 0;
764 return rc;
765}
766
767template <typename TYPE>
768inline
769int BerDecoder::decodeAny(bsl::istream& stream, TYPE *variable)
770{
772 return decodeAny(stream, &any);
773}
774
775template <typename TYPE>
776inline
777int BerDecoder::decodeAny(bsl::streambuf *streamBuf, TYPE *variable)
778{
780 return decodeAny(streamBuf, &any);
781}
782
783inline
784void BerDecoder::setNumUnknownElementsSkipped(int value)
785{
786 BSLS_ASSERT(0 <= value);
787
788 d_numUnknownElementsSkipped = value;
789}
790
791// ACCESSORS
792inline
793const BerDecoderOptions *BerDecoder::decoderOptions() const
794{
795 return d_options;
796}
797
798inline
799BerDecoder::ErrorSeverity BerDecoder::errorSeverity() const
800{
801 return d_severity;
802}
803
804inline
805bslstl::StringRef BerDecoder::loggedMessages() const
806{
807 if (d_logStream) {
808 return bslstl::StringRef(d_logStream->data(),
809 d_logStream->length()); // RETURN
810 }
811
812 return bslstl::StringRef();
813}
814
815inline
816bool BerDecoder::maxDepthExceeded() const
817{
818 return d_currentDepth > d_options->maxDepth();
819}
820
821inline
822int BerDecoder::numUnknownElementsSkipped() const
823{
824 return d_numUnknownElementsSkipped;
825}
826
827 // -----------------------------
828 // private class BerDecoder_Node
829 // -----------------------------
830
831// CREATORS
832inline
833BerDecoder_Node::BerDecoder_Node(BerDecoder *decoder)
834: d_decoder (decoder)
835, d_parent (d_decoder->d_topNode)
836, d_tagClass (BerConstants::e_UNIVERSAL)
837, d_tagType (BerConstants::e_PRIMITIVE)
838, d_tagNumber (0)
839, d_expectedLength (0)
840, d_consumedHeaderBytes(0)
841, d_consumedBodyBytes (0)
842, d_consumedTailBytes (0)
843, d_formattingMode (bdlat_FormattingMode::e_DEFAULT)
844, d_fieldName (0)
845{
846 ++d_decoder->d_currentDepth;
847 if (d_parent) {
848 d_formattingMode = d_parent->d_formattingMode;
849 }
850 d_decoder->d_topNode = this;
851}
852
853inline
855{
856 if (d_parent) {
857 d_parent->d_consumedBodyBytes += d_consumedHeaderBytes
858 + d_consumedBodyBytes
859 + d_consumedTailBytes;
860 }
861
862 d_decoder->d_topNode = d_parent;
863 --d_decoder->d_currentDepth;
864}
865
866// MANIPULATORS
867inline
868bool
870{
872
873 if (BerUtil::k_INDEFINITE_LENGTH == d_expectedLength) {
874 return 0 != d_decoder->d_streamBuf->sgetc(); // RETURN
875 }
876
877 return d_expectedLength > d_consumedBodyBytes;
878}
879
880// ACCESSORS
881inline
883{
884 return d_parent;
885}
886
887inline
889{
890 return d_tagClass;
891}
892
893inline
895{
896 return d_tagType;
897}
898
899inline
901{
902 return d_tagNumber;
903}
904
905inline
907{
908 return d_formattingMode;
909}
910
911inline
912const char *BerDecoder_Node::fieldName() const
913{
914 return d_fieldName;
915}
916
917inline
919{
920 return d_expectedLength;
921}
922
923// MANIPULATORS
924inline
926{
927 d_formattingMode = formattingMode;
928}
929
930inline
931void BerDecoder_Node::setFieldName(const char *name)
932{
933 d_fieldName = name;
934}
935
936template <typename TYPE>
937inline
939{
940 BSLS_ASSERT(0 && "Should never execute this function");
941
942 return -1;
943}
944
945template <typename TYPE, typename ANY_CATEGORY>
946inline
947int BerDecoder_Node::operator()(TYPE *object, ANY_CATEGORY category)
948{
949 return this->decode(object, category);
950}
951
952template <typename TYPE>
953inline
955{
956 typedef typename bdlat_TypeCategory::Select<TYPE>::Type Tag;
957 return this->decode(object, Tag());
958}
959
960// PRIVATE TYPES
962 // PUBLIC DATA
964
965 // MANIPULATORS
966 template <class t_BASE_TYPE>
967 int operator()(t_BASE_TYPE *value) {
968 typedef typename bdlat_TypeCategory::Select<t_BASE_TYPE>::Type BaseTag;
969 return d_that->decode(value, BaseTag());
970 }
971};
972
973// PRIVATE MANIPULATORS
974template <typename TYPE>
975int
976BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Choice)
977{
978 // A misunderstanding of X.694 (clause 20.4), an XML choice (not anonymous)
979 // element is encoded as a sequence (outer) with 1 element (inner).
980 // However, if the element is anonymous (i.e., untagged), then there is no
981 // inner tag. This behavior is kept for backward compatibility.
982
983 if (d_tagType != BerConstants::e_CONSTRUCTED) {
984 return logError("Expected CONSTRUCTED tag type for choice"); // RETURN
985 }
986
987 bool isUntagged = d_formattingMode & bdlat_FormattingMode::e_UNTAGGED;
988
990
991 if (!isUntagged) {
992
993 // 'typename' will be taken from predecessor node.
994 BerDecoder_Node innerNode(d_decoder);
995 rc = innerNode.readTagHeader();
996 if (rc != BerDecoder::e_BER_SUCCESS) {
997 return rc; // error message is already logged // RETURN
998 }
999
1000 if (innerNode.tagClass() != BerConstants::e_CONTEXT_SPECIFIC) {
1001 return innerNode.logError(
1002 "Expected CONTEXT tag class for tagged choice"); // RETURN
1003 }
1004
1005 if (innerNode.tagType() != BerConstants::e_CONSTRUCTED) {
1006 return innerNode.logError(
1007 "Expected CONSTRUCTED tag type for tagged choice"); // RETURN
1008 }
1009
1010 if (innerNode.tagNumber() != 0) {
1011 return innerNode.logError(
1012 "Expected 0 as a tag number for tagged choice"); // RETURN
1013 }
1014
1015 if (innerNode.hasMore()) {
1016 // if shouldContinue returns false, then there is no selection
1017 rc = innerNode.decodeChoice(variable);
1018 if (rc != BerDecoder::e_BER_SUCCESS) {
1019 return rc; // error message is already logged // RETURN
1020 }
1021 }
1022
1023 rc = innerNode.readTagTrailer();
1024 }
1025 else if (this->hasMore()) {
1026
1027 // if shouldContinue returns false, then there is no selection
1028 rc = this->decodeChoice(variable);
1029 }
1030
1031 return rc;
1032}
1033
1034template <typename TYPE>
1035int
1036BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::NullableValue)
1037{
1039
1040 if (d_formattingMode & bdlat_FormattingMode::e_NILLABLE) {
1041 // nillable is encoded in BER as a sequence with one optional element
1042
1043 if (d_tagType != BerConstants::e_CONSTRUCTED) {
1044 return logError(
1045 "Expected CONSTRUCTED tag type for nullable"); // RETURN
1046 }
1047
1048 if (hasMore()) {
1049
1050 // If 'hasMore' returns false, then the nullable value is null.
1051 BerDecoder_Node innerNode(d_decoder);
1052 rc = innerNode.readTagHeader();
1053 if (rc != BerDecoder::e_BER_SUCCESS) {
1054 return rc; // error message is already logged // RETURN
1055 }
1056
1057 if (innerNode.tagClass() != BerConstants::e_CONTEXT_SPECIFIC) {
1058 return innerNode.logError("Expected CONTEXT tag class for "
1059 "inner nillable"); // RETURN
1060 }
1061
1062 if (innerNode.tagNumber() != 0) {
1063 return innerNode.logError(
1064 "Expected 0 as tag number for inner nillable"); // RETURN
1065 }
1066
1068
1070 innerNode);
1071 if (rc != BerDecoder::e_BER_SUCCESS) {
1072 return rc; // error message is already logged // RETURN
1073 }
1074
1075 rc = innerNode.readTagTrailer();
1076
1077 } // this->hasMore()
1078 else {
1080 }
1081 }
1082 else { // not 'bdlat_FormattingMode::e_NILLABLE'
1085 }
1086
1087 return rc;
1088}
1089
1090template <typename TYPE>
1091int
1092BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::CustomizedType)
1093{
1094 CustomizedManipulator baseManipulator = {this};
1096 variable,
1097 baseManipulator);
1098}
1099
1100template <typename TYPE>
1101int
1102BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Enumeration)
1103{
1104 int value = 0;
1105 int rc = this->decode(&value, bdlat_TypeCategory::Simple());
1106
1107 if (rc != BerDecoder::e_BER_SUCCESS) {
1108 return rc; // error message is already logged // RETURN
1109 }
1110
1111 if (0 != bdlat::EnumUtil::fromIntOrFallbackIfEnabled(variable, value)) {
1112 return logError("Error converting enumeration value"); // RETURN
1113 }
1114
1116}
1117
1118template <typename TYPE>
1119inline
1120int BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Simple)
1121{
1122 if (d_tagType != BerConstants::e_PRIMITIVE) {
1123 return logError(
1124 "Expected PRIMITIVE tag type for simple type"); // RETURN
1125 }
1126
1127 if (BerUtil::getValue(d_decoder->d_streamBuf,
1128 variable,
1129 d_expectedLength,
1130 *d_decoder->d_options) != 0) {
1131 return logError("Error reading value for simple type"); // RETURN
1132 }
1133
1134 d_consumedBodyBytes = d_expectedLength;
1135
1137}
1138
1139template <typename TYPE>
1140int
1141BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Sequence)
1142{
1143 if (d_tagType != BerConstants::e_CONSTRUCTED) {
1144 return logError(
1145 "Expected CONSTRUCTED tag type for sequence"); // RETURN
1146 }
1147
1148 while (this->hasMore()) {
1149
1150 BerDecoder_Node innerNode(d_decoder);
1151
1152 int rc = innerNode.readTagHeader();
1153 if (rc != BerDecoder::e_BER_SUCCESS) {
1154 return rc; // error message is already logged // RETURN
1155 }
1156
1157 if (innerNode.tagClass() != BerConstants::e_CONTEXT_SPECIFIC) {
1158 return innerNode.logError(
1159 "Expected CONTEXT tag class inside sequence"); // RETURN
1160 }
1161
1163 innerNode.tagNumber())) {
1164
1165 BerDecoder_NodeVisitor visitor(&innerNode);
1166
1168 variable,
1169 visitor,
1170 innerNode.tagNumber());
1171 }
1173 innerNode.tagNumber()) {
1174 rc = innerNode.decode(&d_decoder->d_arrayLengthHint,
1176 }
1177 else {
1178 rc = innerNode.skipField();
1180 d_decoder->numUnknownElementsSkipped() + 1);
1181 }
1182
1183 if (rc != BerDecoder::e_BER_SUCCESS) {
1184 return rc; // error message is already logged // RETURN
1185 }
1186
1187 rc = innerNode.readTagTrailer();
1188 if (rc != BerDecoder::e_BER_SUCCESS) {
1189 return rc; // error message is already logged // RETURN
1190 }
1191 }
1192
1194}
1195
1196template <typename TYPE>
1197inline
1198int BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Array)
1199{
1200 // Note: 'bsl::vector<char>' and 'bsl::vector<unsigned char>' are
1201 // handled as special cases in the CPP file.
1202
1203 return this->decodeArray(variable);
1204}
1205
1206template <typename TYPE>
1207inline
1208int BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::DynamicType)
1209{
1210 return bdlat_TypeCategoryUtil::manipulateByCategory(variable, *this);
1211}
1212
1213template <typename TYPE>
1214int BerDecoder_Node::decodeChoice(TYPE *variable)
1215{
1216 BerDecoder_Node innerNode(d_decoder);
1217
1218 int rc = innerNode.readTagHeader();
1219 if (rc != BerDecoder::e_BER_SUCCESS) {
1220 return rc; // error message is already logged // RETURN
1221 }
1222
1223 if (innerNode.tagClass() != BerConstants::e_CONTEXT_SPECIFIC) {
1224 return innerNode.logError(
1225 "Expected CONTEXT tag class for internal "); // RETURN
1226 }
1227
1229 innerNode.tagNumber())) {
1230
1231 if (0 != bdlat_ChoiceFunctions::makeSelection(variable,
1232 innerNode.tagNumber())) {
1233 return innerNode.logError(
1234 "Unable to make choice selection"); // RETURN
1235 }
1236
1237 BerDecoder_NodeVisitor visitor(&innerNode);
1238
1239 rc = bdlat_ChoiceFunctions::manipulateSelection(variable, visitor);
1240 }
1241 else {
1242 rc = innerNode.skipField();
1244 d_decoder->numUnknownElementsSkipped() + 1);
1245 }
1246
1247 if (rc != BerDecoder::e_BER_SUCCESS) {
1248 return rc; // error message is already logged // RETURN
1249 }
1250
1251 return innerNode.readTagTrailer();
1252}
1253
1254template <typename TYPE>
1255int
1256BerDecoder_Node::decodeArray(TYPE *variable)
1257{
1258 if (d_tagType != BerConstants::e_CONSTRUCTED) {
1259 return logError("Expected CONSTRUCTED tag class for array"); // RETURN
1260 }
1261
1262 const int maxSize = d_decoder->decoderOptions()->maxSequenceSize();
1263
1264 // The hint comes from untrusted input. Always consume it (it applies to
1265 // the next array only, never to a sibling), but only honor it to the
1266 // extent it is justified by bytes the producer has *actually* delivered
1267 // into the streambuf. Never trust `d_expectedLength` as a budget here: it
1268 // is a wire claim from the same source as the hint. Each BER TLV
1269 // (Tag-Length-Value) tuple is at least 2 bytes (1-byte tag + 1-byte
1270 // length=0) regardless of element type, so `in_avail() / 2` is a tight
1271 // upper bound on the number of elements that can follow. For streambufs
1272 // that don't report buffered bytes (sockets/pipes with empty get area,
1273 // some filtering streambufs), `in_avail()` returns 0 (or -1 at EOF, which
1274 // truncates to 0 after division), in which case we simply drop the hint
1275 // and let `vector`'s geometric growth amortize the per-element `resize`
1276 // cost.
1277 const int arrayLengthHint = d_decoder->d_arrayLengthHint;
1278 d_decoder->d_arrayLengthHint = 0;
1280 variable,
1281 static_cast<int>(bsl::min<bsl::streamsize>(
1282 bsl::min(arrayLengthHint, maxSize),
1283 d_decoder->d_streamBuf->in_avail() / 2)));
1284
1285 int i = static_cast<int>(bdlat_ArrayFunctions::size(*variable));
1286 while (this->hasMore()) {
1287 int j = i + 1;
1288
1289 if (j > maxSize) {
1290 return logError("Array size exceeds the limit"); // RETURN
1291 }
1292
1293 bdlat_ArrayFunctions::resize(variable, j);
1294
1295 BerDecoder_UniversalElementVisitor visitor(d_decoder);
1296 int rc = bdlat_ArrayFunctions::manipulateElement(variable, visitor, i);
1297 if (rc != BerDecoder::e_BER_SUCCESS) {
1298 return logError("Error in decoding array element"); // RETURN
1299 }
1300 i = j;
1301 }
1302
1304}
1305
1306 // ------------------------------------
1307 // private class BerDecoder_NodeVisitor
1308 // ------------------------------------
1309
1310// CREATORS
1311inline
1312BerDecoder_NodeVisitor::
1313BerDecoder_NodeVisitor(BerDecoder_Node *node)
1314: d_node(node)
1315{
1316}
1317
1318// MANIPULATORS
1319template <typename TYPE, typename INFO>
1320inline
1321int BerDecoder_NodeVisitor::operator()(TYPE *variable, const INFO& info)
1322{
1323 d_node->setFormattingMode(info.formattingMode());
1324 d_node->setFieldName(info.name());
1325
1326 return d_node->operator()(variable);
1327}
1328
1329 // ------------------------------------------------
1330 // private class BerDecoder_UniversalElementVisitor
1331 // ------------------------------------------------
1332
1333// CREATORS
1334inline
1335BerDecoder_UniversalElementVisitor::
1336BerDecoder_UniversalElementVisitor(BerDecoder *decoder)
1337: d_node(decoder)
1338{
1339}
1340
1341// MANIPULATORS
1342template <typename TYPE>
1344{
1345 int alternateTag = -1;
1346 BerUniversalTagNumber::Value expectedTagNumber =
1348 d_node.formattingMode(),
1349 &alternateTag);
1350
1351 int rc = d_node.readTagHeader();
1352 if (rc != BerDecoder::e_BER_SUCCESS) {
1353 return rc; // error message is already logged // RETURN
1354 }
1355
1356 if (d_node.tagClass() != BerConstants::e_UNIVERSAL) {
1357 return d_node.logError("Expected UNIVERSAL tag class"); // RETURN
1358 }
1359
1360 if (d_node.tagNumber() != static_cast<int>(expectedTagNumber)) {
1361 if (-1 == alternateTag || d_node.tagNumber() != alternateTag) {
1362 return d_node.logError("Unexpected tag number"); // RETURN
1363 }
1364 }
1365
1366 rc = d_node(variable);
1367
1368 if (rc != BerDecoder::e_BER_SUCCESS) {
1369 return rc; // RETURN
1370 }
1371
1372 rc = d_node.readTagTrailer();
1373
1374 return rc;
1375}
1376
1377} // close package namespace
1378
1379#endif
1380
1381// ----------------------------------------------------------------------------
1382// Copyright 2015 Bloomberg Finance L.P.
1383//
1384// Licensed under the Apache License, Version 2.0 (the "License");
1385// you may not use this file except in compliance with the License.
1386// You may obtain a copy of the License at
1387//
1388// http://www.apache.org/licenses/LICENSE-2.0
1389//
1390// Unless required by applicable law or agreed to in writing, software
1391// distributed under the License is distributed on an "AS IS" BASIS,
1392// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1393// See the License for the specific language governing permissions and
1394// limitations under the License.
1395// ----------------------------- END-OF-FILE ----------------------------------
1396
1397/** @} */
1398/** @} */
1399/** @} */
Definition balber_berdecoderoptions.h:76
const int & maxSequenceSize() const
Definition balber_berdecoderoptions.h:741
Definition balber_berdecoder.h:566
int operator()(TYPE *variable, const INFO &info)
Definition balber_berdecoder.h:1321
Definition balber_berdecoder.h:388
BerDecoder_Node(BerDecoder *decoder, const TYPE *variable)
BerConstants::TagType tagType() const
Return the BER tag type for this node.
Definition balber_berdecoder.h:894
BerConstants::TagClass tagClass() const
Return the BER tag class for this node.
Definition balber_berdecoder.h:888
void setFieldName(const char *name)
Definition balber_berdecoder.h:931
void print(bsl::ostream &out, int depth, int spacePerLevel=0, const char *prefixText=0) const
int readVectorChar(bsl::vector< char > *variable)
const char * fieldName() const
Return field name for this node.
Definition balber_berdecoder.h:912
BerDecoder_Node * parent() const
Return the address of the parent node.
Definition balber_berdecoder.h:882
int operator()(TYPE *object, bslmf::Nil)
Definition balber_berdecoder.h:938
int logError(const char *msg)
int readVectorUnsignedChar(bsl::vector< unsigned char > *variable)
void setFormattingMode(int formattingMode)
Set formatting mode specified by formattingMode.
Definition balber_berdecoder.h:925
void printStack(bsl::ostream &out) const
int tagNumber() const
Return the BER tag number for this node.
Definition balber_berdecoder.h:900
int length() const
Return expected length of the body or -1 when the length is indefinite.
Definition balber_berdecoder.h:918
int formattingMode() const
Return formatting mode for this node.
Definition balber_berdecoder.h:906
int startPos() const
Return the position of node tag from the beginning of input stream.
bool hasMore()
Definition balber_berdecoder.h:869
~BerDecoder_Node()
Definition balber_berdecoder.h:854
Definition balber_berdecoder.h:598
int operator()(TYPE *variable)
Definition balber_berdecoder.h:1343
Definition balber_berdecoder.h:631
~BerDecoder_Zeroer()
Definition balber_berdecoder.h:644
BerDecoder_Zeroer(const BerDecoderOptions **options)
Definition balber_berdecoder.h:639
Definition balber_berdecoder.h:175
int numUnknownElementsSkipped() const
Definition balber_berdecoder.h:822
int decodeAny(bsl::streambuf *streamBuf, TYPE *variable)
Definition balber_berdecoder.h:777
bool maxDepthExceeded() const
Definition balber_berdecoder.h:816
int decode(bsl::streambuf *streamBuf, TYPE *variable)
Definition balber_berdecoder.h:732
int decodeAny(bsl::istream &stream, bdlar::AnyRef *variable)
bslstl::StringRef loggedMessages() const
Definition balber_berdecoder.h:805
void setNumUnknownElementsSkipped(int value)
Definition balber_berdecoder.h:784
int decodeAny(bsl::streambuf *streamBuf, bdlar::AnyRef *variable)
ErrorSeverity
Definition balber_berdecoder.h:228
@ BDEM_BER_SUCCESS
Definition balber_berdecoder.h:233
@ e_BER_SUCCESS
Definition balber_berdecoder.h:229
@ e_BER_ERROR
Definition balber_berdecoder.h:230
@ BDEM_BER_ERROR
Definition balber_berdecoder.h:234
BerDecoder(const BerDecoderOptions *options=0, bslma::Allocator *basicAllocator=0)
ErrorSeverity errorSeverity() const
Definition balber_berdecoder.h:799
const BerDecoderOptions * decoderOptions() const
Return the address of the BER decoder options.
Definition balber_berdecoder.h:793
Definition bdlar_anyref.h:85
static bsl::enable_if<!IsDynamic< t_TYPE >::value, AnyRef >::type makeAnyRef(t_TYPE &object)
Make AnyRef to the specified object.
Definition bdlar_refutil.h:209
Definition bdlsb_memoutstreambuf.h:212
Definition bslstl_vector.h:1120
Definition bslma_allocator.h:545
Definition bslstl_stringref.h:374
int length() const
Definition balber_berdecoder.h:685
const char * data() const
Definition balber_berdecoder.h:679
void reset()
Reset the internal streambuf to the empty state.
Definition balber_berdecoder.h:672
static int manipulateByCategory(TYPE *object, MANIPULATOR &manipulator)
Definition bdlat_typecategory.h:1414
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1976
#define BSLS_IDENT(str)
BSLS_IDENT() - insert string into .comment binary segment (if supported)
Definition bsls_ident.h:238
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:695
Definition balber_berconstants.h:84
int manipulateElement(TYPE *array, MANIPULATOR &manipulator, int index)
void resize(TYPE *array, int newSize)
bsl::size_t size(const TYPE &array)
Return the number of elements in the specified array.
int reserve(TYPE *array, int numElements)
bool hasSelection(const TYPE &object, const char *selectionName, int selectionNameLength)
int manipulateSelection(TYPE *object, MANIPULATOR &manipulator)
int makeSelection(TYPE *object, int selectionId)
int createBaseAndConvert(t_TYPE *object, t_MANIPULATOR &baseManipulator)
int manipulateValue(TYPE *object, MANIPULATOR &manipulator)
void makeValue(TYPE *object)
int manipulateAttribute(TYPE *object, MANIPULATOR &manipulator, const char *attributeName, int attributeNameLength)
bool hasAttribute(const TYPE &object, const char *attributeName, int attributeNameLength)
void reset(TYPE *object)
Reset the value of the specified object to its default value.
Definition bdlat_valuetypefunctions.h:939
Definition baljsn_encoder_testtypes.h:76
StringRefImp< char > StringRef
Definition bslstl_stringref.h:725
Definition balber_berconstants.h:94
TagType
Definition balber_berconstants.h:117
@ e_PRIMITIVE
Definition balber_berconstants.h:120
@ e_CONSTRUCTED
Definition balber_berconstants.h:121
TagClass
Definition balber_berconstants.h:96
@ e_CONTEXT_SPECIFIC
Definition balber_berconstants.h:101
@ e_UNIVERSAL
Definition balber_berconstants.h:99
static const int k_ARRAY_LENGTH_HINT_TAG_NUMBER
Definition balber_berconstants.h:132
Definition balber_berdecoder.h:961
int operator()(t_BASE_TYPE *value)
Definition balber_berdecoder.h:967
BerDecoder_Node * d_that
Definition balber_berdecoder.h:963
Value
Definition balber_beruniversaltagnumber.h:196
static Value select(const TYPE &object, int formattingMode, int *alternateTag)
Definition balber_beruniversaltagnumber.h:605
static int getValue(bsl::streambuf *streamBuf, TYPE *value, int length, const BerDecoderOptions &options=BerDecoderOptions())
Definition balber_berutil.h:3991
@ k_INDEFINITE_LENGTH
Definition balber_berutil.h:201
static int fromIntOrFallbackIfEnabled(TYPE *result, int number)
Definition bdlat_enumutil.h:333
Definition bdlat_formattingmode.h:109
@ e_NILLABLE
Definition bdlat_formattingmode.h:125
@ e_UNTAGGED
Definition bdlat_formattingmode.h:122
Definition bdlat_typecategory.h:1037
Definition bdlat_typecategory.h:1038
Definition bdlat_typecategory.h:1039
Definition bdlat_typecategory.h:1036
Definition bdlat_typecategory.h:1040
Definition bdlat_typecategory.h:1041
Definition bdlat_typecategory.h:1042
Definition bdlat_typecategory.h:1043
Definition bslmf_nil.h:133
Definition bsls_objectbuffer.h:277