Overview

The ROSE library stores EXPRESS "binary" values as strings encoded in the format used by Part 21 files. EXPRESS allows binary values of arbitrary bit lengths, but for exact byte lengths (multiples of eight bits), the encoding is just a hexadecimal number starting with a zero "0" rather than the C convention of "0x".

    012             ==> 8 bit quantity, value 0x12
    0FFFF           ==> 16 bit quantity, value 0xFFFF
    03BA71234       ==> 32 bit quantity, value 0x3BA71234

The C++ get and put functions generated by the EXPRESS compiler use char*, but the RoseBinaryObject helper class is available to handle bit and byte level access to the data.

The example below shows an object with a binary attribute called "binary_att" and puts, gets, and manupulates some binary data.

    SomeEntity * obj;
    
    // Set attribute to hex 0xFFFF
    obj-> binary_att ("0FFFF");  
    
    // print the value back out again
    printf ("Binary Value %s\n", obj-> binary_att());
    
    // use helper class for bit and byte level access
    RoseBinaryObject helper (obj-> binary_att());
    
    helper.putBit (8, 0)        // changes to 0xFFEF
    helper.putByte (1, 0xA7)    // changes to 0xA7EF
    helper.putWord (1, 0x1234)  // resizes to 0x1234A7EF
    
    // Update the attribute to with the modified value
    obj-> binary_att (helper.getP21String());
    
    // You can also use late-bound data dictionary calls 
    // to get and put the data.
    helper = obj-> getBinary ("binary_att");
    obj-> putBinary (helper.getP21String(), "binary_att");

Note that the functions below use a "little endian" representation of the binary data, which means that changing bit 0 of the binary changes bit #0 of byte 0 and bit 0 of word 0. Changing bit 8 of the binary changes bit 0 of byte 1 and bit 8 of word 0, and so on.

RoseBinaryObject Constructor

RoseBinaryObject(
	unsigned bitcnt=0
	);

RoseBinaryObject(
	unsigned char * buf,
	unsigned bytecnt
	);

RoseBinaryObject(
	const char * p21encoding
	);

RoseBinaryObject(
	const RoseBinaryObject& other
	);

There are four versions of the constructor. The first takes a length in bits and initializes the object with a binary value of that length filled with zeros.

The second takes a pointer to a location in memory and a length initializes the object by copying the number of bytes specified.

The third takes a pointer to string encoded using the Part 21 hexadecimal notation, parses the string and initializes the object with the resulting value.

The last is a copy constructor. Reference counts are used to avoid duplicating the underlying binary data, so these objects can be passed into and returned from functions without performance impact.

Example

The example below shows the ways of creating a RoseBinaryObject on the stack. You can also create them on the heap and pass around a pointer, but the copy constructor is quite efficient and it is usually easier to just pass the entire object.

    RoseBinaryObject a (5);           // 5 bits long, all zeros
    
    unsigned char * buf;
    RoseBinaryObject b (buf, 20);    // 20 bytes, copied starting at buf
    
    RoseBinaryObject c ("0ABCD");    // 2 bytes, value 0xABCD
    
    RoseBinaryObject d (c);          // copy of c, 2 bytes, value 0xABCD

Operator =

RoseBinaryObject& operator=(
	const RoseBinaryObject& other
	);

RoseBinaryObject& operator= (
	const char * p21encoding
	);

Two versions of the assignment operator are provided. The first copies the value of another RoseBinaryObject. The second is a shorthand form of the putP21String() function. It parses a hexadecimal string as described by the Part 21 encoding and assigns the result to the binary object. Refer to RoseBinaryObject::putP21String() for more details.

buffer()

unsigned char * buffer()

The buffer() function returns a pointer to the memory buffer holding the binary data. The size of the buffer will be the exact number of bytes returned by sizeInBytes(). Note that, depending on the contents of the object, sizeInBits() might underestimate the size of the buffer and sizeInWords() might overestimate it.

The pointer returned by buffer() may change if the binary is resized or assigned to using any of the assignment operators or put functions. Calling buffer() on an empty binary will return a null pointer.

getBit() / getByte() / getWord()

RoseBoolean getBit(
	size_t bitIndex
	);

unsigned char getByte(
	size_t byteIndex
	);

unsigned long getWord(
	size_t wordIndex
	);

The get functions get a value of a particular size at the given offset within the binary data. The getBit() function returns an individual bit given a bit offset, getByte() returns an 8bit byte at a given a byte offset, and getWord() returns a 32bit word at a given a word offset.

When getting bytes or words, the value will be padded with zeros if the underlying data has fewer bits than requested. So creating binary value one bit long with that bit set and then calling getByte(0) will return 0x01. Calling getWord(0) will return 0x00000001. Calling with an index beyond the end of all data will return zero.

getP21String()

const char * getP21String();

The getP21String() functions formats the binary data as a hexadecimal string as described by the Part 21 encoding. The function returns a pointer to a static buffer so the string should be copied before calling the function a second time.

Use this function to assign a binary value to an EXPRESS object as shown in the examples above in Overview.

putBit() / putByte() / putWord()

void putBit(
	size_t bitIndex,
	RoseBoolean b
	);

void putByte(
	size_t byteIndex,
	unsigned char b
	);

void putWord(
	size_t wordIndex,
	unsigned long b
	);

The put functions assign a value of a particular size at the given offset within the binary data. The putBit() function assigns an individual bit given a bit offset, putByte() assigns an 8bit byte at a given a byte offset, and putWord() assigns a 32bit word at a given a word offset.

If a value would be written beyond the end of the binary data, the size of the object will be increased and filled with zeros as needed to accommodate the the new value. So creating binary value one bit long and then calling putByte(0, 0xFF) will resize the data to 8 bits long. Calling putWord(0, 0x12345678) will resize the data to 32 bits.

putP21String()

void putP21String(
	const char * p21str
	);

The putP21String() functions parses a hexadecimal string as described by the Part 21 encoding and assigns the result to the binary object. Use this function to initialize a RoseBinaryObject with a binary value from an EXPRESS object as shown in the examples above in Overview.

sizeInBits() / sizeInBytes() / sizeInWords()

size_t sizeInBits();
size_t sizeInBytes();
size_t sizeInWords();

void sizeInBits(
	size_t sz
	);

void sizeInBytes(
	size_t sz
	);

void sizeInWords(
	size_t sz
	);

The size functions get or set the size of the binary value in terms of various value types. The sizeInBits() functions get and set the exact number of bits in the value. The sizeInBytes() functions get and set the number length of the value in terms of 8bit bytes, while the sizeInWords() functions use 32bit words.

When getting the size with sizeInBytes() or sizeInWords() will return the closes value greater than or equal to the actual size. So a 12bit value is two bytes in size and one word in size.