BDE 4.14.0 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 `bslsb::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 <bdlat_arrayfunctions.h>
132#include <bdlat_enumfunctions.h>
133#include <bdlat_enumutil.h>
134#include <bdlat_formattingmode.h>
137#include <bdlat_typecategory.h>
139
140#include <bdlb_variant.h>
141
143
144#include <bslma_allocator.h>
145
146#include <bsls_assert.h>
147#include <bsls_keyword.h>
148#include <bsls_objectbuffer.h>
149#include <bsls_platform.h>
150#include <bsls_review.h>
151
152#include <bsl_istream.h>
153#include <bsl_ostream.h>
154#include <bsl_string.h>
155#include <bsl_vector.h>
156
157
158namespace balber {
159
160class BerDecoder_Node;
161class BerDecoder_NodeVisitor;
162class BerDecoder_UniversalElementVisitor;
163
164 // ================
165 // class BerDecoder
166 // ================
167
168/// This class contains the parameterized `decode` functions that decode
169/// data (in BER format) from an incoming stream into `bdlat` types.
170///
171/// See @ref balber_berdecoder
173
174 private:
175 // PRIVATE TYPES
176
177 /// This class provides stream for logging using
178 /// `bdlsb::MemOutStreamBuf` as a streambuf. The logging stream is
179 /// created on demand, i.e., during the first attempt to log message.
180 ///
181 /// See @ref balber_berdecoder
182 class MemOutStream : public bsl::ostream {
183
185
186 // NOT IMPLEMENTED
187 MemOutStream(const MemOutStream&); // = delete;
188 MemOutStream& operator=(const MemOutStream&); // = delete;
189
190 public:
191 // CREATORS
192
193 /// Create a stream object. Optionally specify a `basicAllocator`
194 /// used to supply memory. If `basicAllocator` is 0, the currently
195 /// installed default allocator is used.
196 MemOutStream(bslma::Allocator *basicAllocator = 0);
197
198 /// Destroy this stream and release memory back to the allocator.
199 ///
200 /// Although the compiler should generate this destructor
201 /// implicitly, xlC 8 breaks when the destructor is called by name
202 /// unless it is explicitly declared.
203 ~MemOutStream() BSLS_KEYWORD_OVERRIDE;
204
205 // MANIPULATORS
206
207 /// Reset the internal streambuf to the empty state.
208 void reset();
209
210 // ACCESSORS
211
212 /// Return a pointer to the memory containing the formatted values
213 /// formatted to this stream. The data is not null-terminated
214 /// unless a null character was appended onto this stream.
215 const char *data() const;
216
217 /// Return the length of the formatted data, including null
218 /// characters appended to the stream, if any.
219 int length() const;
220 };
221
222 public:
223 // PUBLIC TYPES
225 e_BER_SUCCESS = 0x00
226 , e_BER_ERROR = 0x02
227
228#ifndef BDE_OMIT_INTERNAL_DEPRECATED
231#endif // BDE_OMIT_INTERNAL_DEPRECATED
232 };
233
234 private:
235 // DATA
236 const BerDecoderOptions *d_options; // held, not owned
237 bslma::Allocator *d_allocator; // held, not owned
238
239 bsls::ObjectBuffer<MemOutStream> d_logArea; // placeholder for
240 // 'MemOutStream'
241
242 MemOutStream *d_logStream; // if not zero,
243 // log stream was created
244 // at the moment of first
245 // logging and must be
246 // destroyed
247
248 ErrorSeverity d_severity; // error severity level
249 bsl::streambuf *d_streamBuf; // held, not owned
250 int d_currentDepth; // current depth
251
252 int d_numUnknownElementsSkipped;
253 // number of unknown
254 // elements skipped
255
256 BerDecoder_Node *d_topNode; // last node
257
258 // NOT IMPLEMENTED
259 BerDecoder(const BerDecoder&); // = delete;
260 BerDecoder& operator=(const BerDecoder&); // = delete;
261
262 // FRIENDS
263 friend class BerDecoder_Node;
264
265 private:
266 // PRIVATE MANIPULATORS
267
268 /// Log the specified `msg`, upgrade the severity level, and return
269 /// `e_BER_ERROR`.
270 ErrorSeverity logError(const char *msg);
271
272 /// Log the specified `msg` and upgrade the severity level.
273 void logErrorImp(const char *msg);
274
275 /// Log the specified `prefix` and `msg` and return `errorSeverity()`.
276 ErrorSeverity logMsg(const char *prefix, const char *msg);
277
278 /// Return the stream used for logging. If stream has not been created
279 /// yet, it will be created during this call.
280 bsl::ostream& logStream();
281
282 public:
283 // CREATORS
284
285 /// Construct a decoder object. Optionally specify decoder `options`.
286 /// If `options` is 0, `BerDecoderOptions()` is used. Optionally
287 /// specify a `basicAllocator` used to supply memory. If
288 /// `basicAllocator` is 0, the currently installed default allocator is
289 /// used.
290 BerDecoder(const BerDecoderOptions *options = 0,
291 bslma::Allocator *basicAllocator = 0);
292
293 /// Destroy this object. This destruction has no effect on objects
294 /// pointed-to by the pointers provided at construction.
296
297 // MANIPULATORS
298
299 /// Decode an object of parameterized `TYPE` from the specified
300 /// `streamBuf` and load the result into the specified `variable`.
301 /// Return 0 on success, and a non-zero value otherwise.
302 template <typename TYPE>
303 int decode(bsl::streambuf *streamBuf, TYPE *variable);
304
305 /// Decode an object of parameterized `TYPE` from the specified `stream`
306 /// and load the result into the specified modifiable `variable`.
307 /// Return 0 on success, and a non-zero value otherwise. If the
308 /// decoding fails `stream` will be invalidated.
309 template <typename TYPE>
310 int decode(bsl::istream& stream, TYPE *variable);
311
312 /// Set the number of unknown elements skipped by the decoder during the
313 /// current decoding operation to the specified `value`. The behavior
314 /// is undefined unless `0 <= value`.
315 void setNumUnknownElementsSkipped(int value);
316
317 // ACCESSORS
318
319 /// Return the address of the BER decoder options.
320 const BerDecoderOptions *decoderOptions() const;
321
322 bool maxDepthExceeded() const;
323 // Return 'true' if the maximum depth level is exceeded and 'false'
324 // otherwise.
325
326 /// Return the number of unknown elements that were skipped during the
327 /// previous decoding operation. Note that unknown elements are skipped
328 /// only if `true == options()->skipUnknownElements()`.
329 int numUnknownElementsSkipped() const;
330
331 /// Return the severity of the most severe log or error message
332 /// encountered during the last call to the `decode` method. The
333 /// severity is reset each time `decode` is called.
335
336 /// Return a string containing any error or trace messages that were
337 /// logged during the last call to the `decode` method. The log is
338 /// reset each time `decode` is called.
340};
341
342
343 // =============================
344 // private class BerDecoder_Node
345 // =============================
346
347/// This class provides current context for BER decoding process and
348/// represents a node for BER element. The BER element consists of element
349/// tag, length field, body field and optional end of tag. The class also
350/// provides various methods to read the different parts of BER element such
351/// as tag header (tag itself and length fields), body for any type of data,
352/// and optional tag trailer.
353///
354/// See @ref balber_berdecoder
356
357 // DATA
358 BerDecoder *d_decoder; // decoder,
359 // held, not owned
360 BerDecoder_Node *d_parent; // parent node,
361 // held, not owned
362 BerConstants::TagClass d_tagClass; // tag class
363 BerConstants::TagType d_tagType; // tag type
364 int d_tagNumber; // tag id or number
365 int d_expectedLength; // body length
366 int d_consumedHeaderBytes; // header bytes read
367 int d_consumedBodyBytes; // body bytes read
368 int d_consumedTailBytes; // trailer bytes read
369 int d_formattingMode; // formatting mode
370 const char *d_fieldName; // name of the field
371
372 // NOT IMPLEMENTED
373 BerDecoder_Node(BerDecoder_Node&); // = delete;
374 BerDecoder_Node& operator=(BerDecoder_Node&); // = delete;
375
376 private:
377 // PRIVATE MANIPULATORS
378
379 int decode(bsl::vector<char> *variable, bdlat_TypeCategory::Array);
380 /// Family of methods to decode current element into the specified
381 /// `variable` of category `bdlat_TypeCategory`. Return zero on
382 /// success, and a non-zero value otherwise. the tag header is already
383 /// read at the moment of call and input stream is positioned at the
384 /// first byte of the body field.
385 int decode(bsl::vector<unsigned char> *variable,
387 template <typename TYPE>
388 int decode(TYPE *variable, bdlat_TypeCategory::Array);
389 template <typename TYPE>
390 int decode(TYPE *variable, bdlat_TypeCategory::Choice);
391 template <typename TYPE>
392 int decode(TYPE *variable, bdlat_TypeCategory::NullableValue);
393 template <typename TYPE>
394 int decode(TYPE *variable, bdlat_TypeCategory::CustomizedType);
395 template <typename TYPE>
396 int decode(TYPE *variable, bdlat_TypeCategory::Enumeration);
397 template <typename TYPE>
398 int decode(TYPE *variable, bdlat_TypeCategory::Sequence);
399 template <typename TYPE>
400 int decode(TYPE *variable, bdlat_TypeCategory::Simple);
401 template <typename TYPE>
402 int decode(TYPE *variable, bdlat_TypeCategory::DynamicType);
403
404 /// Decode the current element, an array, into specified `variable`.
405 /// Return zero on success, and a non-zero value otherwise.
406 template <typename TYPE>
407 int decodeArray(TYPE *variable);
408
409 /// Decode the current element, which is a choice object, into specified
410 /// `variable`. Return zero on success, and a non-zero value otherwise.
411 template <typename TYPE>
412 int decodeChoice(TYPE *variable);
413
414 public:
415 // CREATORS
416 BerDecoder_Node(BerDecoder *decoder);
417
418 template <typename TYPE>
419 BerDecoder_Node(BerDecoder *decoder, const TYPE *variable);
420
422
423 // MANIPULATORS
424 template <typename TYPE>
425 int operator()(TYPE *object, bslmf::Nil);
426
427 template <typename TYPE, typename ANY_CATEGORY>
428 int operator()(TYPE *object, ANY_CATEGORY category);
429
430 template <typename TYPE>
431 int operator()(TYPE *object);
432
433 /// Print the content of node to the specified stream `out`. `depth` is
434 /// the value `d_decoder->currentDepth` assumed after node was created.
435 void print(bsl::ostream& out,
436 int depth,
437 int spacePerLevel = 0,
438 const char *prefixText = 0) const;
439
440 /// Print the chain of nodes to the specified `out` stream, starting
441 /// from this node and iterating to the parent node, then its parent,
442 /// etc.
443 void printStack(bsl::ostream& out) const;
444
445 /// Set formatting mode specified by `formattingMode`.
447
448 /// Set object field name associated with this node to the specified
449 /// `name`.
450 void setFieldName(const char *name);
451
452 /// Set the node severity to `e_BER_ERROR`, print the error message
453 /// specified by `msg` to the decoder's log, print the stack of nodes to
454 /// the decoder's log, and return a non-zero value.
455 int logError(const char *msg);
456
457 /// Read the node tag field containing tag class, tag type and tag
458 /// number, and the node length field. Return zero on success, and a
459 /// non-zero value otherwise.
461
462 /// Read the node end-of-octets field, if such exists, so the stream
463 /// will be positioned at the start of next node. Return zero on
464 /// success and a non-zero value otherwise.
466
467 /// Return `true` if current node has more embedded elements and return
468 /// `false` otherwise.
469 bool hasMore();
470
471 /// Skip the field body. The identifier octet and length have already
472 /// been extracted. Return zero on success, and a non-zero value
473 /// otherwise. Note that method must be called when input stream is
474 /// positioned at the first byte of the body field.
476
477 /// Load the node body content into the specified `variable`. Return 0
478 /// on success, and a non-zero value otherwise.
480
481 /// Load the node body content into the specified `variable`. Return 0
482 /// on success, and a non-zero value otherwise.
484
485 // ACCESSORS
486
487 /// Return the address of the parent node.
488 BerDecoder_Node *parent() const;
489
490 /// Return the BER tag class for this node.
492
493 /// Return the BER tag type for this node.
495
496 /// Return the BER tag number for this node.
497 int tagNumber() const;
498
499 /// Return formatting mode for this node.
500 int formattingMode() const;
501
502 /// Return field name for this node.
503 const char *fieldName() const;
504
505 int length() const;
506 // Return expected length of the body or -1 when the length is
507 // indefinite.
508
509 /// Return the position of node tag from the beginning of input stream.
510 int startPos() const;
511};
512
513 // ====================================
514 // private class BerDecoder_NodeVisitor
515 // ====================================
516
517/// This class is used as a visitor for visiting contained objects during
518/// decoding.
519///
520/// See @ref balber_berdecoder
522
523 // DATA
524 BerDecoder_Node *d_node; // current node, held, not owned
525
526 // NOT IMPLEMENTED
529 // = delete;
530
531 public:
532 // CREATORS
534
536
537 // MANIPULATORS
538 template <typename TYPE, typename INFO>
539 int operator()(TYPE *variable, const INFO& info);
540};
541
542 // ================================================
543 // private class BerDecoder_UniversalElementVisitor
544 // ================================================
545
546/// This `class` is used as a visitor for visiting the top-level element and
547/// also array elements during decoding. This class is required so that the
548/// universal tag number of the element can be determined when the element
549/// is visited.
550///
551/// See @ref balber_berdecoder
553
554 // DATA
555 BerDecoder_Node d_node; // a new node
556
557 // NOT IMPLEMENTED
560 // = delete;
563 // = delete;
564
565 public:
566 // CREATORS
568
570
571 // MANIPULATORS
572 template <typename TYPE>
573 int operator()(TYPE *variable);
574};
575
576 // =======================
577 // class BerDecoder_Zeroer
578 // =======================
579
580/// This class is a deleter that just zeroes out a given pointer upon
581/// destruction, for making code exception-safe.
582///
583/// See @ref balber_berdecoder
585
586 // DATA
587 const BerDecoderOptions **d_options_p; // address of pointer to zero
588 // out upon destruction
589
590 public:
591 // CREATORS
593 : d_options_p(options)
594 {
595 }
596
598 {
599 *d_options_p = 0;
600 }
601};
602
603} // close package namespace
604
605// ============================================================================
606// INLINE FUNCTION DEFINITIONS
607// ============================================================================
608
609 // --------------------------------------
610 // class balber::BerDecoder::MemOutStream
611 // --------------------------------------
612
613// CREATORS
614inline
615balber::BerDecoder::MemOutStream::MemOutStream(
616 bslma::Allocator *basicAllocator)
617: bsl::ostream(0)
618, d_sb(bslma::Default::allocator(basicAllocator))
619{
620 rdbuf(&d_sb);
621}
622
623// MANIPULATORS
624inline
626{
627 d_sb.reset();
628}
629
630// ACCESSORS
631inline
633{
634 return d_sb.data();
635}
636
637inline
639{
640 return (int)d_sb.length();
641}
642
643namespace balber {
644 // ----------------
645 // class BerDecoder
646 // ----------------
647
648// MANIPULATORS
650BerDecoder::logError(const char *msg)
651{
652 // This is inline just so compilers see it cannot return SUCCESS, thereby
653 // improving flow analysis and choking off spurious warnings.
654
655 logErrorImp(msg);
656 return e_BER_ERROR;
657}
658
659inline
660bsl::ostream& BerDecoder::logStream()
661{
662 if (0 == d_logStream) {
663 d_logStream = new(d_logArea.buffer()) MemOutStream(d_allocator);
664 }
665 return *d_logStream;
666}
667
668template <typename TYPE>
669inline
670int BerDecoder::decode(bsl::istream& stream, TYPE *variable)
671{
672 if (!stream.good()) {
673 return -1;
674 }
675
676 if (0 != this->decode(stream.rdbuf(), variable)) {
677 stream.setstate(bsl::ios_base::failbit);
678 return -1;
679 }
680
681 return 0;
682}
683
684template <typename TYPE>
685int BerDecoder::decode(bsl::streambuf *streamBuf, TYPE *variable)
686{
687 BSLS_ASSERT(0 == d_streamBuf);
688
689 d_streamBuf = streamBuf;
690 d_currentDepth = 0;
691 d_severity = e_BER_SUCCESS;
692 d_numUnknownElementsSkipped = 0;
693
694 if (d_logStream != 0) {
695 d_logStream->reset();
696 }
697
698 d_topNode = 0;
699
701
702 int rc = d_severity;
703
704 if (! d_options) {
705 // Create temporary options object
706 BerDecoderOptions options; d_options = &options;
707 BerDecoder_Zeroer zeroer(&d_options);
709 rc = visitor(variable);
710 }
711 else {
713 rc = visitor(variable);
714 }
715
716 d_streamBuf = 0;
717 return rc;
718}
719
720inline
721void BerDecoder::setNumUnknownElementsSkipped(int value)
722{
723 BSLS_ASSERT(0 <= value);
724
725 d_numUnknownElementsSkipped = value;
726}
727
728// ACCESSORS
729inline
730const BerDecoderOptions *BerDecoder::decoderOptions() const
731{
732 return d_options;
733}
734
735inline
736BerDecoder::ErrorSeverity BerDecoder::errorSeverity() const
737{
738 return d_severity;
739}
740
741inline
742bslstl::StringRef BerDecoder::loggedMessages() const
743{
744 if (d_logStream) {
745 return bslstl::StringRef(d_logStream->data(), d_logStream->length());
746 }
747
748 return bslstl::StringRef();
749}
750
751inline
752bool BerDecoder::maxDepthExceeded() const
753{
754 return d_currentDepth > d_options->maxDepth();
755}
756
757inline
758int BerDecoder::numUnknownElementsSkipped() const
759{
760 return d_numUnknownElementsSkipped;
761}
762
763 // -----------------------------
764 // private class BerDecoder_Node
765 // -----------------------------
766
767// CREATORS
768inline
769BerDecoder_Node::BerDecoder_Node(BerDecoder *decoder)
770: d_decoder (decoder)
771, d_parent (d_decoder->d_topNode)
772, d_tagClass (BerConstants::e_UNIVERSAL)
773, d_tagType (BerConstants::e_PRIMITIVE)
774, d_tagNumber (0)
775, d_expectedLength (0)
776, d_consumedHeaderBytes(0)
777, d_consumedBodyBytes (0)
778, d_consumedTailBytes (0)
779, d_formattingMode (bdlat_FormattingMode::e_DEFAULT)
780, d_fieldName (0)
781{
782 ++d_decoder->d_currentDepth;
783 if (d_parent) {
784 d_formattingMode = d_parent->d_formattingMode;
785 }
786 d_decoder->d_topNode = this;
787}
788
789inline
791{
792 if (d_parent) {
793 d_parent->d_consumedBodyBytes += d_consumedHeaderBytes
794 + d_consumedBodyBytes
795 + d_consumedTailBytes;
796 }
797
798 d_decoder->d_topNode = d_parent;
799 --d_decoder->d_currentDepth;
800}
801
802// MANIPULATORS
803inline
804bool
806{
808
809 if (BerUtil::k_INDEFINITE_LENGTH == d_expectedLength) {
810 return 0 != d_decoder->d_streamBuf->sgetc();
811 }
812
813 return d_expectedLength > d_consumedBodyBytes;
814}
815
816// ACCESSORS
817inline
819{
820 return d_parent;
821}
822
823inline
825{
826 return d_tagClass;
827}
828
829inline
831{
832 return d_tagType;
833}
834
835inline
837{
838 return d_tagNumber;
839}
840
841inline
843{
844 return d_formattingMode;
845}
846
847inline
848const char *BerDecoder_Node::fieldName() const
849{
850 return d_fieldName;
851}
852
853inline
855{
856 return d_expectedLength;
857}
858
859// MANIPULATORS
860inline
862{
863 d_formattingMode = formattingMode;
864}
865
866inline
867void BerDecoder_Node::setFieldName(const char *name)
868{
869 d_fieldName = name;
870}
871
872template <typename TYPE>
873inline
875{
876 BSLS_ASSERT(0 && "Should never execute this function");
877
878 return -1;
879}
880
881template <typename TYPE, typename ANY_CATEGORY>
882inline
883int BerDecoder_Node::operator()(TYPE *object, ANY_CATEGORY category)
884{
885 return this->decode(object, category);
886}
887
888template <typename TYPE>
889inline
891{
892 typedef typename bdlat_TypeCategory::Select<TYPE>::Type Tag;
893 return this->decode(object, Tag());
894}
895
896// PRIVATE MANIPULATORS
897template <typename TYPE>
898int
899BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Choice)
900{
901 // A misunderstanding of X.694 (clause 20.4), an XML choice (not anonymous)
902 // element is encoded as a sequence (outer) with 1 element (inner).
903 // However, if the element is anonymous (i.e., untagged), then there is no
904 // inner tag. This behavior is kept for backward compatibility.
905
906 if (d_tagType != BerConstants::e_CONSTRUCTED) {
907 return logError("Expected CONSTRUCTED tag type for choice");
908 }
909
910 bool isUntagged = d_formattingMode & bdlat_FormattingMode::e_UNTAGGED;
911
913
914 if (!isUntagged) {
915
916 // 'typename' will be taken from predecessor node.
917 BerDecoder_Node innerNode(d_decoder);
918 rc = innerNode.readTagHeader();
919 if (rc != BerDecoder::e_BER_SUCCESS) {
920 return rc; // error message is already logged
921 }
922
923 if (innerNode.tagClass() != BerConstants::e_CONTEXT_SPECIFIC) {
924 return innerNode.logError(
925 "Expected CONTEXT tag class for tagged choice");
926 }
927
928 if (innerNode.tagType() != BerConstants::e_CONSTRUCTED) {
929 return innerNode.logError(
930 "Expected CONSTRUCTED tag type for tagged choice");
931 }
932
933 if (innerNode.tagNumber() != 0) {
934 return innerNode.logError(
935 "Expected 0 as a tag number for tagged choice");
936 }
937
938 if (innerNode.hasMore()) {
939 // if shouldContinue returns false, then there is no selection
940 rc = innerNode.decodeChoice(variable);
941 if (rc != BerDecoder::e_BER_SUCCESS) {
942 return rc; // error message is already logged
943 }
944 }
945
946 rc = innerNode.readTagTrailer();
947 }
948 else if (this->hasMore()) {
949
950 // if shouldContinue returns false, then there is no selection
951 rc = this->decodeChoice(variable);
952 }
953
954 return rc;
955}
956
957template <typename TYPE>
958int
959BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::NullableValue)
960{
962
963 if (d_formattingMode & bdlat_FormattingMode::e_NILLABLE) {
964 // nillable is encoded in BER as a sequence with one optional element
965
966 if (d_tagType != BerConstants::e_CONSTRUCTED) {
967 return logError("Expected CONSTRUCTED tag type for nullable");
968 }
969
970 if (hasMore()) {
971
972 // If 'hasMore' returns false, then the nullable value is null.
973 BerDecoder_Node innerNode(d_decoder);
974 rc = innerNode.readTagHeader();
975 if (rc != BerDecoder::e_BER_SUCCESS) {
976 return rc; // error message is already logged
977 }
978
979 if (innerNode.tagClass() != BerConstants::e_CONTEXT_SPECIFIC) {
980 return innerNode.logError(
981 "Expected CONTEXT tag class for inner nillable");
982 }
983
984 if (innerNode.tagNumber() != 0) {
985 return innerNode.logError(
986 "Expected 0 as tag number for inner nillable");
987 }
988
990
992 innerNode);
993 if (rc != BerDecoder::e_BER_SUCCESS) {
994 return rc; // error message is already logged
995 }
996
997 rc = innerNode.readTagTrailer();
998
999 } // this->hasMore()
1000 else {
1002 }
1003 }
1004 else { // not 'bdlat_FormattingMode::e_NILLABLE'
1007 }
1008
1009 return rc;
1010}
1011
1012template <typename TYPE>
1013int
1014BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::CustomizedType)
1015{
1016 typedef typename
1018
1019#ifdef BSLS_PLATFORM_HAS_PRAGMA_GCC_DIAGNOSTIC
1020#pragma GCC diagnostic push
1021#pragma GCC diagnostic ignored "-Wuninitialized"
1022#ifndef BSLS_PLATFORM_CMP_CLANG
1023#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
1024#endif
1025#endif
1026
1027 BaseType base;
1028
1029 typedef typename bdlat_TypeCategory::Select<BaseType>::Type BaseTag;
1030 int rc = this->decode(&base, BaseTag());
1031
1032 if (rc != BerDecoder::e_BER_SUCCESS) {
1033 return rc; // error message is already logged
1034 }
1035
1037 base) != 0) {
1038 return logError("Error converting from base type for customized");
1039 }
1040
1041#ifdef BSLS_PLATFORM_HAS_PRAGMA_GCC_DIAGNOSTIC
1042#pragma GCC diagnostic pop
1043#endif
1044
1046}
1047
1048template <typename TYPE>
1049int
1050BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Enumeration)
1051{
1052 int value = 0;
1053 int rc = this->decode(&value, bdlat_TypeCategory::Simple());
1054
1055 if (rc != BerDecoder::e_BER_SUCCESS) {
1056 return rc; // error message is already logged
1057 }
1058
1059 if (0 != bdlat::EnumUtil::fromIntOrFallbackIfEnabled(variable, value)) {
1060 return logError("Error converting enumeration value");
1061 }
1062
1064}
1065
1066template <typename TYPE>
1067inline
1068int BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Simple)
1069{
1070 if (d_tagType != BerConstants::e_PRIMITIVE) {
1071 return logError("Expected PRIMITIVE tag type for simple type");
1072 }
1073
1074 if (BerUtil::getValue(d_decoder->d_streamBuf,
1075 variable,
1076 d_expectedLength,
1077 *d_decoder->d_options) != 0) {
1078 return logError("Error reading value for simple type");
1079 }
1080
1081 d_consumedBodyBytes = d_expectedLength;
1082
1084}
1085
1086template <typename TYPE>
1087int
1088BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Sequence)
1089{
1090 if (d_tagType != BerConstants::e_CONSTRUCTED) {
1091 return logError("Expected CONSTRUCTED tag type for sequence");
1092 }
1093
1094 while (this->hasMore()) {
1095
1096 BerDecoder_Node innerNode(d_decoder);
1097
1098 int rc = innerNode.readTagHeader();
1099 if (rc != BerDecoder::e_BER_SUCCESS) {
1100 return rc; // error message is already logged
1101 }
1102
1103 if (innerNode.tagClass() != BerConstants::e_CONTEXT_SPECIFIC) {
1104 return innerNode.logError(
1105 "Expected CONTEXT tag class inside sequence");
1106 }
1107
1109 innerNode.tagNumber())) {
1110
1111 BerDecoder_NodeVisitor visitor(&innerNode);
1112
1114 variable,
1115 visitor,
1116 innerNode.tagNumber());
1117 }
1118 else {
1119 rc = innerNode.skipField();
1121 d_decoder->numUnknownElementsSkipped() + 1);
1122 }
1123
1124 if (rc != BerDecoder::e_BER_SUCCESS) {
1125 return rc; // error message is already logged
1126 }
1127
1128 rc = innerNode.readTagTrailer();
1129 if (rc != BerDecoder::e_BER_SUCCESS) {
1130 return rc; // error message is already logged
1131 }
1132 }
1133
1135}
1136
1137template <typename TYPE>
1138inline
1139int BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::Array)
1140{
1141 // Note: 'bsl::vector<char>' and 'bsl::vector<unsigned char>' are
1142 // handled as special cases in the CPP file.
1143
1144 return this->decodeArray(variable);
1145}
1146
1147template <typename TYPE>
1148inline
1149int BerDecoder_Node::decode(TYPE *variable, bdlat_TypeCategory::DynamicType)
1150{
1151 return bdlat_TypeCategoryUtil::manipulateByCategory(variable, *this);
1152}
1153
1154template <typename TYPE>
1155int BerDecoder_Node::decodeChoice(TYPE *variable)
1156{
1157 BerDecoder_Node innerNode(d_decoder);
1158
1159 int rc = innerNode.readTagHeader();
1160 if (rc != BerDecoder::e_BER_SUCCESS) {
1161 return rc; // error message is already logged
1162 }
1163
1164 if (innerNode.tagClass() != BerConstants::e_CONTEXT_SPECIFIC) {
1165 return innerNode.logError(
1166 "Expected CONTEXT tag class for internal choice");
1167 }
1168
1170 innerNode.tagNumber())) {
1171
1172 if (0 != bdlat_ChoiceFunctions::makeSelection(variable,
1173 innerNode.tagNumber())) {
1174
1175 return innerNode.logError("Unable to make choice selection");
1176 }
1177
1178 BerDecoder_NodeVisitor visitor(&innerNode);
1179
1180 rc = bdlat_ChoiceFunctions::manipulateSelection(variable, visitor);
1181 }
1182 else {
1183 rc = innerNode.skipField();
1185 d_decoder->numUnknownElementsSkipped() + 1);
1186 }
1187
1188 if (rc != BerDecoder::e_BER_SUCCESS) {
1189 return rc; // error message is already logged
1190 }
1191
1192 return innerNode.readTagTrailer();
1193}
1194
1195template <typename TYPE>
1196int
1197BerDecoder_Node::decodeArray(TYPE *variable)
1198{
1199 if (d_tagType != BerConstants::e_CONSTRUCTED) {
1200 return logError("Expected CONSTRUCTED tag class for array");
1201 }
1202
1203 const int maxSize = d_decoder->decoderOptions()->maxSequenceSize();
1204
1205 int i = static_cast<int>(bdlat_ArrayFunctions::size(*variable));
1206 while (this->hasMore()) {
1207 int j = i + 1;
1208
1209 if (j > maxSize) {
1210 return logError("Array size exceeds the limit");
1211 }
1212
1213 bdlat_ArrayFunctions::resize(variable, j);
1214
1215 BerDecoder_UniversalElementVisitor visitor(d_decoder);
1216 int rc = bdlat_ArrayFunctions::manipulateElement(variable, visitor, i);
1217 if (rc != BerDecoder::e_BER_SUCCESS) {
1218 return logError("Error in decoding array element");
1219 }
1220 i = j;
1221 }
1222
1224}
1225
1226 // ------------------------------------
1227 // private class BerDecoder_NodeVisitor
1228 // ------------------------------------
1229
1230// CREATORS
1231inline
1232BerDecoder_NodeVisitor::
1233BerDecoder_NodeVisitor(BerDecoder_Node *node)
1234: d_node(node)
1235{
1236}
1237
1238// MANIPULATORS
1239template <typename TYPE, typename INFO>
1240inline
1241int BerDecoder_NodeVisitor::operator()(TYPE *variable, const INFO& info)
1242{
1243 d_node->setFormattingMode(info.formattingMode());
1244 d_node->setFieldName(info.name());
1245
1246 return d_node->operator()(variable);
1247}
1248
1249 // ------------------------------------------------
1250 // private class BerDecoder_UniversalElementVisitor
1251 // ------------------------------------------------
1252
1253// CREATORS
1254inline
1255BerDecoder_UniversalElementVisitor::
1256BerDecoder_UniversalElementVisitor(BerDecoder *decoder)
1257: d_node(decoder)
1258{
1259}
1260
1261// MANIPULATORS
1262template <typename TYPE>
1264{
1265 int alternateTag = -1;
1266 BerUniversalTagNumber::Value expectedTagNumber =
1268 d_node.formattingMode(),
1269 &alternateTag);
1270
1271 int rc = d_node.readTagHeader();
1272 if (rc != BerDecoder::e_BER_SUCCESS) {
1273 return rc; // error message is already logged
1274 }
1275
1276 if (d_node.tagClass() != BerConstants::e_UNIVERSAL) {
1277 return d_node.logError("Expected UNIVERSAL tag class");
1278 }
1279
1280 if (d_node.tagNumber() != static_cast<int>(expectedTagNumber)) {
1281 if (-1 == alternateTag || d_node.tagNumber() != alternateTag) {
1282 return d_node.logError("Unexpected tag number");
1283 }
1284 }
1285
1286 rc = d_node(variable);
1287
1288 if (rc != BerDecoder::e_BER_SUCCESS) {
1289 return rc;
1290 }
1291
1292 rc = d_node.readTagTrailer();
1293
1294 return rc;
1295}
1296
1297} // close package namespace
1298
1299#endif
1300
1301// ----------------------------------------------------------------------------
1302// Copyright 2015 Bloomberg Finance L.P.
1303//
1304// Licensed under the Apache License, Version 2.0 (the "License");
1305// you may not use this file except in compliance with the License.
1306// You may obtain a copy of the License at
1307//
1308// http://www.apache.org/licenses/LICENSE-2.0
1309//
1310// Unless required by applicable law or agreed to in writing, software
1311// distributed under the License is distributed on an "AS IS" BASIS,
1312// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1313// See the License for the specific language governing permissions and
1314// limitations under the License.
1315// ----------------------------- END-OF-FILE ----------------------------------
1316
1317/** @} */
1318/** @} */
1319/** @} */
Definition balber_berdecoderoptions.h:76
const int & maxSequenceSize() const
Definition balber_berdecoderoptions.h:737
Definition balber_berdecoder.h:521
int operator()(TYPE *variable, const INFO &info)
Definition balber_berdecoder.h:1241
Definition balber_berdecoder.h:355
BerDecoder_Node(BerDecoder *decoder, const TYPE *variable)
BerConstants::TagType tagType() const
Return the BER tag type for this node.
Definition balber_berdecoder.h:830
BerConstants::TagClass tagClass() const
Return the BER tag class for this node.
Definition balber_berdecoder.h:824
void setFieldName(const char *name)
Definition balber_berdecoder.h:867
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:848
BerDecoder_Node * parent() const
Return the address of the parent node.
Definition balber_berdecoder.h:818
int operator()(TYPE *object, bslmf::Nil)
Definition balber_berdecoder.h:874
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:861
void printStack(bsl::ostream &out) const
int tagNumber() const
Return the BER tag number for this node.
Definition balber_berdecoder.h:836
int length() const
Definition balber_berdecoder.h:854
int formattingMode() const
Return formatting mode for this node.
Definition balber_berdecoder.h:842
int startPos() const
Return the position of node tag from the beginning of input stream.
bool hasMore()
Definition balber_berdecoder.h:805
~BerDecoder_Node()
Definition balber_berdecoder.h:790
Definition balber_berdecoder.h:552
int operator()(TYPE *variable)
Definition balber_berdecoder.h:1263
Definition balber_berdecoder.h:584
~BerDecoder_Zeroer()
Definition balber_berdecoder.h:597
BerDecoder_Zeroer(const BerDecoderOptions **options)
Definition balber_berdecoder.h:592
Definition balber_berdecoder.h:172
int numUnknownElementsSkipped() const
Definition balber_berdecoder.h:758
bool maxDepthExceeded() const
Definition balber_berdecoder.h:752
int decode(bsl::streambuf *streamBuf, TYPE *variable)
Definition balber_berdecoder.h:685
bslstl::StringRef loggedMessages() const
Definition balber_berdecoder.h:742
void setNumUnknownElementsSkipped(int value)
Definition balber_berdecoder.h:721
ErrorSeverity
Definition balber_berdecoder.h:224
@ BDEM_BER_SUCCESS
Definition balber_berdecoder.h:229
@ e_BER_SUCCESS
Definition balber_berdecoder.h:225
@ e_BER_ERROR
Definition balber_berdecoder.h:226
@ BDEM_BER_ERROR
Definition balber_berdecoder.h:230
BerDecoder(const BerDecoderOptions *options=0, bslma::Allocator *basicAllocator=0)
ErrorSeverity errorSeverity() const
Definition balber_berdecoder.h:736
const BerDecoderOptions * decoderOptions() const
Return the address of the BER decoder options.
Definition balber_berdecoder.h:730
Definition bdlsb_memoutstreambuf.h:212
Definition bslstl_vector.h:1025
Definition bslma_allocator.h:457
Definition bslstl_stringref.h:372
int length() const
Definition balber_berdecoder.h:638
const char * data() const
Definition balber_berdecoder.h:632
void reset()
Reset the internal streambuf to the empty state.
Definition balber_berdecoder.h:625
static int manipulateByCategory(TYPE *object, MANIPULATOR &manipulator)
Definition bdlat_typecategory.h:1404
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
#define BSLS_KEYWORD_OVERRIDE
Definition bsls_keyword.h:653
Definition balber_berconstants.h:82
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.
bool hasSelection(const TYPE &object, const char *selectionName, int selectionNameLength)
int manipulateSelection(TYPE *object, MANIPULATOR &manipulator)
int makeSelection(TYPE *object, int selectionId)
int convertFromBaseType(TYPE *object, const BASE_TYPE &value)
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 bdlb_printmethods.h:283
Definition balxml_encoderoptions.h:68
StringRefImp< char > StringRef
Definition bslstl_stringref.h:699
Definition balber_berconstants.h:90
TagType
Definition balber_berconstants.h:113
@ e_PRIMITIVE
Definition balber_berconstants.h:116
@ e_CONSTRUCTED
Definition balber_berconstants.h:117
TagClass
Definition balber_berconstants.h:92
@ e_CONTEXT_SPECIFIC
Definition balber_berconstants.h:97
@ e_UNIVERSAL
Definition balber_berconstants.h:95
Value
Definition balber_beruniversaltagnumber.h:194
static Value select(const TYPE &object, int formattingMode, int *alternateTag)
Definition balber_beruniversaltagnumber.h:595
static int getValue(bsl::streambuf *streamBuf, TYPE *value, int length, const BerDecoderOptions &options=BerDecoderOptions())
Definition balber_berutil.h:3920
@ k_INDEFINITE_LENGTH
Definition balber_berutil.h:199
static int fromIntOrFallbackIfEnabled(TYPE *result, int number)
Definition bdlat_enumutil.h:329
TYPE::BaseType Type
Definition bdlat_customizedtypefunctions.h:536
Definition bdlat_formattingmode.h:105
@ e_NILLABLE
Definition bdlat_formattingmode.h:121
@ e_UNTAGGED
Definition bdlat_formattingmode.h:118
Definition bdlat_typecategory.h:1035
Definition bdlat_typecategory.h:1036
Definition bdlat_typecategory.h:1037
Definition bdlat_typecategory.h:1034
Definition bdlat_typecategory.h:1038
Definition bdlat_typecategory.h:1039
Definition bdlat_typecategory.h:1040
Definition bdlat_typecategory.h:1041
This struct is empty and represents a nil type.
Definition bslmf_nil.h:131
Definition bsls_objectbuffer.h:276