BDE 4.14.0 Production release
Loading...
Searching...
No Matches
baljsn_decoder.h
Go to the documentation of this file.
1/// @file baljsn_decoder.h
2///
3/// The content of this file has been pre-processed for Doxygen.
4///
5
6
7// baljsn_decoder.h -*-C++-*-
8#ifndef INCLUDED_BALJSN_DECODER
9#define INCLUDED_BALJSN_DECODER
10
11#include <bsls_ident.h>
12BSLS_IDENT("$Id: $")
13
14/// @defgroup baljsn_decoder baljsn_decoder
15/// @brief Provide a JSON decoder for `bdeat` compatible types.
16/// @addtogroup bal
17/// @{
18/// @addtogroup baljsn
19/// @{
20/// @addtogroup baljsn_decoder
21/// @{
22///
23/// <h1> Outline </h1>
24/// * <a href="#baljsn_decoder-purpose"> Purpose</a>
25/// * <a href="#baljsn_decoder-classes"> Classes </a>
26/// * <a href="#baljsn_decoder-description"> Description </a>
27/// * <a href="#baljsn_decoder-validateinputisutf8-option"> validateInputIsUtf8 Option </a>
28/// * <a href="#baljsn_decoder-strict-conformance"> Strict Conformance </a>
29/// * <a href="#baljsn_decoder-usage"> Usage </a>
30/// * <a href="#baljsn_decoder-example-1-decoding-into-a-bas_codegen-pl-generated-from-data-in-json"> Example 1: Decoding into a bas_codegen.pl-generated from data in JSON </a>
31///
32/// # Purpose {#baljsn_decoder-purpose}
33/// Provide a JSON decoder for `bdeat` compatible types.
34///
35/// # Classes {#baljsn_decoder-classes}
36///
37/// - baljsn::Decoder: JSON decoder for `bdeat`-compliant types
38///
39/// @see baljsn_decoderoptions, balsjn_decoderoptionsutil,
40/// baljsn_encoder, baljsn_parserutil, baljsn_parser
41///
42/// # Description {#baljsn_decoder-description}
43/// This component provides a class, `baljsn::Decoder`, for
44/// decoding value-semantic objects in the JSON format. In particular, the
45/// `class` contains a parameterized `decode` function that decodes an object
46/// from a specified stream. There are two overloaded versions of this
47/// function:
48///
49/// * one that reads from a `bsl::streambuf`
50/// * one that reads from a `bsl::istream`
51///
52/// This component can be used with types that support the `bdeat` framework
53/// (see the `bdeat` package for details), which is a compile-time interface for
54/// manipulating struct-like and union-like objects. In particular, types
55/// generated by the `bas_codegen.pl` tool, and other dynamic types, can be
56/// decoded using this `class`. The `decode` function can be invoked on any
57/// object that satisfies the requirements of a sequence, choice, or array
58/// object as defined in the @ref bdlat_sequencefunctions , @ref bdlat_choicefunctions ,
59/// and @ref bdlat_arrayfunctions components.
60///
61/// Although the JSON format is easy to read and write and is very useful for
62/// debugging, it is relatively expensive to encode and decode and relatively
63/// bulky to transmit. It is more efficient to use a binary encoding (such as
64/// BER) if the encoding format is under your control (see @ref balber_berdecoder ).
65///
66/// Refer to the details of the JSON encoding format supported by this decoder
67/// in the package documentation file (doc/baljsn.txt).
68///
69/// ## validateInputIsUtf8 Option {#baljsn_decoder-validateinputisutf8-option}
70///
71///
72/// The `baljsn::DecoderOption` parameter of the `decode` function has a
73/// configuration option named `validateInputIsUtf8`. If this option is `true`,
74/// the `decode` function will succeed only if the encoding of the JSON data is
75/// UTF-8, which the JSON specification requires. If the option is `false`,
76/// `decode` will not validate that the encoding of the JSON data is UTF-8, and
77/// may succeed even if the data does not satisfy the UTF-8 validity requirement
78/// of the JSON specification. This option primarily affects the acceptance of
79/// string literals, which are the parts of JSON documents that may have
80/// rational justification for having non-UTF-8, and therefore invalid, content.
81///
82/// Ideally, users *should* set `validateInputIsUtf8` to `true`. However, some
83/// legacy applications currently might be trafficking in JSON that contains
84/// non-UTF-8 with no adverse effects to their clients. Consequently, this
85/// option is `false` by default to maintain backward compatibility.
86///
87/// ## Strict Conformance {#baljsn_decoder-strict-conformance}
88///
89///
90/// The `baljsn::Decoder` class allows several convenient variances from the
91/// JSON grammar as described in RFC8259 (see
92/// https://www.rfc-editor.org/rfc/rfc8259). If strict conformance is needed,
93/// users should use the `read` overloads that accept a `baljsn::DecoderOptions`
94/// object and set the following attributes to the values shown below:
95/// @code
96/// validateInputIsUtf8() == true;
97/// allowConsecutiveSeparators() == false;
98/// allowFormFeedAsWhitespace() == false;
99/// allowUnescapedControlCharacters() == false;
100/// @endcode
101/// See also {@ref bdljsn_tokenizer |Strict Conformance}.
102///
103/// ## Usage {#baljsn_decoder-usage}
104///
105///
106/// This section illustrates intended use of this component.
107///
108/// ## Example 1: Decoding into a bas_codegen.pl-generated from data in JSON {#baljsn_decoder-example-1-decoding-into-a-bas_codegen-pl-generated-from-data-in-json}
109///
110///
111/// Consider that we want to exchange an employee's information between two
112/// processes. To allow this information exchange we will define the XML schema
113/// representation for that class, use `bas_codegen.pl` to create the `Employee`
114/// `class` for storing that information, and decode into that object using the
115/// `baljsn` decoder.
116///
117/// First, we will define the XML schema inside a file called `employee.xsd`:
118/// @code
119/// <?xml version='1.0' encoding='UTF-8'?>
120/// <xs:schema xmlns:xs='http://www.w3.org/2001/XMLSchema'
121/// xmlns:test='http://bloomberg.com/schemas/test'
122/// targetNamespace='http://bloomberg.com/schemas/test'
123/// elementFormDefault='unqualified'>
124///
125/// <xs:complexType name='Address'>
126/// <xs:sequence>
127/// <xs:element name='street' type='xs:string'/>
128/// <xs:element name='city' type='xs:string'/>
129/// <xs:element name='state' type='xs:string'/>
130/// </xs:sequence>
131/// </xs:complexType>
132///
133/// <xs:complexType name='Employee'>
134/// <xs:sequence>
135/// <xs:element name='name' type='xs:string'/>
136/// <xs:element name='homeAddress' type='test:Address'/>
137/// <xs:element name='age' type='xs:int'/>
138/// </xs:sequence>
139/// </xs:complexType>
140///
141/// <xs:element name='Employee' type='test:Employee'/>
142///
143/// </xs:schema>
144/// @endcode
145/// Then, we will use the `bas_codegen.pl` tool, to generate the C++ classes for
146/// this schema. The following command will generate the header and
147/// implementation files for the all the classes in the @ref test_messages
148/// components in the current directory:
149/// @code
150/// $ bas_codegen.pl -m msg -p test xsdfile.xsd
151/// @endcode
152/// Next, we will create a `test::Employee` object:
153/// @code
154/// test::Employee employee;
155/// @endcode
156/// Then, we will create a `baljsn::Decoder` object:
157/// @code
158/// baljsn::Decoder decoder;
159/// @endcode
160/// Next, we will specify the input data provided to the decoder:
161/// @code
162/// const char INPUT[] = "{\"name\":\"Bob\",\"homeAddress\":{\"street\":"
163/// "\"Lexington Ave\",\"city\":\"New York City\","
164/// "\"state\":\"New York\"},\"age\":21}";
165///
166/// bsl::istringstream is(INPUT);
167/// @endcode
168/// Now, we will decode this object using the `decode` function of the baljsn
169/// decoder by providing it a `baljsn::DecoderOptions` object. The decoder
170/// options allow us to specify that unknown elements should *not* be skipped.
171/// Setting this option to `false` will result in the decoder returning an error
172/// on encountering an unknown element:
173/// @code
174/// baljsn::DecoderOptions options;
175/// options.setSkipUnknownElements(false);
176///
177/// const int rc = decoder.decode(is, &employee, options);
178/// assert(!rc);
179/// assert(is);
180/// @endcode
181/// Finally, we will verify that the decoded object is as expected:
182/// @code
183/// assert("Bob" == employee.name());
184/// assert("Lexington Ave" == employee.homeAddress().street());
185/// assert("New York City" == employee.homeAddress().city());
186/// assert("New York" == employee.homeAddress().state());
187/// assert(21 == employee.age());
188/// @endcode
189/// @}
190/** @} */
191/** @} */
192
193/** @addtogroup bal
194 * @{
195 */
196/** @addtogroup baljsn
197 * @{
198 */
199/** @addtogroup baljsn_decoder
200 * @{
201 */
202
203#include <balscm_version.h>
204
206#include <baljsn_parserutil.h>
207#include <baljsn_tokenizer.h>
208
209#include <bdlat_attributeinfo.h>
212#include <bdlat_enumfunctions.h>
213#include <bdlat_enumutil.h>
214#include <bdlat_formattingmode.h>
215#include <bdlat_selectioninfo.h>
217#include <bdlat_typecategory.h>
219
220#include <bdlb_printmethods.h>
221
223
224#include <bslmf_assert.h>
225#include <bslmf_isintegral.h>
226
227#include <bsls_assert.h>
228#include <bsls_types.h>
229
230#include <bsl_iostream.h>
231#include <bsl_sstream.h>
232#include <bsl_streambuf.h>
233#include <bsl_string.h>
234#include <bsl_string_view.h>
235
236
237namespace baljsn {
238
239 // =============
240 // class Decoder
241 // =============
242
243/// This class provides a mechanism for decoding JSON data into
244/// value-semantic objects. The `decode` methods are function templates
245/// that will decode any object that meets the requirements of a sequence,
246/// choice, or array object as defined in the @ref bdlat_sequencefunctions ,
247/// @ref bdlat_choicefunctions , and @ref bdlat_choicefunctions components
248/// respectively. These generic frameworks provide a common compile-time
249/// interface for manipulating struct-like and union-like objects. In
250/// particular, the types generated by `bas_codegen.pl` provide the
251/// necessary interface and can be decoded using this component.
252///
253/// See @ref baljsn_decoder
254class Decoder {
255
256 // DATA
257 bsl::ostringstream d_logStream; // stream to record errors
258 Tokenizer d_tokenizer; // JSON tokenizer
259 bsl::string d_elementName; // current element name
260 int d_currentDepth; // current decoding depth
261 int d_maxDepth; // max decoding depth
262 bool d_skipUnknownElements; // skip unknown elements flag
263
264 // FRIENDS
267
268 // PRIVATE MANIPULATORS
269
270 /// Decode into the specified `value`, of a (template parameter) `TYPE`
271 /// corresponding to the specified `bdeat` `category`, the JSON data
272 /// currently referred to by the tokenizer owned by this object, using
273 /// the specified formatting `mode`. Return 0 on success and a non-zero
274 /// value otherwise. The behavior is undefined unless `value`
275 /// corresponds to the specified `bdeat` category and `mode` is a valid
276 /// formatting mode as specified in `bdlat_FormattingMode`. Note that
277 /// `ANY_CATEGORY` shall be a tag-type defined in `bdlat_TypeCategory`.
278 template <class TYPE>
279 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::DynamicType);
280 template <class TYPE>
281 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Sequence);
282 template <class TYPE>
283 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Choice);
284 template <class TYPE>
285 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Enumeration);
286 template <class TYPE>
287 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::CustomizedType);
288 template <class TYPE>
289 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Simple);
290 template <class TYPE>
291 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Array);
292 template <class TYPE>
293 int decodeImp(TYPE *value, int mode, bdlat_TypeCategory::NullableValue);
294 int decodeImp(bsl::vector<char> *value,
295 int mode,
297 template <class TYPE, class ANY_CATEGORY>
298 int decodeImp(TYPE *value, ANY_CATEGORY category);
299
300 /// Log the latest tokenizer error to `d_logStream`. If the tokenizer
301 /// did not have an error, log the specified `alternateString`. Return
302 /// a reference to `d_logStream`.
303 bsl::ostream& logTokenizerError(const char *alternateString);
304
305 /// Skip the unknown element specified by `elementName` by discarding
306 /// all the data associated with it and advancing the parser to the next
307 /// element. Return 0 on success and a non-zero value otherwise.
308 int skipUnknownElement(const bsl::string_view& elementName);
309
310 private:
311 // NOT IMPLEMENTED
312 Decoder(const Decoder&);
313 Decoder& operator=(const Decoder&);
314
315 public:
316 // CREATORS
317
318 /// Construct a decoder object using the optionally specified
319 /// `basicAllocator`. If `basicAllocator` is 0, the default allocator
320 /// is used.
321 explicit Decoder(bslma::Allocator *basicAllocator = 0);
322
323 // MANIPULATORS
324
325 /// Decode into the specified `value`, of a (template parameter) `TYPE`,
326 /// the JSON data read from the specified `streamBuf` and using the
327 /// specified `options`. Specifying a nullptr `options` is equivalent
328 /// to passing a default-constructed DecoderOptions in `options`.
329 /// `TYPE` shall be a `bdeat`-compatible sequence, choice, or array
330 /// type, or a `bdeat`-compatible dynamic type referring to one of those
331 /// types. Return 0 on success, and a non-zero value otherwise. Note
332 /// that this operation internally buffers input from `streambuf`, and
333 /// if decoding is successful, will attempt to update the input position
334 /// of `streambuf` to the last unprocessed byte.
335 template <class TYPE>
336 int decode(bsl::streambuf *streamBuf,
337 TYPE *value,
338 const DecoderOptions& options);
339 template <class TYPE>
340 int decode(bsl::streambuf *streamBuf,
341 TYPE *value,
342 const DecoderOptions *options);
343
344 /// Decode into the specified `value`, of a (template parameter) `TYPE`,
345 /// the JSON data read from the specified `stream` and using the
346 /// specified `options`. `TYPE` shall be a `bdeat`-compatible sequence,
347 /// choice, or array type, or a `bdeat`-compatible dynamic type
348 /// referring to one of those types. Specifying a nullptr `options` is
349 /// equivalent to passing a default-constructed DecoderOptions in
350 /// `options`. Return 0 on success, and a non-zero value otherwise.
351 /// Note that this operation internally buffers input from `stream`, and
352 /// if decoding is successful, will attempt to update the input position
353 /// of `stream` to the last unprocessed byte.
354 template <class TYPE>
355 int decode(bsl::istream& stream,
356 TYPE *value,
357 const DecoderOptions& options);
358 template <class TYPE>
359 int decode(bsl::istream& stream,
360 TYPE *value,
361 const DecoderOptions *options);
362
363 /// Decode an object of (template parameter) `TYPE` from the specified
364 /// `streamBuf` and load the result into the specified modifiable `value`.
365 /// Return 0 on success, and a non-zero value otherwise.
366 ///
367 /// @deprecated Use @ref decode function passed a reference to a
368 /// non-modifiable `DecoderOptions` object instead.
369 template <class TYPE>
370 int decode(bsl::streambuf *streamBuf, TYPE *value);
371
372 /// Decode an object of (template parameter) `TYPE` from the specified
373 /// `stream` and load the result into the specified modifiable `value`.
374 /// Return 0 on success, and a non-zero value otherwise. Note that
375 /// `stream` will be invalidated if the decoding fails.
376 ///
377 /// @deprecated Use @ref decode function passed a reference to a
378 /// non-modifiable `DecoderOptions` object instead.
379 template <class TYPE>
380 int decode(bsl::istream& stream, TYPE *value);
381
382 // ACCESSORS
383
384 /// Return a string containing any error, warning, or trace messages that
385 /// were logged during the last call to the `decode` method. The log is
386 /// reset each time `decode` is called.
388};
389
390 // =============================
391 // struct Decoder_ElementVisitor
392 // =============================
393
394/// This `class` implements a visitor for decoding elements within a sequence,
395/// choice, or array type. This is a component-private class and should not be
396/// used outside of this component. Note that the operators provided in this
397/// `class` match the function signatures required of visitors decoding into
398/// elements of compatible types.
400
401 // DATA
402 Decoder *d_decoder_p; // decoder (held, not owned)
403 int d_mode; // formatting mode
404
405 // CREATORS
406
407 // Creators have been omitted to allow simple static initialization of this
408 // struct.
409
410 // MANIPULATORS
411
412 /// Decode into the specified `value` the data in the JSON format.
413 /// Return 0 on success and a non-zero value otherwise.
414 template <class TYPE>
415 int operator()(TYPE *value);
416
417 /// Decode into the specified `value` using the specified `info` the data
418 /// in the JSON format. Return 0 on success and a non-zero value
419 /// otherwise.
420 template <class TYPE, class INFO>
421 int operator()(TYPE *value, const INFO& info);
422};
423
424 // =============================
425 // struct Decoder_DecodeImpProxy
426 // =============================
427
428/// This class provides a functor that dispatches the appropriate `decodeImp`
429/// method for a `bdeat` Dynamic type. Note that the operators provided in
430/// this `class` match the function signatures required of visitors decoding
431/// into compatible types.
433
434 // DATA
435 Decoder *d_decoder_p; // decoder (held, not owned)
436 int d_mode; // formatting mode
437
438 // CREATORS
439
440 // Creators have been omitted to allow simple static initialization of this
441 // struct.
442
443 // MANIPULATORS
444 template <class TYPE>
445 int operator()(TYPE *, bslmf::Nil);
446
447 /// Dencode into the specified `value` of the specified `bdeat` `category`
448 /// from the data in the JSON format. Return 0 on success and a non-zero
449 /// value otherwise.
450 template <class TYPE, class ANY_CATEGORY>
451 int operator()(TYPE *object, ANY_CATEGORY category);
452};
453
454// ============================================================================
455// INLINE DEFINITIONS
456// ============================================================================
457
458 // -------------
459 // class Decoder
460 // -------------
461
462// PRIVATE MANIPULATORS
463template <class TYPE>
464inline
465int Decoder::decodeImp(TYPE *value, int mode, bdlat_TypeCategory::DynamicType)
466{
467 Decoder_DecodeImpProxy proxy = { this, mode };
469}
470
471template <class TYPE>
472int Decoder::decodeImp(TYPE *value, int mode, bdlat_TypeCategory::Sequence)
473{
475 // This is an anonymous element. Do not read anything and instead
476 // decode into the corresponding sub-element.
477
479 *value,
480 d_elementName.data(),
481 static_cast<int>(d_elementName.length()))) {
482 Decoder_ElementVisitor visitor = { this, mode };
483
485 value,
486 visitor,
487 d_elementName.data(),
488 static_cast<int>(d_elementName.length()))) {
489 d_logStream << "Could not decode sequence, error decoding "
490 << "element or bad element name '"
491 << d_elementName << "' \n";
492 return -1; // RETURN
493 }
494 }
495 else {
496 if (d_skipUnknownElements) {
497 const int rc = skipUnknownElement(d_elementName);
498 if (rc) {
499 d_logStream << "Error reading unknown element '"
500 << d_elementName << "' or after it\n";
501 return -1; // RETURN
502 }
503 }
504 else {
505 d_logStream << "Unknown element '" << d_elementName
506 << "' found\n";
507 return -1; // RETURN
508 }
509 }
510 }
511 else {
512 if (++d_currentDepth > d_maxDepth) {
513 d_logStream << "Maximum allowed decoding depth reached: "
514 << d_currentDepth << "\n";
515 return -1; // RETURN
516 }
517
518 if (Tokenizer::e_START_OBJECT != d_tokenizer.tokenType()) {
519 d_logStream << "Could not decode sequence, missing starting '{'\n";
520 return -1; // RETURN
521 }
522
523 int rc = d_tokenizer.advanceToNextToken();
524 if (rc) {
525 d_logStream << "Could not decode sequence, ";
526 logTokenizerError("error") << " reading token after '{'\n";
527 return -1; // RETURN
528 }
529
530 while (Tokenizer::e_ELEMENT_NAME == d_tokenizer.tokenType()) {
531
532 bslstl::StringRef elementName;
533 rc = d_tokenizer.value(&elementName);
534 if (rc) {
535 d_logStream << "Error reading attribute name after '{'\n";
536 return -1; // RETURN
537 }
538
540 *value,
541 elementName.data(),
542 static_cast<int>(elementName.length()))) {
543 d_elementName = elementName;
544
545 rc = d_tokenizer.advanceToNextToken();
546 if (rc) {
547 logTokenizerError("Error") << " reading value for"
548 << " attribute '" << d_elementName << "' \n";
549 return -1; // RETURN
550 }
551
552 Decoder_ElementVisitor visitor = { this, mode };
553
555 value,
556 visitor,
557 d_elementName.data(),
558 static_cast<int>(d_elementName.length()))) {
559 d_logStream << "Could not decode sequence, error decoding "
560 << "element or bad element name '"
561 << d_elementName << "' \n";
562 return -1; // RETURN
563 }
564 }
565 else {
566 if (d_skipUnknownElements) {
567 rc = skipUnknownElement(elementName);
568 if (rc) {
569 d_logStream << "Error reading unknown element '"
570 << elementName << "' or after it\n";
571 return -1; // RETURN
572 }
573 }
574 else {
575 d_logStream << "Unknown element '"
576 << elementName << "' found\n";
577 return -1; // RETURN
578 }
579 }
580
581 rc = d_tokenizer.advanceToNextToken();
582 if (rc) {
583 d_logStream << "Could not decode sequence, ";
584 logTokenizerError("error") << " reading token"
585 << " after value for attribute '"
586 << d_elementName << "' \n";
587 return -1; // RETURN
588 }
589 }
590
591 if (Tokenizer::e_END_OBJECT != d_tokenizer.tokenType()) {
592 d_logStream << "Could not decode sequence, "
593 << "missing terminator '}' or seperator ','\n";
594 return -1; // RETURN
595 }
596
597 --d_currentDepth;
598 }
599 return 0;
600}
601
602template <class TYPE>
603int Decoder::decodeImp(TYPE *value,
604 int mode,
606{
608 // This is an anonymous element. Do not read anything and instead
609 // decode into the corresponding sub-element.
610
611 bslstl::StringRef selectionName;
612 selectionName.assign(d_elementName.begin(), d_elementName.end());
613
615 *value,
616 selectionName.data(),
617 static_cast<int>(selectionName.length()))) {
619 value,
620 selectionName.data(),
621 static_cast<int>(selectionName.length()))) {
622 d_logStream << "Could not decode choice, bad selection name '"
623 << selectionName << "' \n";
624 return -1; // RETURN
625 }
626
627 Decoder_ElementVisitor visitor = { this, mode };
628
630 visitor)) {
631 d_logStream << "Could not decode choice, selection "
632 << "was not decoded\n";
633 return -1; // RETURN
634 }
635 }
636 else {
637 if (d_skipUnknownElements) {
638 const int rc = skipUnknownElement(selectionName);
639 if (rc) {
640 d_logStream << "Error reading unknown element '"
641 << selectionName << "' or after that "
642 << "element\n";
643 return -1; // RETURN
644 }
645 }
646 else {
647 d_logStream << "Unknown element '"
648 << selectionName << "' found\n";
649 return -1; // RETURN
650 }
651 }
652 }
653 else {
654 if (++d_currentDepth > d_maxDepth) {
655 d_logStream << "Maximum allowed decoding depth reached: "
656 << d_currentDepth << "\n";
657 return -1; // RETURN
658 }
659
660 if (Tokenizer::e_START_OBJECT != d_tokenizer.tokenType()) {
661 d_logStream << "Could not decode choice, missing starting {\n";
662 return -1; // RETURN
663 }
664
665 int rc = d_tokenizer.advanceToNextToken();
666 if (rc) {
667 d_logStream << "Could not decode choice, ";
668 logTokenizerError("error") << " reading token after {\n";
669 return -1; // RETURN
670 }
671
672 if (Tokenizer::e_ELEMENT_NAME == d_tokenizer.tokenType()) {
673 bslstl::StringRef selectionName;
674 rc = d_tokenizer.value(&selectionName);
675 if (rc) {
676 d_logStream << "Error reading selection name after '{'\n";
677 return -1; // RETURN
678 }
679
681 *value,
682 selectionName.data(),
683 static_cast<int>(selectionName.length()))) {
685 value,
686 selectionName.data(),
687 static_cast<int>(selectionName.length()))) {
688 d_logStream << "Could not decode choice, bad selection "
689 << "name '" << selectionName << "' \n";
690 return -1; // RETURN
691 }
692
693 rc = d_tokenizer.advanceToNextToken();
694 if (rc) {
695 d_logStream << "Could not decode choice, ";
696 logTokenizerError("error") << " reading value \n";
697 return -1; // RETURN
698 }
699
700 Decoder_ElementVisitor visitor = { this, mode };
701
703 visitor)) {
704 d_logStream << "Could not decode choice, selection "
705 << "was not decoded\n";
706 return -1; // RETURN
707 }
708 }
709 else {
710 if (d_skipUnknownElements) {
711 rc = skipUnknownElement(selectionName);
712 if (rc) {
713 d_logStream << "Error reading unknown element '"
714 << selectionName << "' or after that "
715 << "element\n";
716 return -1; // RETURN
717 }
718 }
719 else {
720 d_logStream << "Unknown element '"
721 << selectionName << "' found\n";
722 return -1; // RETURN
723 }
724 }
725
726 rc = d_tokenizer.advanceToNextToken();
727 if (rc) {
728 d_logStream << "Could not decode choice, ";
729 logTokenizerError("error") << " reading token after value for"
730 " selection \n";
731
732 return -1; // RETURN
733 }
734 }
735
736 if (Tokenizer::e_END_OBJECT != d_tokenizer.tokenType()) {
737 d_logStream << "Could not decode choice, "
738 << "missing terminator '}'\n";
739 return -1; // RETURN
740 }
741
742 --d_currentDepth;
743 }
744 return 0;
745}
746
747template <class TYPE>
748int Decoder::decodeImp(TYPE *value, int, bdlat_TypeCategory::Enumeration)
749{
750 enum { k_MIN_ENUM_STRING_LENGTH = 2 };
751
752 if (Tokenizer::e_ELEMENT_VALUE != d_tokenizer.tokenType()) {
753 d_logStream << "Enumeration element value was not found\n";
754 return -1; // RETURN
755 }
756
757 bslstl::StringRef dataValue;
758 int rc = d_tokenizer.value(&dataValue);
759 if (rc) {
760 d_logStream << "Error reading enumeration value\n";
761 return -1; // RETURN
762 }
763
764 if (dataValue.length() >= k_MIN_ENUM_STRING_LENGTH &&
765 '"' == dataValue.front() && '"' == dataValue.back()) {
766 const int kBufSize = 128;
768 bsl::string tmpString(&bufferAllocator);
769
770 rc = baljsn::ParserUtil::getValue(&tmpString, dataValue);
771 if (rc) {
772 d_logStream << "Error reading enumeration value\n";
773 return -1; // RETURN
774 }
775
777 value, tmpString.data(), static_cast<int>(tmpString.size()));
778 if (rc) {
779 d_logStream << "Could not decode Enum String, value not allowed \""
780 << dataValue << "\"\n";
781 }
782
783 return rc; // RETURN
784 }
785
786 // We also accept an unquoted integer (DRQS 166048981).
787 int intValue;
788 rc = ParserUtil::getValue(&intValue, dataValue);
789 if (rc) {
790 d_logStream << "Error reading enumeration value\n";
791 return -1; // RETURN
792 }
793
795 if (rc) {
796 d_logStream << "Could not decode int Enum, value " << intValue
797 << " not allowed\n";
798 }
799
800 return rc;
801}
802
803template <class TYPE>
804int Decoder::decodeImp(TYPE *value, int, bdlat_TypeCategory::CustomizedType)
805{
806 if (Tokenizer::e_ELEMENT_VALUE != d_tokenizer.tokenType()) {
807 d_logStream << "Customized element value was not found\n";
808 return -1; // RETURN
809 }
810
811 bslstl::StringRef dataValue;
812 int rc = d_tokenizer.value(&dataValue);
813 if (rc) {
814 d_logStream << "Error reading customized type value\n";
815 return -1; // RETURN
816 }
817
818 typedef
820
821 BaseType valueBaseType;
822
823 rc = ParserUtil::getValue(&valueBaseType, dataValue);
824 // For integral base types, we also accept a quoted representation
825 // (DRQS 166048981).
826 if (bsl::is_integral<BaseType>::value && 0 != rc &&
827 ParserUtil::stripQuotes(&dataValue)) {
828 rc = ParserUtil::getValue(&valueBaseType, dataValue);
829 }
830 if (rc) {
831 d_logStream << "Could not decode Enum Customized, "
832 << "value not allowed \"" << dataValue << "\"\n";
833 return -1; // RETURN
834 }
835
837 valueBaseType);
838 if (rc) {
839 d_logStream << "Could not convert base type to customized type, "
840 << "base value disallowed: \"";
841 bdlb::PrintMethods::print(d_logStream, valueBaseType, 0, -1);
842 d_logStream << "\"\n";
843 }
844 return rc;
845}
846
847template <class TYPE>
848int Decoder::decodeImp(TYPE *value, int, bdlat_TypeCategory::Simple)
849{
850 if (Tokenizer::e_ELEMENT_VALUE != d_tokenizer.tokenType()) {
851 d_logStream << "Simple element value was not found\n";
852 return -1; // RETURN
853 }
854
855 bslstl::StringRef dataValue;
856 int rc = d_tokenizer.value(&dataValue);
857 if (rc) {
858 d_logStream << "Error reading simple value\n";
859 return -1; // RETURN
860 }
861
862 rc = ParserUtil::getValue(value, dataValue);
863 // For integral types, we also accept a quoted representation
864 // (DRQS 166048981).
865 if (bsl::is_integral<TYPE>::value && 0 != rc &&
866 ParserUtil::stripQuotes(&dataValue)) {
867 rc = ParserUtil::getValue(value, dataValue);
868 }
869 return rc;
870}
871
872inline
873int Decoder::decodeImp(bsl::vector<char> *value,
874 int,
876{
877 if (Tokenizer::e_ELEMENT_VALUE != d_tokenizer.tokenType()) {
878 d_logStream << "Could not decode vector<char> "
879 << "expected as an element value\n";
880 return -1; // RETURN
881 }
882
883 bslstl::StringRef dataValue;
884 int rc = d_tokenizer.value(&dataValue);
885
886 if (rc) {
887 d_logStream << "Error reading customized type element value\n";
888 return -1; // RETURN
889 }
890
891 return ParserUtil::getValue(value, dataValue);
892}
893
894template <class TYPE>
895int Decoder::decodeImp(TYPE *value,
896 int mode,
898{
899 if (Tokenizer::e_START_ARRAY != d_tokenizer.tokenType()) {
900 d_logStream << "Could not decode vector, missing start token: '['\n";
901 return -1; // RETURN
902 }
903
904 int rc = d_tokenizer.advanceToNextToken();
905 if (rc) {
906 logTokenizerError("Error") << " reading array.\n";
907 return rc; // RETURN
908 }
909
910 int i = 0;
911 while (Tokenizer::e_END_ARRAY != d_tokenizer.tokenType()) {
912 if (Tokenizer::e_ELEMENT_VALUE == d_tokenizer.tokenType()
913 || Tokenizer::e_START_OBJECT == d_tokenizer.tokenType()
914 || Tokenizer::e_START_ARRAY == d_tokenizer.tokenType()) {
915 ++i;
917
918 Decoder_ElementVisitor visitor = { this, mode };
919
921 visitor,
922 i - 1)) {
923 d_logStream << "Error adding element '" << i - 1 << "'\n";
924 return -1; // RETURN
925 }
926
927 rc = d_tokenizer.advanceToNextToken();
928 if (rc) {
929 logTokenizerError("Error") << " reading token after value of"
930 " element '" << i - 1 << "'\n";
931 return rc; // RETURN
932 }
933 }
934 else {
935 d_logStream << "Erroneous token found instead of array element\n";
936 return -1; // RETURN
937 }
938 }
939
940 if (Tokenizer::e_END_ARRAY != d_tokenizer.tokenType()) {
941 d_logStream << "Could not decode vector, missing end token: ']'\n";
942 return -1; // RETURN
943 }
944
945 return 0;
946}
947
948template <class TYPE>
949int Decoder::decodeImp(TYPE *value,
950 int mode,
952{
953 enum { k_NULL_VALUE_LENGTH = 4 };
954
955 if (Tokenizer::e_ELEMENT_VALUE == d_tokenizer.tokenType()) {
956 bslstl::StringRef dataValue;
957 const int rc = d_tokenizer.value(&dataValue);
958 if (rc) {
959 return rc; // RETURN
960 }
961
962 if (k_NULL_VALUE_LENGTH == dataValue.length()
963 && 'n' == dataValue[0]
964 && 'u' == dataValue[1]
965 && 'l' == dataValue[2]
966 && 'l' == dataValue[3]) {
967 return 0; // RETURN
968 }
969 }
970
972
973 Decoder_ElementVisitor visitor = { this, mode };
975}
976
977template <class TYPE, class ANY_CATEGORY>
978inline
979int Decoder::decodeImp(TYPE *, ANY_CATEGORY)
980{
981 BSLS_ASSERT_OPT(0 == "Unreachable");
982
983 return -1;
984}
985
986// CREATORS
987inline
988Decoder::Decoder(bslma::Allocator *basicAllocator)
989: d_logStream(basicAllocator)
990, d_tokenizer(basicAllocator)
991, d_elementName(basicAllocator)
992, d_currentDepth(0)
993, d_maxDepth(0)
994, d_skipUnknownElements(false)
995{
996}
997
998// MANIPULATORS
999template <class TYPE>
1000int Decoder::decode(bsl::streambuf *streamBuf,
1001 TYPE *value,
1002 const DecoderOptions& options)
1003{
1004 BSLS_ASSERT(streamBuf);
1005 BSLS_ASSERT(value);
1006
1007 d_logStream.clear();
1008 d_logStream.str("");
1009
1010 bdlat_TypeCategory::Value category =
1012
1015 && bdlat_TypeCategory::e_ARRAY_CATEGORY != category) {
1016 d_logStream << "The object being decoded must be a Sequence, "
1017 << "Choice, or Array type\n";
1018 return -1; // RETURN
1019 }
1020
1021 d_tokenizer.reset(streamBuf);
1022 d_tokenizer
1024 .setAllowHeterogenousArrays(true) // needed for nillable arrays
1031
1032 typedef typename bdlat_TypeCategory::Select<TYPE>::Type TypeCategory;
1033
1034 int rc = d_tokenizer.advanceToNextToken();
1035 if (rc) {
1036 logTokenizerError("Error") << " advancing to the first token. "
1037 "Expecting a '{' or '[' as the first character\n";
1038 return rc; // RETURN
1039 }
1040
1042
1043 d_maxDepth = options.maxDepth();
1044 d_skipUnknownElements = options.skipUnknownElements();
1045
1046 rc = decodeImp(value, 0, TypeCategory());
1047
1048 d_tokenizer.resetStreamBufGetPointer();
1049
1050 return rc;
1051}
1052
1053template <class TYPE>
1054int Decoder::decode(bsl::streambuf *streamBuf,
1055 TYPE *value,
1056 const DecoderOptions *options)
1057{
1058 DecoderOptions localOpts;
1059 return decode(streamBuf, value, options ? *options : localOpts);
1060}
1061
1062template <class TYPE>
1063int Decoder::decode(bsl::istream& stream,
1064 TYPE *value,
1065 const DecoderOptions& options)
1066{
1067 if (!stream.good()) {
1068 d_logStream
1069 << "Input stream state is not 'good()' ["
1070 << (stream.bad() ? " 'bad()'" : "")
1071 << (stream.fail() ? " 'fail()'" : "")
1072 << (stream.eof() ? " 'eof()'" : "")
1073 << " ] - nothing to decode\n";
1074 return -1; // RETURN
1075 }
1076
1077 if (0 != decode(stream.rdbuf(), value, options)) {
1078 stream.setstate(bsl::ios_base::failbit);
1079 return -1; // RETURN
1080 }
1081
1082 return 0;
1083}
1084
1085template <class TYPE>
1086int Decoder::decode(bsl::istream& stream,
1087 TYPE *value,
1088 const DecoderOptions *options)
1089{
1090 DecoderOptions localOpts;
1091 return decode(stream, value, options ? *options : localOpts);
1092}
1093
1094template <class TYPE>
1095int Decoder::decode(bsl::streambuf *streamBuf, TYPE *value)
1096{
1097 const DecoderOptions options;
1098 return decode(streamBuf, value, options);
1099}
1100
1101template <class TYPE>
1102int Decoder::decode(bsl::istream& stream, TYPE *value)
1103{
1104 const DecoderOptions options;
1105 return decode(stream, value, options);
1106}
1107
1108// ACCESSORS
1109inline
1111{
1112 return d_logStream.str();
1113}
1114
1115 // -----------------------------
1116 // struct Decoder_ElementVisitor
1117 // -----------------------------
1118
1119template <class TYPE>
1120inline
1122{
1123 typedef typename bdlat_TypeCategory::Select<TYPE>::Type TypeCategory;
1124 return d_decoder_p->decodeImp(value, d_mode, TypeCategory());
1125}
1126
1127template <class TYPE, class INFO>
1128inline
1129int Decoder_ElementVisitor::operator()(TYPE *value, const INFO& info)
1130{
1131 typedef typename bdlat_TypeCategory::Select<TYPE>::Type TypeCategory;
1132 return d_decoder_p->decodeImp(value,
1133 info.formattingMode(),
1134 TypeCategory());
1135}
1136
1137 // -----------------------------
1138 // struct Decoder_DecodeImpProxy
1139 // -----------------------------
1140
1141// MANIPULATORS
1142template <class TYPE>
1143inline
1145{
1146 BSLS_ASSERT_OPT(0 == "Unreachable");
1147
1148 return -1;
1149}
1150
1151template <class TYPE, class ANY_CATEGORY>
1152inline
1154 ANY_CATEGORY category)
1155{
1156 return d_decoder_p->decodeImp(object, d_mode, category);
1157}
1158
1159} // close package namespace
1160
1161
1162#endif
1163
1164// ----------------------------------------------------------------------------
1165// Copyright 2015 Bloomberg Finance L.P.
1166//
1167// Licensed under the Apache License, Version 2.0 (the "License");
1168// you may not use this file except in compliance with the License.
1169// You may obtain a copy of the License at
1170//
1171// http://www.apache.org/licenses/LICENSE-2.0
1172//
1173// Unless required by applicable law or agreed to in writing, software
1174// distributed under the License is distributed on an "AS IS" BASIS,
1175// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
1176// See the License for the specific language governing permissions and
1177// limitations under the License.
1178// ----------------------------- END-OF-FILE ----------------------------------
1179
1180/** @} */
1181/** @} */
1182/** @} */
Definition baljsn_decoderoptions.h:153
bool validateInputIsUtf8() const
Definition baljsn_decoderoptions.h:697
bool allowUnescapedControlCharacters() const
Definition baljsn_decoderoptions.h:715
bool skipUnknownElements() const
Definition baljsn_decoderoptions.h:691
bool allowConsecutiveSeparators() const
Definition baljsn_decoderoptions.h:703
bool allowFormFeedAsWhitespace() const
Definition baljsn_decoderoptions.h:709
int maxDepth() const
Return the value of the "MaxDepth" attribute of this object.
Definition baljsn_decoderoptions.h:685
Definition baljsn_decoder.h:254
friend struct Decoder_ElementVisitor
Definition baljsn_decoder.h:266
int decode(bsl::streambuf *streamBuf, TYPE *value, const DecoderOptions &options)
Definition baljsn_decoder.h:1000
bsl::string loggedMessages() const
Definition baljsn_decoder.h:1110
Definition bdljsn_tokenizer.h:234
int resetStreamBufGetPointer()
TokenType tokenType() const
Return the token type of the current token.
Definition bdljsn_tokenizer.h:925
Tokenizer & setAllowConsecutiveSeparators(bool value)
Definition bdljsn_tokenizer.h:771
Tokenizer & setAllowHeterogenousArrays(bool value)
Definition bdljsn_tokenizer.h:780
Tokenizer & setAllowStandAloneValues(bool value)
Definition bdljsn_tokenizer.h:807
Tokenizer & setAllowUnescapedControlCharacters(bool value)
Definition bdljsn_tokenizer.h:825
Tokenizer & setAllowTrailingTopLevelComma(bool value)
Definition bdljsn_tokenizer.h:816
Tokenizer & setAllowFormFeedAsWhitespace(bool value)
Definition bdljsn_tokenizer.h:789
void reset(bsl::streambuf *streambuf)
Definition bdljsn_tokenizer.h:753
Tokenizer & setAllowNonUtf8StringLiterals(bool value)
Definition bdljsn_tokenizer.h:798
@ e_ELEMENT_NAME
Definition bdljsn_tokenizer.h:245
@ e_END_OBJECT
Definition bdljsn_tokenizer.h:247
@ e_END_ARRAY
Definition bdljsn_tokenizer.h:249
@ e_ELEMENT_VALUE
Definition bdljsn_tokenizer.h:250
@ e_START_ARRAY
Definition bdljsn_tokenizer.h:248
@ e_START_OBJECT
Definition bdljsn_tokenizer.h:246
int value(bsl::string_view *data) const
Definition bdlma_localsequentialallocator.h:230
Definition bslstl_ostringstream.h:175
void str(const StringType &value)
Definition bslstl_ostringstream.h:581
Definition bslstl_stringview.h:441
BSLS_KEYWORD_CONSTEXPR_CPP14 const_reference back() const
Definition bslstl_stringview.h:1749
BSLS_KEYWORD_CONSTEXPR_CPP14 const_reference front() const
Definition bslstl_stringview.h:1738
Definition bslstl_string.h:1281
size_type length() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6601
iterator end() BSLS_KEYWORD_NOEXCEPT
Return the past-the-end iterator for this modifiable string.
Definition bslstl_string.h:5452
CHAR_TYPE * data() BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:6477
void swap(basic_string &other) BSLS_KEYWORD_NOEXCEPT_SPECIFICATION(AllocatorTraits const_iterator begin() const BSLS_KEYWORD_NOEXCEPT
Definition bslstl_string.h:2533
Definition bslstl_vector.h:1025
Definition bslma_allocator.h:457
Definition bslstl_stringref.h:372
const CHAR_TYPE * data() const
Definition bslstl_stringref.h:936
size_type length() const
Definition bslstl_stringref.h:958
void assign(const CHAR_TYPE *data, INT_TYPE length, typename bsl::enable_if< bsl::is_integral< INT_TYPE >::value, bslmf::Nil >::type=bslmf::Nil())
Definition bslstl_stringref.h:821
static int manipulateByCategory(TYPE *object, MANIPULATOR &manipulator)
Definition bdlat_typecategory.h:1404
#define BSLS_ASSERT(X)
Definition bsls_assert.h:1804
#define BSLS_ASSERT_OPT(X)
Definition bsls_assert.h:1856
#define BSLS_IDENT(str)
Definition bsls_ident.h:195
Definition baljsn_datumdecoderoptions.h:113
int manipulateElement(TYPE *array, MANIPULATOR &manipulator, int index)
void resize(TYPE *array, int newSize)
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)
bdlat_TypeCategory::Value select(const TYPE &object)
void reset(TYPE *object)
Reset the value of the specified object to its default value.
bsl::ostream & print(bsl::ostream &stream, const TYPE &object, int level=0, int spacesPerLevel=4)
Definition bdlb_printmethods.h:719
Definition baljsn_decoder.h:432
int operator()(TYPE *, bslmf::Nil)
Definition baljsn_decoder.h:1144
int d_mode
Definition baljsn_decoder.h:436
Decoder * d_decoder_p
Definition baljsn_decoder.h:435
Definition baljsn_decoder.h:399
int d_mode
Definition baljsn_decoder.h:403
int operator()(TYPE *value)
Definition baljsn_decoder.h:1121
Decoder * d_decoder_p
Definition baljsn_decoder.h:402
static int getValue(bool *value, const bsl::string_view &data)
static bool stripQuotes(bsl::string_view *str)
static int fromIntOrFallbackIfEnabled(TYPE *result, int number)
Definition bdlat_enumutil.h:329
static int fromStringOrFallbackIfEnabled(TYPE *result, const char *string, int stringLength)
Definition bdlat_enumutil.h:343
TYPE::BaseType Type
Definition bdlat_customizedtypefunctions.h:536
@ 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
Value
Definition bdlat_typecategory.h:1044
@ e_ARRAY_CATEGORY
Definition bdlat_typecategory.h:1046
@ e_CHOICE_CATEGORY
Definition bdlat_typecategory.h:1047
@ e_SEQUENCE_CATEGORY
Definition bdlat_typecategory.h:1051
Definition bslmf_isintegral.h:130
This struct is empty and represents a nil type.
Definition bslmf_nil.h:131