// bslx_marshallingutil.h -*-C++-*- #ifndef INCLUDED_BSLX_MARSHALLINGUTIL #define INCLUDED_BSLX_MARSHALLINGUTIL #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Support platform-independent marshalling of fundamental types. // //@CLASSES: // bslx::MarshallingUtil: namespace for put/get marshalling functions // //@SEE_ALSO: bslx_byteinstream, bslx_byteoutstream // //@DESCRIPTION: This component provides a byte-array-based implementation, // 'bslx::MarshallingUtil', for a suite of marshalling functions used to // convert values (and arrays of values) of the following fundamental integer // and floating-point types: //.. // C++ TYPE REQUIRED CONTENT OF ANY PLATFORM-NEUTRAL FORMAT // -------- ----------------------------------------------- // Int64 least significant 64 bits (signed) // Uint64 least significant 64 bits (unsigned) // int least significant 32 bits (signed) // unsigned int least significant 32 bits (unsigned) // short least significant 16 bits (signed) // unsigned short least significant 16 bits (unsigned) // char least significant 8 bits (platform-dependent) // signed char least significant 8 bits (signed) // unsigned char least significant 8 bits (unsigned) // double IEEE standard 8-byte floating-point value // float IEEE standard 4-byte floating-point value //.. // In addition to basic marshalling functions, where each marshalled instance // of a fundamental type occupies the same number of bytes in the stream // (regardless of its value), this component provides an interface for // efficient marshalling of integer types. In particular, 64-bit values can be // streamed as 40-, 48-, 56-, or 64-bit values, and 32-bit values can be // streamed as 24- or 32-bit values. Marshalled integers are written and // assumed to be in two's complement, big-endian format (i.e., network byte // order). Floating-point formats are described below. // ///Note on Function Naming and Interface ///------------------------------------- // The names and interfaces of the functions of 'bslx::MarshallingUtil' follow // a systematic fashion explained below. This makes it easier to guess the // name and signature of the intended function. In what follows, 'buffer' is // always of type 'char *' or 'const char *' depending on whether it is used as // an input or an output, and 'variable' and 'value' are of a type that depends // on the name of the function and intended width, with 'variable' used as an // output, while 'value' is used as an input. // // Here are the 'get...' functions for integral and floating-point scalar // types: //.. // Name Type of 'variable' Notes // ---- ------------------ ----- // getIntNN(variable, buffer) bsls::Types::Int64 * NN=64,56,48,40 // int * NN=32,24 // short * NN=16 // char * NN=8 // signed char * NN=8 // unsigned char * NN=8 // // getUintNN(variable, buffer) bsls::Types::Uint64 * NN=64,56,48,40 // unsigned int * NN=32,24 // unsigned short * NN=16 // // getFloatNN(variable, buffer) double * NN=64 // float * NN=32 //.. // Here are the 'put...' functions for scalar types. Note that there is no // 'putUintNN' since 'putIntNN' applies equally to unsigned 'NN'-bit values // (through a conversion to a signed value): //.. // Name Type of 'value' Notes // ---- --------------- ----- // putIntNN(buffer, value) bsls::Types::Int64 NN=64,56,48,40 // int NN=32,24,16,8 // // putFloatNN(buffer, value) double NN=64 // float NN=32 //.. // Here are the 'getArray...' functions for integral and floating-point scalar // array types: //.. // Name Type of 'variables' Notes // ---- ---------------- ----- // getArrayIntNN(variables, bsls::Types::Int64 * NN=64,56,48,40 // buffer, int * NN=32,24 // numVariables) short * NN=16 // char * NN=8 // signed char * NN=8 // unsigned char * NN=8 // // getArrayUintNN(variables, bsls::Types::Uint64 * NN=64,56,48,40 // buffer, unsigned int * NN=32,24 // numVariables) unsigned short * NN=16 // // getArrayFloatNN(variables, double * NN=64 // buffer, float * NN=32 // numVariables) //.. // Finally, the 'putArray...' functions follow. Note that this time there is // an overload for unsigned types, but that the function name is still // 'putArrayInt...' for arrays of both signed and unsigned integrals: //.. // Name Type of 'values' Notes // ---- --------------- ----- // putArrayIntNN(buffer, const bsls::Types::Int64 * NN=64,56,48,40 // values, const bsls::Types::Uint64 * NN=64,56,48,40 // numValues) const int * NN=32,24 // const unsigned int * NN=32,24 // const short * NN=16 // const unsigned short * NN=16 // const char * NN=8 // const signed char * NN=8 // const unsigned char * NN=8 // // putArrayFloatNN(buffer, const double * NN=64 // values, const float * NN=32 // numValues) //.. // ///IEEE 754 Double-Precision Format ///-------------------------------- // A 'double' is assumed to be *at* *least* 64 bits in size. The externalized // byte representation of a 64-bit floating-point value is defined to conform // to the IEEE double-precision format illustrated below. If the native // representation of a 64-bit floating-point value does not match this format, // a conversion process to and from this format is performed. This conversion // may (of course) be lossy: //.. // sign bit 11-bit exponent 52-bit significand // / / / // +-+-----------+----------------------------------------------------+ // |s|e10......e0|m51...............................................m0| // +-+-----------+----------------------------------------------------+ // LSB MSB //.. // ///IEEE 754 Single-Precision Format ///-------------------------------- // A 'float' is assumed to be *at* *least* 32 bits in size. The externalized // byte representation of a 32-bit floating-point value is defined to conform // to the IEEE single-precision format illustrated below. If the native // representation of a 32-bit floating-point value does not match this format, // a conversion process to and from this format is performed. This conversion // may (of course) be lossy: //.. // sign bit 8-bit exponent 23-bit significand // / / / // +-+--------+-----------------------+ // |s|e7....e0|m22..................m0| // +-+--------+-----------------------+ // LSB MSB //.. // ///Usage ///----- // This section illustrates intended use of this component. // ///Example 1: Round-Trip Marshalling ///- - - - - - - - - - - - - - - - - // The 'bslx::MarshallingUtil' component can be used stand-alone to marshal a // platform-neutral representation of fundamental data and arrays of // fundamental data to and from a buffer. In this example, the round-trip // marshalling of an 'int' and an array of 'int' values will be demonstrated. // First, declare the buffer and the data to be marshalled: //.. // char buffer[32]; // int value = 17; // int values[] = { 1, 2, 3 }; //.. // Then, marshal all data into the 'buffer': //.. // bslx::MarshallingUtil::putInt32(buffer + 0, value); // bslx::MarshallingUtil::putArrayInt32(buffer + 4, values, 3); //.. // Next, declare variables to hold the values to be extracted from the // 'buffer': //.. // int newValue = 0; // int newValues[] = { 0, 0, 0 }; //.. // Finally, marshal the data from the 'buffer' to these variables and confirm // the round-trip marshalling was successful: //.. // bslx::MarshallingUtil::getInt32(&newValue, buffer + 0); // bslx::MarshallingUtil::getArrayInt32(newValues, buffer + 4, 3); // // assert(newValue == value); // assert(newValues[0] == values[0]); // assert(newValues[1] == values[1]); // assert(newValues[2] == values[2]); //.. #include <bslscm_version.h> #include <bsls_assert.h> #include <bsls_platform.h> #include <bsls_types.h> #include <bsl_cstring.h> // for 'bsl::memcpy' namespace BloombergLP { namespace bslx { // ====================== // struct MarshallingUtil // ====================== struct MarshallingUtil { // This 'struct' provides a namespace for a suite of functions that // facilitate the marshalling of values, and C-style arrays of values, of // the fundamental integral and floating-point types in a data-independent, // platform-neutral representation. // TYPES enum { // Enumerate the platform-independent sizes (in bytes) of data types in // wire format. Note that the wire format size may differ from the // size in memory. k_SIZEOF_INT64 = 8, k_SIZEOF_INT56 = 7, k_SIZEOF_INT48 = 6, k_SIZEOF_INT40 = 5, k_SIZEOF_INT32 = 4, k_SIZEOF_INT24 = 3, k_SIZEOF_INT16 = 2, k_SIZEOF_INT8 = 1, k_SIZEOF_FLOAT64 = 8, k_SIZEOF_FLOAT32 = 4 }; // CLASS METHODS // *** put scalar integral values *** static void putInt64(char *buffer, bsls::Types::Int64 value); // Load into the specified 'buffer' the eight-byte, two's complement // integer (in network byte order) comprised of the least-significant // eight bytes of the specified 'value' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity. Note // that this function applies equally to unsigned 64-bit values. static void putInt56(char *buffer, bsls::Types::Int64 value); // Load into the specified 'buffer' the seven-byte, two's complement // integer (in network byte order) comprised of the least-significant // seven bytes of the specified 'value' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity. Note // that this function applies equally to unsigned 64-bit values. static void putInt48(char *buffer, bsls::Types::Int64 value); // Load into the specified 'buffer' the six-byte, two's complement // integer (in network byte order) comprised of the least-significant // six bytes of the specified 'value' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity. Note // that this function applies equally to unsigned 64-bit values. static void putInt40(char *buffer, bsls::Types::Int64 value); // Load into the specified 'buffer' the five-byte, two's complement // integer (in network byte order) comprised of the least-significant // five bytes of the specified 'value' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity. Note // that this function applies equally to unsigned 64-bit values. static void putInt32(char *buffer, int value); // Load into the specified 'buffer' the four-byte, two's complement // integer (in network byte order) comprised of the least-significant // four bytes of the specified 'value' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity. Note // that this function applies equally to unsigned 32-bit values, and // signed and unsigned 16- and 8-bit values. static void putInt24(char *buffer, int value); // Load into the specified 'buffer' the three-byte, two's complement // integer (in network byte order) comprised of the least-significant // three bytes of the specified 'value' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity. Note // that this function applies equally to unsigned 32-bit values, and // signed and unsigned 16- and 8-bit values. static void putInt16(char *buffer, int value); // Load into the specified 'buffer' the two-byte, two's complement // integer (in network byte order) comprised of the least-significant // two bytes of the specified 'value' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity. Note // that this function applies equally to unsigned 32-bit values, and // signed and unsigned 16- and 8-bit values. static void putInt8(char *buffer, int value); // Load into the specified 'buffer' the one-byte, two's complement // integer comprised of the least-significant one byte of the specified // 'value'. The behavior is undefined unless 'buffer' has sufficient // capacity. Note that this function applies equally to unsigned // 32-bit values, and signed and unsigned 16- and 8-bit values. // *** put scalar floating-point values *** static void putFloat64(char *buffer, double value); // Load into the specified 'buffer' the eight-byte IEEE // double-precision floating-point number (in network byte order) // comprised of the most-significant eight bytes of the specified // 'value' (in host byte order). The behavior is undefined unless // 'buffer' has sufficient capacity. Note that for non-conforming // platforms, this operation may be lossy. static void putFloat32(char *buffer, float value); // Load into the specified 'buffer' the four-byte IEEE single-precision // floating-point number (in network byte order) comprised of the // most-significant four bytes of the specified 'value' (in host byte // order). The behavior is undefined unless 'buffer' has sufficient // capacity. Note that for non-conforming platforms, this operation // may be lossy. // *** get scalar integral values *** static void getInt64(bsls::Types::Int64 *variable, const char *buffer); // Load into the specified 'variable' the eight-byte, two's complement // integer (in host byte order) comprised of the initial eight bytes of // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'buffer' has sufficient contents. Note that the // value will be sign-extended. static void getUint64(bsls::Types::Uint64 *variable, const char *buffer); // Load into the specified 'variable' the eight-byte, two's complement // unsigned integer (in host byte order) comprised of the initial eight // bytes of the specified 'buffer' (in network byte order). The // behavior is undefined unless 'buffer' has sufficient contents. Note // that the value will be zero-extended. static void getInt56(bsls::Types::Int64 *variable, const char *buffer); // Load into the specified 'variable' the seven-byte, two's complement // integer (in host byte order) comprised of the initial seven bytes of // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'buffer' has sufficient contents. Note that the // value will be sign-extended. static void getUint56(bsls::Types::Uint64 *variable, const char *buffer); // Load into the specified 'variable' the seven-byte, two's complement // unsigned integer (in host byte order) comprised of the initial seven // bytes of the specified 'buffer' (in network byte order). The // behavior is undefined unless 'buffer' has sufficient contents. Note // that the value will be zero-extended. static void getInt48(bsls::Types::Int64 *variable, const char *buffer); // Load into the specified 'variable' the six-byte, two's complement // integer (in host byte order) comprised of the initial six bytes of // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'buffer' has sufficient contents. Note that the // value will be sign-extended. static void getUint48(bsls::Types::Uint64 *variable, const char *buffer); // Load into the specified 'variable' the six-byte, two's complement // unsigned integer (in host byte order) comprised of the initial six // bytes of the specified 'buffer' (in network byte order). The // behavior is undefined unless 'buffer' has sufficient contents. Note // that the value will be zero-extended. static void getInt40(bsls::Types::Int64 *variable, const char *buffer); // Load into the specified 'variable' the five-byte, two's complement // integer (in host byte order) comprised of the initial five bytes of // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'buffer' has sufficient contents. Note that the // value will be sign-extended. static void getUint40(bsls::Types::Uint64 *variable, const char *buffer); // Load into the specified 'variable' the five-byte, two's complement // unsigned integer (in host byte order) comprised of the initial five // bytes of the specified 'buffer' (in network byte order). The // behavior is undefined unless 'buffer' has sufficient contents. Note // that the value will be zero-extended. static void getInt32(int *variable, const char *buffer); // Load into the specified 'variable' the four-byte, two's complement // integer (in host byte order) comprised of the initial four bytes of // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'buffer' has sufficient contents. Note that the // value will be sign-extended. static void getUint32(unsigned int *variable, const char *buffer); // Load into the specified 'variable' the four-byte, two's complement // unsigned integer (in host byte order) comprised of the initial four // bytes of the specified 'buffer' (in network byte order). The // behavior is undefined unless 'buffer' has sufficient contents. Note // that the value will be zero-extended. static void getInt24(int *variable, const char *buffer); // Load into the specified 'variable' the three-byte, two's complement // integer (in host byte order) comprised of the initial three bytes of // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'buffer' has sufficient contents. Note that the // value will be sign-extended. static void getUint24(unsigned int *variable, const char *buffer); // Load into the specified 'variable' the three-byte, two's complement // unsigned integer (in host byte order) comprised of the initial three // bytes of the specified 'buffer' (in network byte order). The // behavior is undefined unless 'buffer' has sufficient contents. Note // that the value will be zero-extended. static void getInt16(short *variable, const char *buffer); // Load into the specified 'variable' the two-byte, two's complement // integer (in host byte order) comprised of the initial two bytes of // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'buffer' has sufficient contents. Note that the // value will be sign-extended. static void getUint16(unsigned short *variable, const char *buffer); // Load into the specified 'variable' the two-byte, two's complement // unsigned integer (in host byte order) comprised of the initial two // bytes of the specified 'buffer' (in network byte order). The // behavior is undefined unless 'buffer' has sufficient contents. Note // that the value will be zero-extended. static void getInt8(char *variable, const char *buffer); static void getInt8(signed char *variable, const char *buffer); static void getInt8(unsigned char *variable, const char *buffer); // Load into the specified 'variable' the one-byte, two's complement // integer comprised of the initial one byte of the specified 'buffer'. // The behavior is undefined unless 'buffer' has sufficient contents. // *** get scalar floating-point values *** static void getFloat64(double *variable, const char *buffer); // Load into the specified 'variable' the eight-byte IEEE // double-precision floating-point number (in host byte order) // comprised of the initial eight bytes of the specified 'buffer' (in // network byte order). The behavior is undefined unless 'buffer' has // sufficient contents. static void getFloat32(float *variable, const char *buffer); // Load into the specified 'variable' the four-byte IEEE // single-precision floating-point number (in host byte order) // comprised of the initial four bytes of the specified 'buffer' (in // network byte order). The behavior is undefined unless 'buffer' has // sufficient contents. // *** put arrays of integral values *** static void putArrayInt64(char *buffer, const bsls::Types::Int64 *values, int numValues); static void putArrayInt64(char *buffer, const bsls::Types::Uint64 *values, int numValues); // Load into the specified 'buffer' the consecutive eight-byte, two's // complement integers (in network byte order) comprised of the // least-significant eight bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity, // 'values' has sufficient contents, and '0 <= numValues'. static void putArrayInt56(char *buffer, const bsls::Types::Int64 *values, int numValues); static void putArrayInt56(char *buffer, const bsls::Types::Uint64 *values, int numValues); // Load into the specified 'buffer' the consecutive seven-byte, two's // complement integers (in network byte order) comprised of the // least-significant seven bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity, // 'values' has sufficient contents, and '0 <= numValues'. static void putArrayInt48(char *buffer, const bsls::Types::Int64 *values, int numValues); static void putArrayInt48(char *buffer, const bsls::Types::Uint64 *values, int numValues); // Load into the specified 'buffer' the consecutive six-byte, two's // complement integers (in network byte order) comprised of the // least-significant six bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity, // 'values' has sufficient contents, and '0 <= numValues'. static void putArrayInt40(char *buffer, const bsls::Types::Int64 *values, int numValues); static void putArrayInt40(char *buffer, const bsls::Types::Uint64 *values, int numValues); // Load into the specified 'buffer' the consecutive five-byte, two's // complement integers (in network byte order) comprised of the // least-significant five bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity, // 'values' has sufficient contents, and '0 <= numValues'. static void putArrayInt32(char *buffer, const int *values, int numValues); static void putArrayInt32(char *buffer, const unsigned int *values, int numValues); // Load into the specified 'buffer' the consecutive four-byte, two's // complement integers (in network byte order) comprised of the // least-significant four bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity, // 'values' has sufficient contents, and '0 <= numValues'. static void putArrayInt24(char *buffer, const int *values, int numValues); static void putArrayInt24(char *buffer, const unsigned int *values, int numValues); // Load into the specified 'buffer' the consecutive three-byte, two's // complement integers (in network byte order) comprised of the // least-significant three bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity, // 'values' has sufficient contents, and '0 <= numValues'. static void putArrayInt16(char *buffer, const short *values, int numValues); static void putArrayInt16(char *buffer, const unsigned short *values, int numValues); // Load into the specified 'buffer' the consecutive two-byte, two's // complement integers (in network byte order) comprised of the // least-significant two bytes of each of the specified 'numValues' // leading entries in the specified 'values' (in host byte order). The // behavior is undefined unless 'buffer' has sufficient capacity, // 'values' has sufficient contents, and '0 <= numValues'. static void putArrayInt8(char *buffer, const char *values, int numValues); static void putArrayInt8(char *buffer, const signed char *values, int numValues); static void putArrayInt8(char *buffer, const unsigned char *values, int numValues); // Load into the specified 'buffer' the consecutive one-byte, two's // complement integers comprised of the one byte of each of the // specified 'numValues' leading entries in the specified 'values'. // The behavior is undefined unless 'buffer' has sufficient capacity, // 'values' has sufficient contents, and '0 <= numValues'. // *** put arrays of floating-point values *** static void putArrayFloat64(char *buffer, const double *values, int numValues); // Load into the specified 'buffer' the consecutive eight-byte IEEE // double-precision floating-point numbers (in network byte order) // comprised of the most-significant eight bytes of each of the // specified 'numValues' leading entries in the specified 'values' (in // host byte order). The behavior is undefined unless 'buffer' has // sufficient capacity, 'values' has sufficient contents, and // '0 <= numValues'. Note that for non-conforming platforms, this // operation may be lossy. static void putArrayFloat32(char *buffer, const float *values, int numValues); // Load into the specified 'buffer' the consecutive four-byte IEEE // single-precision floating-point numbers (in network byte order) // comprised of the most-significant four bytes of each of the // specified 'numValues' leading entries in the specified 'values' (in // host byte order). The behavior is undefined unless 'buffer' has // sufficient capacity, 'values' has sufficient contents, and // '0 <= numValues'. Note that for non-conforming platforms, this // operation may be lossy. // *** get arrays of integral values *** static void getArrayInt64(bsls::Types::Int64 *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive eight-byte, // two's complement integers (in host byte order) comprised of each of // the specified 'numVariables' leading eight-byte sequences in the // specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be sign-extended. static void getArrayUint64(bsls::Types::Uint64 *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive eight-byte, // two's complement unsigned integers (in host byte order) comprised of // each of the specified 'numVariables' leading eight-byte sequences in // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be zero-extended. static void getArrayInt56(bsls::Types::Int64 *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive seven-byte, // two's complement integers (in host byte order) comprised of each of // the specified 'numVariables' leading seven-byte sequences in the // specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be sign-extended. static void getArrayUint56(bsls::Types::Uint64 *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive seven-byte, // two's complement unsigned integers (in host byte order) comprised of // each of the specified 'numVariables' leading seven-byte sequences in // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be zero-extended. static void getArrayInt48(bsls::Types::Int64 *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive six-byte, two's // complement integers (in host byte order) comprised of each of the // specified 'numVariables' leading six-byte sequences in the specified // 'buffer' (in network byte order). The behavior is undefined unless // 'variables' has sufficient capacity, 'buffer' has sufficient // contents, and '0 <= numVariables'. Note that each of the values // will be sign-extended. static void getArrayUint48(bsls::Types::Uint64 *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive six-byte, two's // complement unsigned integers (in host byte order) comprised of each // of the specified 'numVariables' leading six-byte sequences in the // specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be zero-extended. static void getArrayInt40(bsls::Types::Int64 *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive five-byte, two's // complement integers (in host byte order) comprised of each of the // specified 'numVariables' leading five-byte sequences in the // specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be sign-extended. static void getArrayUint40(bsls::Types::Uint64 *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive five-byte, two's // complement unsigned integers (in host byte order) comprised of each // of the specified 'numVariables' leading five-byte sequences in the // specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be zero-extended. static void getArrayInt32(int *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive four-byte, two's // complement integers (in host byte order) comprised of each of the // specified 'numVariables' leading four-byte sequences in the // specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be sign-extended. static void getArrayUint32(unsigned int *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive four-byte, two's // complement unsigned integers (in host byte order) comprised of each // of the specified 'numVariables' leading four-byte sequences in the // specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be zero-extended. static void getArrayInt24(int *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive three-byte, // two's complement integers (in host byte order) comprised of each of // the specified 'numVariables' leading three-byte sequences in the // specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be sign-extended. static void getArrayUint24(unsigned int *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive three-byte, // two's complement unsigned integers (in host byte order) comprised of // each of the specified 'numVariables' leading three-byte sequences in // the specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be zero-extended. static void getArrayInt16(short *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive two-byte, two's // complement integers (in host byte order) comprised of each of the // specified 'numVariables' leading two-byte sequences in the specified // 'buffer' (in network byte order). The behavior is undefined unless // 'variables' has sufficient capacity, 'buffer' has sufficient // contents, and '0 <= numVariables'. Note that each of the values // will be sign-extended. static void getArrayUint16(unsigned short *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive two-byte, two's // complement unsigned integers (in host byte order) comprised of each // of the specified 'numVariables' leading two-byte sequences in the // specified 'buffer' (in network byte order). The behavior is // undefined unless 'variables' has sufficient capacity, 'buffer' has // sufficient contents, and '0 <= numVariables'. Note that each of the // values will be zero-extended. static void getArrayInt8(char *variables, const char *buffer, int numVariables); static void getArrayInt8(signed char *variables, const char *buffer, int numVariables); static void getArrayInt8(unsigned char *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive one-byte, two's // complement integers comprised of each of the specified // 'numVariables' leading one-byte sequences in the specified 'buffer'. // The behavior is undefined unless 'variables' has sufficient // capacity, 'buffer' has sufficient contents, and '0 <= numVariables'. // *** get arrays of floating-point values *** static void getArrayFloat64(double *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive eight-byte IEEE // double-precision floating-point numbers (in host byte order) // comprised of each of the specified 'numVariables' leading eight-byte // sequences in the specified 'buffer' (in network byte order). The // behavior is undefined unless 'variables' has sufficient capacity, // 'buffer' has sufficient contents, and '0 <= numVariables'. static void getArrayFloat32(float *variables, const char *buffer, int numVariables); // Load into the specified 'variables' the consecutive four-byte IEEE // single-precision floating-point numbers (in host byte order) // comprised of each of the specified 'numVariables' leading four-byte // sequences in the specified 'buffer' (in network byte order). The // behavior is undefined unless 'variables' has sufficient capacity, // 'buffer' has sufficient contents, and '0 <= numVariables'. }; // ============================================================================ // INLINE DEFINITIONS // ============================================================================ // ---------------------- // struct MarshallingUtil // ---------------------- // CLASS METHODS // *** put scalar integral values *** inline void MarshallingUtil::putInt64(char *buffer, bsls::Types::Int64 value) { BSLS_ASSERT_SAFE(buffer); const char *bytes = reinterpret_cast<char *>(&value); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN buffer[0] = bytes[7]; buffer[1] = bytes[6]; buffer[2] = bytes[5]; buffer[3] = bytes[4]; buffer[4] = bytes[3]; buffer[5] = bytes[2]; buffer[6] = bytes[1]; buffer[7] = bytes[0]; #else bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT64, k_SIZEOF_INT64); #endif } inline void MarshallingUtil::putInt56(char *buffer, bsls::Types::Int64 value) { BSLS_ASSERT_SAFE(buffer); const char *bytes = reinterpret_cast<char *>(&value); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN buffer[0] = bytes[6]; buffer[1] = bytes[5]; buffer[2] = bytes[4]; buffer[3] = bytes[3]; buffer[4] = bytes[2]; buffer[5] = bytes[1]; buffer[6] = bytes[0]; #else bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT56, k_SIZEOF_INT56); #endif } inline void MarshallingUtil::putInt48(char *buffer, bsls::Types::Int64 value) { BSLS_ASSERT_SAFE(buffer); const char *bytes = reinterpret_cast<char *>(&value); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN buffer[0] = bytes[5]; buffer[1] = bytes[4]; buffer[2] = bytes[3]; buffer[3] = bytes[2]; buffer[4] = bytes[1]; buffer[5] = bytes[0]; #else bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT48, k_SIZEOF_INT48); #endif } inline void MarshallingUtil::putInt40(char *buffer, bsls::Types::Int64 value) { BSLS_ASSERT_SAFE(buffer); const char *bytes = reinterpret_cast<char *>(&value); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN buffer[0] = bytes[4]; buffer[1] = bytes[3]; buffer[2] = bytes[2]; buffer[3] = bytes[1]; buffer[4] = bytes[0]; #else bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT40, k_SIZEOF_INT40); #endif } inline void MarshallingUtil::putInt32(char *buffer, int value) { BSLS_ASSERT_SAFE(buffer); const char *bytes = reinterpret_cast<char *>(&value); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN buffer[0] = bytes[3]; buffer[1] = bytes[2]; buffer[2] = bytes[1]; buffer[3] = bytes[0]; #else bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT32, k_SIZEOF_INT32); #endif } inline void MarshallingUtil::putInt24(char *buffer, int value) { BSLS_ASSERT_SAFE(buffer); const char *bytes = reinterpret_cast<char *>(&value); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN buffer[0] = bytes[2]; buffer[1] = bytes[1]; buffer[2] = bytes[0]; #else bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT24, k_SIZEOF_INT24); #endif } inline void MarshallingUtil::putInt16(char *buffer, int value) { BSLS_ASSERT_SAFE(buffer); const char *bytes = reinterpret_cast<char *>(&value); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN buffer[0] = bytes[1]; buffer[1] = bytes[0]; #else bsl::memcpy(buffer, bytes + sizeof value - k_SIZEOF_INT16, k_SIZEOF_INT16); #endif } inline void MarshallingUtil::putInt8(char *buffer, int value) { BSLS_ASSERT_SAFE(buffer); *buffer = static_cast<char>(value); } // *** put scalar floating-point values *** inline void MarshallingUtil::putFloat64(char *buffer, double value) { BSLS_ASSERT_SAFE(buffer); const char *bytes = reinterpret_cast<char *>(&value); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN buffer[0] = bytes[sizeof value - 1]; buffer[1] = bytes[sizeof value - 2]; buffer[2] = bytes[sizeof value - 3]; buffer[3] = bytes[sizeof value - 4]; buffer[4] = bytes[sizeof value - 5]; buffer[5] = bytes[sizeof value - 6]; buffer[6] = bytes[sizeof value - 7]; buffer[7] = bytes[sizeof value - 8]; #else bsl::memcpy(buffer, bytes, k_SIZEOF_FLOAT64); #endif } inline void MarshallingUtil::putFloat32(char *buffer, float value) { BSLS_ASSERT_SAFE(buffer); const char *bytes = reinterpret_cast<char *>(&value); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN buffer[0] = bytes[sizeof value - 1]; buffer[1] = bytes[sizeof value - 2]; buffer[2] = bytes[sizeof value - 3]; buffer[3] = bytes[sizeof value - 4]; #else bsl::memcpy(buffer, bytes, k_SIZEOF_FLOAT32); #endif } // *** get scalar integral values *** inline void MarshallingUtil::getInt64(bsls::Types::Int64 *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); if (sizeof *variable > k_SIZEOF_INT64) { *variable = 0x80 & buffer[0] ? -1 : 0; // sign extend } char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[7] = buffer[0]; bytes[6] = buffer[1]; bytes[5] = buffer[2]; bytes[4] = buffer[3]; bytes[3] = buffer[4]; bytes[2] = buffer[5]; bytes[1] = buffer[6]; bytes[0] = buffer[7]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT64, buffer, k_SIZEOF_INT64); #endif } inline void MarshallingUtil::getUint64(bsls::Types::Uint64 *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); if (sizeof *variable > k_SIZEOF_INT64) { *variable = 0; // zero-extend } char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[7] = buffer[0]; bytes[6] = buffer[1]; bytes[5] = buffer[2]; bytes[4] = buffer[3]; bytes[3] = buffer[4]; bytes[2] = buffer[5]; bytes[1] = buffer[6]; bytes[0] = buffer[7]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT64, buffer, k_SIZEOF_INT64); #endif } inline void MarshallingUtil::getInt56(bsls::Types::Int64 *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); *variable = 0x80 & buffer[0] ? -1 : 0; // sign extend char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[6] = buffer[0]; bytes[5] = buffer[1]; bytes[4] = buffer[2]; bytes[3] = buffer[3]; bytes[2] = buffer[4]; bytes[1] = buffer[5]; bytes[0] = buffer[6]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT56, buffer, k_SIZEOF_INT56); #endif } inline void MarshallingUtil::getUint56(bsls::Types::Uint64 *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); *variable = 0; // zero-extend char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[6] = buffer[0]; bytes[5] = buffer[1]; bytes[4] = buffer[2]; bytes[3] = buffer[3]; bytes[2] = buffer[4]; bytes[1] = buffer[5]; bytes[0] = buffer[6]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT56, buffer, k_SIZEOF_INT56); #endif } inline void MarshallingUtil::getInt48(bsls::Types::Int64 *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); *variable = 0x80 & buffer[0] ? -1 : 0; // sign extend char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[5] = buffer[0]; bytes[4] = buffer[1]; bytes[3] = buffer[2]; bytes[2] = buffer[3]; bytes[1] = buffer[4]; bytes[0] = buffer[5]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT48, buffer, k_SIZEOF_INT48); #endif } inline void MarshallingUtil::getUint48(bsls::Types::Uint64 *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); *variable = 0; // zero-extend char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[5] = buffer[0]; bytes[4] = buffer[1]; bytes[3] = buffer[2]; bytes[2] = buffer[3]; bytes[1] = buffer[4]; bytes[0] = buffer[5]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT48, buffer, k_SIZEOF_INT48); #endif } inline void MarshallingUtil::getInt40(bsls::Types::Int64 *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); *variable = 0x80 & buffer[0] ? -1 : 0; // sign extend char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[4] = buffer[0]; bytes[3] = buffer[1]; bytes[2] = buffer[2]; bytes[1] = buffer[3]; bytes[0] = buffer[4]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT40, buffer, k_SIZEOF_INT40); #endif } inline void MarshallingUtil::getUint40(bsls::Types::Uint64 *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); *variable = 0; // zero-extend char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[4] = buffer[0]; bytes[3] = buffer[1]; bytes[2] = buffer[2]; bytes[1] = buffer[3]; bytes[0] = buffer[4]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT40, buffer, k_SIZEOF_INT40); #endif } inline void MarshallingUtil::getInt32(int *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); if (sizeof *variable > k_SIZEOF_INT32) { *variable = 0x80 & buffer[0] ? -1 : 0; // sign extend } char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[3] = buffer[0]; bytes[2] = buffer[1]; bytes[1] = buffer[2]; bytes[0] = buffer[3]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT32, buffer, k_SIZEOF_INT32); #endif } inline void MarshallingUtil::getUint32(unsigned int *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); if (sizeof *variable > k_SIZEOF_INT32) { *variable = 0; // zero-extend } char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[3] = buffer[0]; bytes[2] = buffer[1]; bytes[1] = buffer[2]; bytes[0] = buffer[3]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT32, buffer, k_SIZEOF_INT32); #endif } inline void MarshallingUtil::getInt24(int *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); *variable = 0x80 & buffer[0] ? -1 : 0; // sign extend char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[2] = buffer[0]; bytes[1] = buffer[1]; bytes[0] = buffer[2]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT24, buffer, k_SIZEOF_INT24); #endif } inline void MarshallingUtil::getUint24(unsigned int *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); *variable = 0; // zero-extend char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[2] = buffer[0]; bytes[1] = buffer[1]; bytes[0] = buffer[2]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT24, buffer, k_SIZEOF_INT24); #endif } inline void MarshallingUtil::getInt16(short *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); if (sizeof *variable > k_SIZEOF_INT16) { *variable = static_cast<short>(0x80 & buffer[0] ? -1 : 0); // sign extend } char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[1] = buffer[0]; bytes[0] = buffer[1]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT16, buffer, k_SIZEOF_INT16); #endif } inline void MarshallingUtil::getUint16(unsigned short *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); if (sizeof *variable > k_SIZEOF_INT16) { *variable = 0; // zero-extend } char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[1] = buffer[0]; bytes[0] = buffer[1]; #else bsl::memcpy(bytes + sizeof *variable - k_SIZEOF_INT16, buffer, k_SIZEOF_INT16); #endif } inline void MarshallingUtil::getInt8(char *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); *variable = *buffer; } inline void MarshallingUtil::getInt8(signed char *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); getInt8(reinterpret_cast<char *>(variable), buffer); } inline void MarshallingUtil::getInt8(unsigned char *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); getInt8(reinterpret_cast<char *>(variable), buffer); } // *** get scalar floating-point values *** inline void MarshallingUtil::getFloat64(double *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); if (sizeof *variable > k_SIZEOF_FLOAT64) { *variable = 0; // zero-fill significand } char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[sizeof *variable - 1] = buffer[0]; bytes[sizeof *variable - 2] = buffer[1]; bytes[sizeof *variable - 3] = buffer[2]; bytes[sizeof *variable - 4] = buffer[3]; bytes[sizeof *variable - 5] = buffer[4]; bytes[sizeof *variable - 6] = buffer[5]; bytes[sizeof *variable - 7] = buffer[6]; bytes[sizeof *variable - 8] = buffer[7]; #else bsl::memcpy(bytes, buffer, k_SIZEOF_FLOAT64); #endif } inline void MarshallingUtil::getFloat32(float *variable, const char *buffer) { BSLS_ASSERT_SAFE(variable); BSLS_ASSERT_SAFE(buffer); if (sizeof *variable > k_SIZEOF_FLOAT32) { *variable = 0; // zero-fill significand } char *bytes = reinterpret_cast<char *>(variable); #if BSLS_PLATFORM_IS_LITTLE_ENDIAN bytes[sizeof *variable - 1] = buffer[0]; bytes[sizeof *variable - 2] = buffer[1]; bytes[sizeof *variable - 3] = buffer[2]; bytes[sizeof *variable - 4] = buffer[3]; #else bsl::memcpy(bytes, buffer, k_SIZEOF_FLOAT32); #endif } // *** put arrays of integral values *** inline void MarshallingUtil::putArrayInt8(char *buffer, const char *values, int numValues) { BSLS_ASSERT_SAFE(buffer); BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); bsl::memcpy(buffer, values, numValues); } inline void MarshallingUtil::putArrayInt8(char *buffer, const signed char *values, int numValues) { BSLS_ASSERT_SAFE(buffer); BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); putArrayInt8(buffer, reinterpret_cast<const char *>(values), numValues); } inline void MarshallingUtil::putArrayInt8(char *buffer, const unsigned char *values, int numValues) { BSLS_ASSERT_SAFE(buffer); BSLS_ASSERT_SAFE(values); BSLS_ASSERT_SAFE(0 <= numValues); putArrayInt8(buffer, reinterpret_cast<const char *>(values), numValues); } // *** get arrays of integral values *** inline void MarshallingUtil::getArrayInt8(char *variables, const char *buffer, int numVariables) { BSLS_ASSERT_SAFE(variables); BSLS_ASSERT_SAFE(buffer); BSLS_ASSERT_SAFE(0 <= numVariables); bsl::memcpy(variables, buffer, numVariables); } inline void MarshallingUtil::getArrayInt8(signed char *variables, const char *buffer, int numVariables) { BSLS_ASSERT_SAFE(variables); BSLS_ASSERT_SAFE(buffer); BSLS_ASSERT_SAFE(0 <= numVariables); getArrayInt8(reinterpret_cast<char *>(variables), buffer, numVariables); } inline void MarshallingUtil::getArrayInt8(unsigned char *variables, const char *buffer, int numVariables) { BSLS_ASSERT_SAFE(variables); BSLS_ASSERT_SAFE(buffer); BSLS_ASSERT_SAFE(0 <= numVariables); getArrayInt8(reinterpret_cast<char *>(variables), buffer, numVariables); } } // close package namespace } // close enterprise namespace #endif // ---------------------------------------------------------------------------- // Copyright 2014 Bloomberg Finance L.P. // // Licensed under the Apache License, Version 2.0 (the "License"); // you may not use this file except in compliance with the License. // You may obtain a copy of the License at // // http://www.apache.org/licenses/LICENSE-2.0 // // Unless required by applicable law or agreed to in writing, software // distributed under the License is distributed on an "AS IS" BASIS, // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. // See the License for the specific language governing permissions and // limitations under the License. // ----------------------------- END-OF-FILE ----------------------------------