Quick Links:

bal | bbl | bdl | bsl

Namespaces

Component balber_berencoder
[Package balber]

Provide a BER encoder class. More...

Namespaces

namespace  balber

Detailed Description

Outline
Purpose:
Provide a BER encoder class.
Classes:
balber::BerEncoder BER encoder
See also:
Component balber_berdecoder, bdem_bdemencoder, Component balxml_encoder
Description:
This component defines a single class, balber::BerEncoder, that contains a parameterized encode function. The encode function encodes data read from a specified stream and loads the corresponding object to an object of the parameterized type. The encode method is overloaded for two types of input streams:
  • bsl::streambuf
  • bsl::istream
This component encodes objects based on the X.690 BER specification. It can only be used with types supported by the bdlat framework.
Usage:
This section illustrates intended use of this component.
Example 1: Encoding an Employee Record:
Suppose that an "employee record" consists of a sequence of attributes -- name, age, and salary -- that are of types bsl::string, int, and float, respectively. Furthermore, we have a need to BER encode employee records as a sequence of values (for out-of-process consumption).
Assume that we have defined a usage::EmployeeRecord class to represent employee record values, and assume that we have provided the bdlat specializations that allow the balber codec components to represent class values as a sequence of BER primitive values. See bdlat_sequencefunctions|Usage for details of creating specializations for a sequence type.
First, we create an employee record object having typical values:
  usage::EmployeeRecord bob("Bob", 56, 1234.00);
  assert("Bob"   == bob.name());
  assert(  56    == bob.age());
  assert(1234.00 == bob.salary());
Now, we create a balber::Encoder object and use it to encode our bob object. Here, to facilitate the examination of our results, the BER encoding data is delivered to a bslsb::MemOutStreamBuf object:
  bdlsb::MemOutStreamBuf osb;
  balber::BerEncoder     encoder;
  int                    rc = encoder.encode(&osb, bob);
  assert( 0 == rc);
  assert(18 == osb.length());
Finally, we confirm that the generated BER encoding has the expected layout and values. We create an bdlsb::FixedMemInStreamBuf to manage our access to the data portion of the bdlsb::MemOutStreamBuf where our BER encoding resides: The balber_berutil component provides functions that allow us to decode the descriptive fields and values of the BER encoded sequence:
  balber::BerConstants::TagClass tagClass;
  balber::BerConstants::TagType  tagType;
  int                            tagNumber;
  int                            accumNumBytesConsumed = 0;
  int                            length;

  rc = balber::BerUtil::getIdentifierOctets(&isb,
                                            &tagClass,
                                            &tagType,
                                            &tagNumber,
                                            &accumNumBytesConsumed);
  assert(0                                             == rc);
  assert(balber::BerConstants::e_UNIVERSAL             == tagClass);
  assert(balber::BerConstants::e_CONSTRUCTED           == tagType);
  assert(balber::BerUniversalTagNumber::e_BER_SEQUENCE == tagNumber);

  rc = balber::BerUtil::getLength(&isb, &length, &accumNumBytesConsumed);
  assert(0                                    == rc);
  assert(balber::BerUtil::k_INDEFINITE_LENGTH == length);
The UNIVERSAL value in tagClass indicates that the tagNumber value represents a type in the BER standard, a BER_SEQUENCE, as we requested of the infrastructure (see the IsSequence specialization above). The tagType value of CONSTRUCTED indicates that this is a non-primitive type. The INDEFINITE value for length is typical for sequence encodings. In these cases, the end-of-data is indicated by a sequence to two null bytes.
We now examine the tags and values corresponding to each of the data members of usage::EmployeeRecord class. For each of these the tagClass is CONTEXT_SPECIFIC (i.e., member of a larger construct) and the tagType is PRIMITIVE (bsl::string, int, and float each correspond to a primitive BER type. The tagNumber for each field was defined (in the elided definiton) to correspond the position of the field in the usage::EmployeeRecord class.
  rc = balber::BerUtil::getIdentifierOctets(&isb,
                                            &tagClass,
                                            &tagType,
                                            &tagNumber,
                                            &accumNumBytesConsumed);
  assert(0                                        == rc);
  assert(balber::BerConstants::e_CONTEXT_SPECIFIC == tagClass);
  assert(balber::BerConstants::e_PRIMITIVE        == tagType);
  assert(1                                        == tagNumber);

  bsl::string name;
  rc = balber::BerUtil::getValue(&isb, &name, &accumNumBytesConsumed);
  assert(0     == rc);
  assert("Bob" == name);

  rc = balber::BerUtil::getIdentifierOctets(&isb,
                                            &tagClass,
                                            &tagType,
                                            &tagNumber,
                                            &accumNumBytesConsumed);
  assert(0                                        == rc);
  assert(balber::BerConstants::e_CONTEXT_SPECIFIC == tagClass);
  assert(balber::BerConstants::e_PRIMITIVE        == tagType);
  assert(2                                        == tagNumber);

  int age = 0;
  rc = balber::BerUtil::getValue(&isb, &age, &accumNumBytesConsumed);
  assert(0  == rc);
  assert(56 == age);

  rc = balber::BerUtil::getIdentifierOctets(&isb,
                                            &tagClass,
                                            &tagType,
                                            &tagNumber,
                                            &accumNumBytesConsumed);
  assert(0 == rc);
  assert(balber::BerConstants::e_CONTEXT_SPECIFIC == tagClass);
  assert(balber::BerConstants::e_PRIMITIVE        == tagType);
  assert(3                                        == tagNumber);

  float salary = 0.0;
  rc = balber::BerUtil::getValue(&isb, &salary, &accumNumBytesConsumed);
  assert(0       == rc);
  assert(1234.00 == salary);
Lastly, we confirm that end-of-data sequence (two null bytes) are found we expect them and that we have entirely consumed the data that we generated by our encoding.
  rc = balber::BerUtil::getEndOfContentOctets(&isb, &accumNumBytesConsumed);
  assert(0            == rc);
  assert(osb.length() == static_cast<bsl::size_t>(accumNumBytesConsumed));