Feature/comments and review (#102)

* Added comments. Replaced -1 with BACNET_STATUS_ERROR macro.

* Added some DogyGen comments

* Added missing return value check for booleans.

* Check used bits against unused bits in bitstrings.

* Added missing return value check for bitstrings.

* Added sanity checks and comments.

* Fixed implicit type conv warning.

* Chose to keep simpler C function methods.

Co-authored-by: Steve Karg <steve@kargs.net>
Co-authored-by: Steve Karg <skarg@users.sourceforge.net>
This commit is contained in:
Roy Schneider
2020-07-14 18:41:51 +02:00
committed by GitHub
parent de7f7e9782
commit 2af16ab14d
5 changed files with 838 additions and 234 deletions
+264 -55
View File
@@ -90,9 +90,14 @@
B'111' interpreted as Type = Closing Tag
*/
/* from clause 20.1.2.4 max-segments-accepted */
/* and clause 20.1.2.5 max-APDU-length-accepted */
/* returns the encoded octet */
/**
* Encode the max APDU value and return the encoded octed.
*
* @param max_segs from clause 20.1.2.4 max-segments-accepted
* @param max_apdu from clause 20.1.2.5 max-APDU-length-accepted
*
* @return The encoded octet
*/
uint8_t encode_max_segs_max_apdu(int max_segs, int max_apdu)
{
uint8_t octet = 0;
@@ -136,9 +141,14 @@ uint8_t encode_max_segs_max_apdu(int max_segs, int max_apdu)
return octet;
}
/* from clause 20.1.2.4 max-segments-accepted */
/* and clause 20.1.2.5 max-APDU-length-accepted */
/* returns the encoded octet */
/**
* Decode the given octed into a maximum segments value.
*
* @param octed From clause 20.1.2.4 max-segments-accepted
* and clause 20.1.2.5 max-APDU-length-accepted
*
* @return Returns the maximum segments value.
*/
int decode_max_segs(uint8_t octet)
{
int max_segs = 0;
@@ -175,6 +185,14 @@ int decode_max_segs(uint8_t octet)
return max_segs;
}
/**
* Decode the given octed into a maximum APDU value.
*
* @param octed From clause 20.1.2.4 max-segments-accepted
* and clause 20.1.2.5 max-APDU-length-accepted
*
* @return Returns the maximum APDU value.
*/
int decode_max_apdu(uint8_t octet)
{
int max_apdu = 0;
@@ -205,8 +223,18 @@ int decode_max_apdu(uint8_t octet)
return max_apdu;
}
/* from clause 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
/**
* Encode a BACnet tag and returns the number of bytes consumed.
* (From clause 20.2.1 General Rules for Encoding BACnet Tags)
*
* @param apdu Pointer to the encode buffer.
* @param tag_number Number of the tag to encode,
* see BACNET_APPLICATION_TAG_X macros.
* @param context_specific Indicates to encode in the given context.
* @param len_value_type Indicates the length of the tag's content.
*
* @return Returns the number of apdu bytes consumed.
*/
int encode_tag(uint8_t *apdu,
uint8_t tag_number,
bool context_specific,
@@ -249,8 +277,17 @@ int encode_tag(uint8_t *apdu,
return len;
}
/* from clause 20.2.1.3.2 Constructed Data */
/* returns the number of apdu bytes consumed */
/**
* Encode a BACnet opening tag and returns the number
* of bytes consumed.
* (From clause 20.2.1.3.2 Constructed Data.)
*
* @param apdu Pointer to the encode buffer.
* @param tag_number Number of the tag to encode,
* see BACNET_APPLICATION_TAG_X macros.
*
* @return Returns the number of apdu bytes consumed.
*/
int encode_opening_tag(uint8_t *apdu, uint8_t tag_number)
{
int len = 1;
@@ -271,8 +308,17 @@ int encode_opening_tag(uint8_t *apdu, uint8_t tag_number)
return len;
}
/* from clause 20.2.1.3.2 Constructed Data */
/* returns the number of apdu bytes consumed */
/**
* Encode a BACnet closing tag and returns the number
* of bytes consumed.
* (From clause 20.2.1.3.2 Constructed Data.)
*
* @param apdu Pointer to the encode buffer.
* @param tag_number Number of the tag to encode,
* see BACNET_APPLICATION_TAG_X macros.
*
* @return Returns the number of apdu bytes consumed.
*/
int encode_closing_tag(uint8_t *apdu, uint8_t tag_number)
{
int len = 1;
@@ -345,20 +391,45 @@ int bacnet_tag_number_decode(
return len;
}
/**
* @brief Returns if at the given pointer a
* opening tag has been found.
*
* @param apdu Pointer to the tag number.
*
* @return true/false
*/
bool decode_is_opening_tag(uint8_t *apdu)
{
return (bool)((apdu[0] & 0x07) == 6);
}
/* from clause 20.2.1.3.2 Constructed Data */
/* returns the number of apdu bytes consumed */
/**
* @brief Returns if at the given pointer a
* closing tag has been found.
*
* @param apdu Pointer to the tag number.
*
* @return true/false
*/
bool decode_is_closing_tag(uint8_t *apdu)
{
return (bool)((apdu[0] & 0x07) == 7);
}
/* from clause 20.2.1.3.2 Constructed Data */
/* returns the number of apdu bytes consumed */
/**
* @brief Decodes the tag number and the value,
* that the APDU pointer is addressing.
* (From clause 20.2.1.3.2 Constructed Data)
*
* @param apdu Pointer to the message buffer.
* @param tag_number Pointer to a variable
* taking the tag number.
* @param value Pointer to a variable
* taking the value.
*
* @return number of bytes decoded, or zero if errors occur
*/
int decode_tag_number_and_value(
uint8_t *apdu, uint8_t *tag_number, uint32_t *value)
{
@@ -371,6 +442,7 @@ int decode_tag_number_and_value(
/* tagged as uint32_t */
if (apdu[len] == 255) {
len++;
value32 = 0;
len += decode_unsigned32(&apdu[len], &value32);
if (value) {
*value = value32;
@@ -379,6 +451,7 @@ int decode_tag_number_and_value(
/* tagged as uint16_t */
else if (apdu[len] == 254) {
len++;
value16 = 0;
len += decode_unsigned16(&apdu[len], &value16);
if (value) {
*value = value16;
@@ -392,6 +465,7 @@ int decode_tag_number_and_value(
len++;
}
} else if (IS_OPENING_TAG(apdu[0]) && value) {
/* opening tag */
*value = 0;
} else if (IS_CLOSING_TAG(apdu[0]) && value) {
/* closing tag */
@@ -466,16 +540,37 @@ int bacnet_tag_number_and_value_decode(
return len;
}
/* from clause 20.2.1.3.2 Constructed Data */
/* returns true if the tag is context specific and matches */
/**
* @brief Returns true if the tag is context specific
* and matches, as defined in clause 20.2.1.3.2 Constructed
* Data.
*
* @param apdu Pointer to the tag begin.
* @param tag_number Tag number, that has been decoded before.
*
* @return true on a match, false otherwise.
*/
bool decode_is_context_tag(uint8_t *apdu, uint8_t tag_number)
{
uint8_t my_tag_number = 0;
decode_tag_number(apdu, &my_tag_number);
return (bool)(IS_CONTEXT_SPECIFIC(*apdu) && (my_tag_number == tag_number));
}
/**
* @brief Returns true if the tag is context specific
* and matches, as defined in clause 20.2.1.3.2 Constructed
* Data. This function returns the tag length as well.
*
* @param apdu Pointer to the tag begin.
* @param tag_number Tag number, that has been decoded before.
* @param tag_length Pointer to a variable, taking the
* length of the tag in bytes.
*
* @return true on a match, false otherwise.
*/
bool decode_is_context_tag_with_length(
uint8_t *apdu, uint8_t tag_number, int *tag_length)
{
@@ -486,18 +581,35 @@ bool decode_is_context_tag_with_length(
return (bool)(IS_CONTEXT_SPECIFIC(*apdu) && (my_tag_number == tag_number));
}
/* from clause 20.2.1.3.2 Constructed Data */
/* returns the true if the tag matches */
/**
* @brief Returns true if the tag does match and it
* is an opening tag as well.
* As defined in clause 20.2.1.3.2 Constructed Data.
*
* @param apdu Pointer to the tag begin.
* @param tag_number Tag number, that has been decoded before.
*
* @return true on a match, false otherwise.
*/
bool decode_is_opening_tag_number(uint8_t *apdu, uint8_t tag_number)
{
uint8_t my_tag_number = 0;
decode_tag_number(apdu, &my_tag_number);
return (bool)(IS_OPENING_TAG(apdu[0]) && (my_tag_number == tag_number));
}
/* from clause 20.2.1.3.2 Constructed Data */
/* returns the number of apdu bytes consumed */
/**
* @brief Returns true if the tag does match and it
* is an closing tag as well.
* As defined in clause 20.2.1.3.2 Constructed Data.
*
* @param apdu Pointer to the tag begin.
* @param tag_number Tag number, that has been decoded before.
*
* @return true on a match, false otherwise.
*/
bool decode_is_closing_tag_number(uint8_t *apdu, uint8_t tag_number)
{
uint8_t my_tag_number = 0;
@@ -506,28 +618,49 @@ bool decode_is_closing_tag_number(uint8_t *apdu, uint8_t tag_number)
return (bool)(IS_CLOSING_TAG(apdu[0]) && (my_tag_number == tag_number));
}
/* from clause 20.2.3 Encoding of a Boolean Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
/**
* @brief Encode an boolean value.
* From clause 20.2.3 Encoding of a Boolean Value
* and 20.2.1 General Rules for Encoding BACnet Tags.
*
* @param apdu Pointer to the encode buffer.
* @param boolean_value Boolean value to encode.
*
* @return returns the number of apdu bytes consumed
*/
int encode_application_boolean(uint8_t *apdu, bool boolean_value)
{
int len = 0;
uint32_t len_value = 0;
uint32_t len_value;
if (boolean_value) {
len_value = 1;
} else {
len_value = 0;
}
len =
encode_tag(&apdu[0], BACNET_APPLICATION_TAG_BOOLEAN, false, len_value);
return len;
}
/* context tagged is encoded differently */
/**
* @brief Encode an boolean value in a context.
* From clause 20.2.3 Encoding of a Boolean Value
* and 20.2.1 General Rules for Encoding BACnet Tags.
*
* @param apdu Pointer to the encode buffer.
* @param tag_number Tag number in which context
* the value shall be encoded.
* @param boolean_value Boolean value to encode.
*
* @return returns the number of apdu bytes consumed
*/
int encode_context_boolean(
uint8_t *apdu, uint8_t tag_number, bool boolean_value)
{
int len = 0; /* return value */
int len; /* return value */
len = encode_tag(&apdu[0], (uint8_t)tag_number, true, 1);
apdu[len] = (bool)(boolean_value ? 1 : 0);
@@ -536,6 +669,13 @@ int encode_context_boolean(
return len;
}
/**
* @brief Decode an boolean value.
*
* @param apdu Pointer to the encode buffer.
*
* @return true/false
*/
bool decode_context_boolean(uint8_t *apdu)
{
bool boolean_value = false;
@@ -547,6 +687,17 @@ bool decode_context_boolean(uint8_t *apdu)
return boolean_value;
}
/**
* @brief Decode an boolean value in the context of a tag.
*
* @param apdu Pointer to the encode buffer.
* @param tag_number Tag number in which context
* the value shall be encoded.
* @param boolean_value Pointer to a boolean variable
* taking the value.
*
* @return The count of bytes decoded or BACNET_STATUS_ERROR.
*/
int decode_context_boolean2(
uint8_t *apdu, uint8_t tag_number, bool *boolean_value)
{
@@ -564,33 +715,65 @@ int decode_context_boolean2(
return len;
}
/* from clause 20.2.3 Encoding of a Boolean Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
/**
* @brief Check the length value and return the boolean meaning.
* From clause 20.2.3 Encoding of a Boolean Value
* and 20.2.1 General Rules for Encoding BACnet Tags.
*
* @param len_value Tag length value.
*
* @return true/false
*/
bool decode_boolean(uint32_t len_value)
{
bool boolean_value = false;
bool boolean_value;
if (len_value) {
boolean_value = true;
} else {
boolean_value = false;
}
return boolean_value;
}
/* from clause 20.2.2 Encoding of a Null Value */
/* and 20.2.1 General Rules for Encoding BACnet Tags */
/* returns the number of apdu bytes consumed */
/**
* @brief Encode a Null value.
* From clause 20.2.2 Encoding of a Null Value
* and 20.2.1 General Rules for Encoding BACnet Tags.
*
* @param apdu Pointer to the encode buffer.
*
* @return returns the number of apdu bytes consumed.
*/
int encode_application_null(uint8_t *apdu)
{
return encode_tag(&apdu[0], BACNET_APPLICATION_TAG_NULL, false, 0);
}
/**
* @brief Encode a Null value in a tag context.
* From clause 20.2.2 Encoding of a Null Value
* and 20.2.1 General Rules for Encoding BACnet Tags.
*
* @param apdu Pointer to the encode buffer.
* @param tag_number Tag number in which context
* the value shall be encoded.
*
* @return returns the number of apdu bytes consumed.
*/
int encode_context_null(uint8_t *apdu, uint8_t tag_number)
{
return encode_tag(&apdu[0], tag_number, true, 0);
}
/**
* @brief Reverse the bits of the given byte.
*
* @param in_byte Byte to reverse.
*
* @return Byte with reversed bit order.
*/
static uint8_t byte_reverse_bits(uint8_t in_byte)
{
uint8_t out_byte = 0;
@@ -623,35 +806,61 @@ static uint8_t byte_reverse_bits(uint8_t in_byte)
return out_byte;
}
/* from clause 20.2.10 Encoding of a Bit String Value */
/* returns the number of apdu bytes consumed */
/**
* @brief Decode a bit string value.
* (From clause 20.2.10 Encoding of a Bit String Value.)
*
* @param apdu Pointer to the buffer holding the message data.
* @param len_value Length of the Data to decode.
* @param bit_string Pointer to the bit string variable,
* taking the decoded result.
*
* @return Returns the number of apdu bytes consumed.
*/
int decode_bitstring(
uint8_t *apdu, uint32_t len_value, BACNET_BIT_STRING *bit_string)
uint8_t * apdu,
uint32_t len_value,
BACNET_BIT_STRING * bit_string)
{
int len = 0;
uint8_t unused_bits = 0;
uint32_t i = 0;
uint32_t bytes_used = 0;
int len = 0; /* Return value */
uint8_t unused_bits;
uint32_t i;
uint32_t bytes_used;
bitstring_init(bit_string);
if (len_value) {
/* the first octet contains the unused bits */
bytes_used = len_value - 1;
if (bytes_used <= MAX_BITSTRING_BYTES) {
len = 1;
for (i = 0; i < bytes_used; i++) {
bitstring_set_octet(
bit_string, (uint8_t)i, byte_reverse_bits(apdu[len++]));
if (apdu && bit_string) {
/* Init/empty the string. */
bitstring_init(bit_string);
if (len_value) {
/* The first octet contains the unused bits. */
bytes_used = len_value - 1;
if (bytes_used <= MAX_BITSTRING_BYTES) {
len = 1;
/* Copy the bytes in reversed bit order. */
for (i = 0; i < bytes_used; i++) {
bitstring_set_octet(bit_string, (uint8_t) i,
byte_reverse_bits(apdu[len++]));
}
/* Erase the remaining unsed bits. */
unused_bits = (uint8_t) (apdu[0] & 0x07);
bitstring_set_bits_used(bit_string, (uint8_t) bytes_used,
unused_bits);
}
unused_bits = (uint8_t)(apdu[0] & 0x07);
bitstring_set_bits_used(
bit_string, (uint8_t)bytes_used, unused_bits);
}
}
return len;
}
/**
* @brief Decode a bit string value in the given context.
* (From clause 20.2.10 Encoding of a Bit String Value.)
*
* @param apdu Pointer to the buffer holding the message data.
* @param tag_number Tag number (context).
* @param bit_string Pointer to the bit string variable,
* taking the decoded result.
*
* @return Returns the number of bytes dcoded or BACNET_STATUS_ERROR.
*/
int decode_context_bitstring(
uint8_t *apdu, uint8_t tag_number, BACNET_BIT_STRING *bit_string)
{
+182 -84
View File
@@ -41,6 +41,18 @@
/** @file bacdevobjpropref.c BACnet Application Device Object (Property)
* Reference */
/**
* Encode a property reference for the device object.
* Add an opening tag, encode the property and finally
* add a closing tag as well.
*
* @param apdu Pointer to the buffer to encode to.
* @param tag_number Tag number.
* @param value Pointer to the object property reference,
* used for encoding.
*
* @return Bytes encoded or 0 on failure.
*/
int bacapp_encode_context_device_obj_property_ref(uint8_t *apdu,
uint8_t tag_number,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value)
@@ -48,28 +60,39 @@ int bacapp_encode_context_device_obj_property_ref(uint8_t *apdu,
int len;
int apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
if (value) {
len = encode_opening_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
len = bacapp_encode_device_obj_property_ref(&apdu[apdu_len], value);
apdu_len += len;
len = bacapp_encode_device_obj_property_ref(&apdu[apdu_len], value);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
}
return apdu_len;
}
/* BACnetDeviceObjectPropertyReference ::= SEQUENCE {
object-identifier [0] BACnetObjectIdentifier,
property-identifier [1] BACnetPropertyIdentifier,
property-array-index [2] Unsigned OPTIONAL,
-- used only with array datatype
-- if omitted with an array then
-- the entire array is referenced
device-identifier [3] BACnetObjectIdentifier OPTIONAL
}
*/
/**
* Encode a property reference for the device object.
*
* BACnetDeviceObjectPropertyReference ::= SEQUENCE {
* object-identifier [0] BACnetObjectIdentifier,
* property-identifier [1] BACnetPropertyIdentifier,
* property-array-index [2] Unsigned OPTIONAL,
* -- used only with array datatype
* -- if omitted with an array then
* -- the entire array is referenced
* device-identifier [3] BACnetObjectIdentifier OPTIONAL
* }
*
* @param apdu Pointer to the buffer to encode to.
* @param value Pointer to the object property reference,
* used for encoding.
*
* @return Bytes encoded.
*/
int bacapp_encode_device_obj_property_ref(
uint8_t *apdu, BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value)
{
@@ -102,45 +125,56 @@ int bacapp_encode_device_obj_property_ref(
return apdu_len;
}
/* BACnetDeviceObjectPropertyReference ::= SEQUENCE {
object-identifier [0] BACnetObjectIdentifier,
property-identifier [1] BACnetPropertyIdentifier,
property-array-index [2] Unsigned OPTIONAL,
-- used only with array datatype
-- if omitted with an array then
-- the entire array is referenced
device-identifier [3] BACnetObjectIdentifier OPTIONAL
}
*/
/**
* Decode a property reference of a device object.
*
* BACnetDeviceObjectPropertyReference ::= SEQUENCE {
* object-identifier [0] BACnetObjectIdentifier,
* property-identifier [1] BACnetPropertyIdentifier,
* property-array-index [2] Unsigned OPTIONAL,
* -- used only with array datatype
* -- if omitted with an array then
* -- the entire array is referenced
* device-identifier [3] BACnetObjectIdentifier OPTIONAL
* }
*
* @param apdu Pointer to the buffer containing the data to decode.
* @param value Pointer to the object property reference,
* used to decode the data into.
*
* @return Bytes decoded or BACNET_STATUS_ERROR on failure.
*/
int bacapp_decode_device_obj_property_ref(
uint8_t *apdu, BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value)
{
int len;
int apdu_len = 0;
uint32_t enumValue;
uint32_t enumValue = 0;
/* object-identifier [0] BACnetObjectIdentifier */
if (-1 ==
(len = decode_context_object_id(&apdu[apdu_len], 0,
&value->objectIdentifier.type,
&value->objectIdentifier.instance))) {
return -1;
len =
decode_context_object_id(&apdu[apdu_len], 0,
&value->objectIdentifier.type,
&value->objectIdentifier.instance);
if (len == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
/* property-identifier [1] BACnetPropertyIdentifier */
if (-1 ==
(len = decode_context_enumerated(&apdu[apdu_len], 1, &enumValue))) {
return -1;
len =
decode_context_enumerated(&apdu[apdu_len], 1, &enumValue);
if (len == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
value->propertyIdentifier = (BACNET_PROPERTY_ID)enumValue;
apdu_len += len;
/* property-array-index [2] Unsigned OPTIONAL */
if (decode_is_context_tag(&apdu[apdu_len], 2) &&
!decode_is_closing_tag(&apdu[apdu_len])) {
if (-1 ==
(len = decode_context_unsigned(
&apdu[apdu_len], 2, &value->arrayIndex))) {
return -1;
len = decode_context_unsigned(
&apdu[apdu_len], 2, &value->arrayIndex);
if (len == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
} else {
@@ -164,7 +198,19 @@ int bacapp_decode_device_obj_property_ref(
return apdu_len;
}
int bacapp_decode_context_device_obj_property_ref(uint8_t *apdu,
/**
* Decode the opening tag and the property reference of
* an device object and check for the closing tag as well.
*
* @param apdu Pointer to the buffer containing the data to decode.
* @param tag_number Tag number
* @param value Pointer to the object property reference,
* used to decode the data into.
*
* @return Bytes decoded or BACNET_STATUS_ERROR on failure.
*/
int bacapp_decode_context_device_obj_property_ref(
uint8_t *apdu,
uint8_t tag_number,
BACNET_DEVICE_OBJECT_PROPERTY_REFERENCE *value)
{
@@ -175,51 +221,77 @@ int bacapp_decode_context_device_obj_property_ref(uint8_t *apdu,
len++;
section_length =
bacapp_decode_device_obj_property_ref(&apdu[len], value);
if (section_length == -1) {
len = -1;
if (section_length == BACNET_STATUS_ERROR) {
len = BACNET_STATUS_ERROR;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
len++;
} else {
len = -1;
len = BACNET_STATUS_ERROR;
}
}
} else {
len = -1;
len = BACNET_STATUS_ERROR;
}
return len;
}
/* BACnetDeviceObjectReference ::= SEQUENCE {
device-identifier [0] BACnetObjectIdentifier OPTIONAL,
object-identifier [1] BACnetObjectIdentifier
}*/
/**
* Encode the opening tag and the device object reference
* and finally for the closing tag as well.
*
* BACnetDeviceObjectReference ::= SEQUENCE {
* device-identifier [0] BACnetObjectIdentifier OPTIONAL,
* object-identifier [1] BACnetObjectIdentifier
* }
*
* @param apdu Pointer to the buffer used for encoding.
* @param tag_number Tag number
* @param value Pointer to the device object reference,
* used to encode.
*
* @return Bytes encoded or 0 on failure.
*/
int bacapp_encode_context_device_obj_ref(
uint8_t *apdu, uint8_t tag_number, BACNET_DEVICE_OBJECT_REFERENCE *value)
uint8_t *apdu,
uint8_t tag_number,
BACNET_DEVICE_OBJECT_REFERENCE *value)
{
int len;
int apdu_len = 0;
len = encode_opening_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
if (value) {
len = encode_opening_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
len = bacapp_encode_device_obj_ref(&apdu[apdu_len], value);
apdu_len += len;
len = bacapp_encode_device_obj_ref(&apdu[apdu_len], value);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
len = encode_closing_tag(&apdu[apdu_len], tag_number);
apdu_len += len;
}
return apdu_len;
}
/* BACnetDeviceObjectReference ::= SEQUENCE {
device-identifier [0] BACnetObjectIdentifier OPTIONAL,
object-identifier [1] BACnetObjectIdentifier
}*/
/**
* Encode the device object reference.
*
* BACnetDeviceObjectReference ::= SEQUENCE {
* device-identifier [0] BACnetObjectIdentifier OPTIONAL,
* object-identifier [1] BACnetObjectIdentifier
* }
*
* @param apdu Pointer to the buffer used for encoding.
* @param value Pointer to the device object reference,
* used to encode.
*
* @return Bytes encoded or 0 on failure.
*/
int bacapp_encode_device_obj_ref(
uint8_t *apdu, BACNET_DEVICE_OBJECT_REFERENCE *value)
uint8_t * apdu,
BACNET_DEVICE_OBJECT_REFERENCE * value)
{
int len;
int apdu_len = 0;
@@ -234,19 +306,31 @@ int bacapp_encode_device_obj_ref(
apdu_len += len;
}
/* object-identifier [1] BACnetObjectIdentifier */
len = encode_context_object_id(&apdu[apdu_len], 1,
value->objectIdentifier.type, value->objectIdentifier.instance);
len =
encode_context_object_id(&apdu[apdu_len], 1,
value->objectIdentifier.type, value->objectIdentifier.instance);
apdu_len += len;
return apdu_len;
}
/* BACnetDeviceObjectReference ::= SEQUENCE {
device-identifier [0] BACnetObjectIdentifier OPTIONAL,
object-identifier [1] BACnetObjectIdentifier
}*/
/**
* Decode the device object reference.
*
* BACnetDeviceObjectReference ::= SEQUENCE {
* device-identifier [0] BACnetObjectIdentifier OPTIONAL,
* object-identifier [1] BACnetObjectIdentifier
* }
*
* @param apdu Pointer to the buffer containing the data to decode.
* @param value Pointer to the object object reference,
* that shall be decoded.
*
* @return Bytes decoded or BACNET_STATUS_ERROR on failure.
*/
int bacapp_decode_device_obj_ref(
uint8_t *apdu, BACNET_DEVICE_OBJECT_REFERENCE *value)
uint8_t * apdu,
BACNET_DEVICE_OBJECT_REFERENCE * value)
{
int len;
int apdu_len = 0;
@@ -254,11 +338,12 @@ int bacapp_decode_device_obj_ref(
/* device-identifier [0] BACnetObjectIdentifier OPTIONAL */
if (decode_is_context_tag(&apdu[apdu_len], 0) &&
!decode_is_closing_tag(&apdu[apdu_len])) {
if (-1 ==
(len = decode_context_object_id(&apdu[apdu_len], 0,
&value->deviceIdentifier.type,
&value->deviceIdentifier.instance))) {
return -1;
len =
decode_context_object_id(&apdu[apdu_len], 0,
&value->deviceIdentifier.type,
&value->deviceIdentifier.instance);
if (len == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
} else {
@@ -266,19 +351,33 @@ int bacapp_decode_device_obj_ref(
value->deviceIdentifier.instance = BACNET_NO_DEV_ID;
}
/* object-identifier [1] BACnetObjectIdentifier */
if (-1 ==
(len = decode_context_object_id(&apdu[apdu_len], 1,
&value->objectIdentifier.type,
&value->objectIdentifier.instance))) {
return -1;
len =
decode_context_object_id(&apdu[apdu_len], 1,
&value->objectIdentifier.type,
&value->objectIdentifier.instance);
if (len == BACNET_STATUS_ERROR) {
return BACNET_STATUS_ERROR;
}
apdu_len += len;
return apdu_len;
}
/**
* Decode the context device object reference. Check for
* an opening tag and a closing tag as well.
*
* @param apdu Pointer to the buffer containing the data to decode.
* @param tag_number Tag number
* @param value Pointer to the context device object reference,
* that shall be decoded.
*
* @return Bytes decoded or BACNET_STATUS_ERROR on failure.
*/
int bacapp_decode_context_device_obj_ref(
uint8_t *apdu, uint8_t tag_number, BACNET_DEVICE_OBJECT_REFERENCE *value)
uint8_t * apdu,
uint8_t tag_number,
BACNET_DEVICE_OBJECT_REFERENCE * value)
{
int len = 0;
int section_length;
@@ -286,19 +385,18 @@ int bacapp_decode_context_device_obj_ref(
if (decode_is_opening_tag_number(&apdu[len], tag_number)) {
len++;
section_length = bacapp_decode_device_obj_ref(&apdu[len], value);
if (section_length == -1) {
len = -1;
if (section_length == BACNET_STATUS_ERROR) {
len = BACNET_STATUS_ERROR;
} else {
len += section_length;
if (decode_is_closing_tag_number(&apdu[len], tag_number)) {
len++;
} else {
len = -1;
len = BACNET_STATUS_ERROR;
}
}
} else {
len = -1;
len = BACNET_STATUS_ERROR;
}
return len;
}
+385 -94
View File
@@ -48,65 +48,105 @@
#define BACNET_STRING_UTF8_VALIDATION 1
#endif
/**
* Initialize a bit string.
*
* @param bit_string Pointer to the bit string structure.
*/
void bitstring_init(BACNET_BIT_STRING *bit_string)
{
int i;
bit_string->bits_used = 0;
for (i = 0; i < MAX_BITSTRING_BYTES; i++) {
bit_string->value[i] = 0;
if (bit_string) {
bit_string->bits_used = 0;
for (i = 0; i < MAX_BITSTRING_BYTES; i++) {
bit_string->value[i] = 0;
}
}
}
/**
* Set bits in the bit string.
*
* @param bit_string Pointer to the bit string structure.
* @param bit_number Number of the bit [0..(MAX_BITSTRING_BYTES*8)-1]
* @param value Value 0/1
*/
void bitstring_set_bit(
BACNET_BIT_STRING *bit_string, uint8_t bit_number, bool value)
{
uint8_t byte_number = bit_number / 8;
uint8_t bit_mask = 1;
if (byte_number < MAX_BITSTRING_BYTES) {
/* set max bits used */
if (bit_string->bits_used < (bit_number + 1)) {
bit_string->bits_used = bit_number + 1;
}
bit_mask = bit_mask << (bit_number - (byte_number * 8));
if (value) {
bit_string->value[byte_number] |= bit_mask;
} else {
bit_string->value[byte_number] &= (~(bit_mask));
if (bit_string) {
if (byte_number < MAX_BITSTRING_BYTES) {
/* set max bits used */
if (bit_string->bits_used < (bit_number + 1)) {
bit_string->bits_used = bit_number + 1;
}
bit_mask = bit_mask << (bit_number - (byte_number * 8));
if (value) {
bit_string->value[byte_number] |= bit_mask;
} else {
bit_string->value[byte_number] &= (~(bit_mask));
}
}
}
}
/**
* Return the value of a single bit
* out of the bit string.
*
* @param bit_string Pointer to the bit string structure.
* @param bit_number Number of the bit [0..(MAX_BITSTRING_BYTES*8)-1]
*
* @return Value 0/1
*/
bool bitstring_bit(BACNET_BIT_STRING *bit_string, uint8_t bit_number)
{
bool value = false;
uint8_t byte_number = bit_number / 8;
uint8_t bit_mask = 1;
if (bit_number < (MAX_BITSTRING_BYTES * 8)) {
bit_mask = bit_mask << (bit_number - (byte_number * 8));
if (bit_string->value[byte_number] & bit_mask) {
value = true;
if (bit_string) {
if (bit_number < (MAX_BITSTRING_BYTES * 8)) {
bit_mask = bit_mask << (bit_number - (byte_number * 8));
if (bit_string->value[byte_number] & bit_mask) {
value = true;
}
}
}
return value;
}
/**
* Return the number of bits used.
*
* @param bit_string Pointer to the bit string structure.
*
* @return Bits used [0..(MAX_BITSTRING_BYTES*8)-1]
*/
uint8_t bitstring_bits_used(BACNET_BIT_STRING *bit_string)
{
return bit_string->bits_used;
return (bit_string ? bit_string->bits_used : 0);
}
/* returns the number of bytes that a bit string is using */
/**
* Returns the number of bytes that a bit string is using.
*
* @param bit_string Pointer to the bit string structure.
*
* @return Bytes used [0..MAX_BITSTRING_BYTES]
*/
uint8_t bitstring_bytes_used(BACNET_BIT_STRING *bit_string)
{
uint8_t len = 0; /* return value */
uint8_t used_bytes = 0;
uint8_t last_bit = 0;
if (bit_string->bits_used) {
if (bit_string && bit_string->bits_used) {
last_bit = bit_string->bits_used - 1;
used_bytes = last_bit / 8;
/* add one for the first byte */
@@ -117,6 +157,14 @@ uint8_t bitstring_bytes_used(BACNET_BIT_STRING *bit_string)
return len;
}
/**
* Returns an octed at the given bit position.
*
* @param bit_string Pointer to the bit string structure.
* @param octet_index Byte index of the octed [0..MAX_BITSTRING_BYTES-1]
*
* @return Value of the octed.
*/
uint8_t bitstring_octet(BACNET_BIT_STRING *bit_string, uint8_t octet_index)
{
uint8_t octet = 0;
@@ -130,6 +178,15 @@ uint8_t bitstring_octet(BACNET_BIT_STRING *bit_string, uint8_t octet_index)
return octet;
}
/**
* Set an octed at the given bit position.
*
* @param bit_string Pointer to the bit string structure.
* @param index Byte index of the octed [0..MAX_BITSTRING_BYTES-1]
* @param octet Octet value
*
* @return true on success, false otherwise.
*/
bool bitstring_set_octet(
BACNET_BIT_STRING *bit_string, uint8_t index, uint8_t octet)
{
@@ -145,13 +202,25 @@ bool bitstring_set_octet(
return status;
}
/**
* Write the amount of bits used in the bit
* string structure.
*
* @param bit_string Pointer to the bit string structure.
* @param bytes_used Count of bytes used.
* @param unused_bits Count of remaining unused bits in
* the last byte.
*
* @return true on success or false on error.
*/
bool bitstring_set_bits_used(
BACNET_BIT_STRING *bit_string, uint8_t bytes_used, uint8_t unused_bits)
BACNET_BIT_STRING * bit_string,
uint8_t bytes_used,
uint8_t unused_bits)
{
bool status = false;
if (bit_string) {
/* FIXME: check that bytes_used is at least one? */
if (bit_string && bytes_used) {
bit_string->bits_used = bytes_used * 8;
bit_string->bits_used -= unused_bits;
status = true;
@@ -160,6 +229,13 @@ bool bitstring_set_bits_used(
return status;
}
/**
* Return the capcity of the bit string.
*
* @param bit_string Pointer to the bit string structure.
*
* @return Capacitiy in bits [0..(MAX_BITSTRING_BYTES*8)]
*/
uint8_t bitstring_bits_capacity(BACNET_BIT_STRING *bit_string)
{
if (bit_string) {
@@ -169,6 +245,14 @@ uint8_t bitstring_bits_capacity(BACNET_BIT_STRING *bit_string)
}
}
/**
* Copy bits from one bit string to another.
*
* @param dest Pointer to the destination bit string structure.
* @param src Pointer to the source bit string structure.
*
* @return true on success, false otherwise.
*/
bool bitstring_copy(BACNET_BIT_STRING *dest, BACNET_BIT_STRING *src)
{
unsigned i;
@@ -185,25 +269,34 @@ bool bitstring_copy(BACNET_BIT_STRING *dest, BACNET_BIT_STRING *src)
return status;
}
/* returns true if the same length and contents */
/**
* Returns true if the same length and contents.
*
* @param bitstring1 Pointer to the first bit string structure.
* @param bitstring2 Pointer to the second bit string structure.
*
* @return true if the content of both bit strings are
* the same, false otherwise.
*/
bool bitstring_same(
BACNET_BIT_STRING *bitstring1, BACNET_BIT_STRING *bitstring2)
{
int i = 0; /* loop counter */
int i; /* loop counter */
int bytes_used = 0;
uint8_t compare_mask = 0;
if (bitstring1 && bitstring2) {
bytes_used = (int)(bitstring1->bits_used / 8);
if ((bitstring1->bits_used == bitstring2->bits_used) &&
(bitstring1->bits_used / 8 <= MAX_BITSTRING_BYTES)) {
bytes_used = (int)(bitstring1->bits_used / 8);
compare_mask = 0xFF >> (8 - (bitstring1->bits_used % 8));
(bytes_used <= MAX_BITSTRING_BYTES)) {
/* compare fully used bytes */
for (i = 0; i < bytes_used; i++) {
if (bitstring1->value[i] != bitstring2->value[i]) {
return false;
}
}
/* compare only the relevant bits of last partly used byte */
compare_mask = 0xFF >> (8 - (bitstring1->bits_used % 8));
if ((bitstring1->value[bytes_used] & compare_mask) !=
(bitstring2->value[bytes_used] & compare_mask)) {
return false;
@@ -217,9 +310,18 @@ bool bitstring_same(
}
#if PRINT_ENABLED
/* converts an null terminated ASCII string to an bitstring.
Expects "1,0,1,0,1,1" or "101011" as the bits
returns true if successfully converted and fits; false if too long */
/**
* Converts an null terminated ASCII string to an bitstring.
*
* Expects "1,0,1,0,1,1" or "101011" as the bits
*
* @param bit_string Pointer to the bit string structure.
* @param ascii Pointer to a zero terminated string, made up from
* '0' and '1' like "010010011", that shall be
* converted into a bit string.
*
* @return true if successfully converted and fits; false if too long.
*/
bool bitstring_init_ascii(BACNET_BIT_STRING *bit_string, const char *ascii)
{
bool status = false; /* return value */
@@ -262,8 +364,19 @@ bool bitstring_init_ascii(BACNET_BIT_STRING *bit_string, const char *ascii)
#endif
#define CHARACTER_STRING_CAPACITY (MAX_CHARACTER_STRING_BYTES - 1)
/* returns false if the string exceeds capacity
initialize by using value=NULL */
/**
* Initialize a BACnet characater string.
* Returns false if the string exceeds capacity.
* Initialize by using value=NULL
*
* @param char_string Pointer to the BACnet string
* @param encoding Encoding that shall be used
* like CHARACTER_UTF8
* @param value C-string used to initialize the object
* @param length C-String length in characters.
*
* @return true on success, false if the string exceeds capacity.
*/
bool characterstring_init(BACNET_CHARACTER_STRING *char_string,
uint8_t encoding,
const char *value,
@@ -299,6 +412,17 @@ bool characterstring_init(BACNET_CHARACTER_STRING *char_string,
return status;
}
/**
* Initialize a BACnet characater string.
* Returns false if the string exceeds capacity.
* Initialize by using value=NULL
*
* @param char_string Pointer to the BACnet string
* @param value C-string used to initialize the object
* @param tmax C-String length in characters.
*
* @return true/false
*/
bool characterstring_init_ansi_safe(
BACNET_CHARACTER_STRING *char_string, const char *value, size_t tmax)
{
@@ -306,6 +430,16 @@ bool characterstring_init_ansi_safe(
value ? strnlen(value, tmax) : 0);
}
/**
* Initialize a BACnet characater string.
* Returns false if the string exceeds capacity.
* Initialize by using value=NULL
*
* @param char_string Pointer to the BACnet string
* @param value C-string used to initialize the object
*
* @return true/false
*/
bool characterstring_init_ansi(
BACNET_CHARACTER_STRING *char_string, const char *value)
{
@@ -313,34 +447,64 @@ bool characterstring_init_ansi(
char_string, CHARACTER_ANSI_X34, value, value ? strlen(value) : 0);
}
/**
* Copy a character string.
*
* @param dest Pointer to the destination string.
* @param src Pointer to the source string.
*
* @return true/false
*/
bool characterstring_copy(
BACNET_CHARACTER_STRING *dest, BACNET_CHARACTER_STRING *src)
{
return characterstring_init(dest, characterstring_encoding(src),
characterstring_value(src), characterstring_length(src));
}
bool characterstring_ansi_copy(
char *dest, size_t dest_max_len, BACNET_CHARACTER_STRING *src)
{
size_t i; /* counter */
if (dest && src && (src->encoding == CHARACTER_ANSI_X34) &&
(src->length < dest_max_len)) {
for (i = 0; i < dest_max_len; i++) {
if (i < src->length) {
dest[i] = src->value[i];
} else {
dest[i] = 0;
}
}
return true;
if (dest && src) {
return characterstring_init(dest, characterstring_encoding(src),
characterstring_value(src), characterstring_length(src));
}
return false;
}
/* returns true if the character encoding and string contents are the same */
/**
* Copy a character string into a C-string.
*
* @param dest Pointer to the destination C-string buffer.
* @param dest_max_len Size of the destination C-string buffer.
* @param src Pointer to the source BACnet string.
*
* @return true/false
*/
bool characterstring_ansi_copy(
char *dest, size_t dest_max_len, BACNET_CHARACTER_STRING *src)
{
size_t i; /* counter */
if (dest && src) {
if ((src->encoding == CHARACTER_ANSI_X34) && (src->length < dest_max_len)) {
for (i = 0; i < dest_max_len; i++) {
if (i < src->length) {
dest[i] = src->value[i];
} else {
dest[i] = 0;
}
}
return true;
}
}
return false;
}
/**
* Returns true if the character encoding and string
* contents are the same.
*
* @param dest Pointer to the first string to test.
* @param src Pointer to the second string to test.
*
* @return true if the character encoding and string contents are the same
*/
bool characterstring_same(
BACNET_CHARACTER_STRING *dest, BACNET_CHARACTER_STRING *src)
{
@@ -348,12 +512,14 @@ bool characterstring_same(
bool same_status = false;
if (src && dest) {
if ((src->length == dest->length) &&
(src->encoding == dest->encoding)) {
if ((src->encoding == dest->encoding) &&
(src->length == dest->length) &&
(src->length <= MAX_CHARACTER_STRING_BYTES)) {
same_status = true;
for (i = 0; (i < src->length) && same_status; i++) {
for (i = 0; i < src->length; i++) {
if (src->value[i] != dest->value[i]) {
same_status = false;
break;
}
}
}
@@ -370,18 +536,29 @@ bool characterstring_same(
return same_status;
}
/**
* Returns true if the BACnet string and the C-string
* contents are the same.
*
* @param dest Pointer to the first string to test.
* @param src Pointer to the second string to test.
*
* @return true if the character encoding and string contents are the same
*/
bool characterstring_ansi_same(BACNET_CHARACTER_STRING *dest, const char *src)
{
size_t i; /* counter */
bool same_status = false;
if (src && dest) {
if ((dest->length == strlen(src)) &&
(dest->encoding == CHARACTER_ANSI_X34)) {
if ((dest->encoding == CHARACTER_ANSI_X34) &&
(dest->length == strlen(src)) &&
(dest->length <= MAX_CHARACTER_STRING_BYTES)) {
same_status = true;
for (i = 0; (i < dest->length) && same_status; i++) {
for (i = 0; i < dest->length; i++) {
if (src[i] != dest->value[i]) {
same_status = false;
break;
}
}
}
@@ -400,7 +577,18 @@ bool characterstring_ansi_same(BACNET_CHARACTER_STRING *dest, const char *src)
return same_status;
}
/* returns false if the string exceeds capacity */
/**
* Append some characters to the end of the characterstring
*
* @param char_string Pointer to the BACnet string to which
* the content of the C-string shall be added.
* @param value Pointer to the C-String to be added.
* @param length Count of characters to add.
*
* @param src Pointer to the first string to test.
*
* @return false if the string exceeds capacity.
*/
bool characterstring_append(
BACNET_CHARACTER_STRING *char_string, const char *value, size_t length)
{
@@ -420,9 +608,14 @@ bool characterstring_append(
return status;
}
/* This function sets a new length without changing the value.
If length exceeds capacity, no modification happens and
function returns false. */
/**
* @brief This function sets a new length without changing
* the value. If length exceeds capacity, no modification
* happens and function returns false.
*
* @return true on success, false if the string exceeds
* capacity.
*/
bool characterstring_truncate(
BACNET_CHARACTER_STRING *char_string, size_t length)
{
@@ -587,8 +780,8 @@ bool characterstring_printable(BACNET_CHARACTER_STRING *char_string)
#if BACNET_STRING_UTF8_VALIDATION
/* Basic UTF-8 manipulation routines
by Jeff Bezanson
placed in the public domain Fall 2005 */
* by Jeff Bezanson
* placed in the public domain Fall 2005 */
static const char trailingBytesForUTF8[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
@@ -601,19 +794,33 @@ static const char trailingBytesForUTF8[256] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5 };
/* based on the valid_utf8 routine from the PCRE library by Philip Hazel
length is in bytes, since without knowing whether the string is valid
it's hard to know how many characters there are! */
/**
* @brief Based on the valid_utf8 routine from the PCRE library by Philip Hazel
* length is in bytes, since without knowing whether the string is valid
* it's hard to know how many characters there are!
*
* @param str Pointer to the character string.
* @param length Count of bytes to check. The count of bytes
* does not necessarily match the count of chars.
*
* @return true if the string is valid, false otherwise.
*/
bool utf8_isvalid(const char *str, size_t length)
{
const unsigned char *p, *pend = (unsigned char *)str + length;
const unsigned char *p, *pend;
unsigned char c;
size_t ab;
/* empty string is valid */
/* An empty string is valid. */
if (length == 0) {
return true;
}
/* Check pointer. */
if (!str) {
return false;
}
/* Check characters. */
pend = (unsigned char *) str + length;
for (p = (const unsigned char *)str; p < pend; p++) {
c = *p;
/* null in middle of string */
@@ -696,26 +903,45 @@ bool utf8_isvalid(const char *str, size_t length)
}
#endif
/**
* Check if the character string is valid or not.
*
* @param char_string Pointer to the character string.
*
* @return true if the string is valid, false otherwise.
*/
bool characterstring_valid(BACNET_CHARACTER_STRING *char_string)
{
bool valid = false; /* return value */
if (char_string->encoding < MAX_CHARACTER_STRING_ENCODING) {
if (char_string->encoding == CHARACTER_UTF8) {
if (utf8_isvalid(char_string->value, char_string->length)) {
if (char_string) {
if (char_string->encoding < MAX_CHARACTER_STRING_ENCODING) {
if (char_string->encoding == CHARACTER_UTF8) {
/*UTF8 check*/
if (utf8_isvalid(char_string->value, char_string->length)) {
valid = true;
}
} else {
/*non UTF8*/
valid = true;
}
} else {
valid = true;
}
}
return valid;
}
#if BACNET_USE_OCTETSTRING
/* returns false if the string exceeds capacity
initialize by using value=NULL */
/**
* @brief Initialize an octed string with the given bytes or
* zeros, if NULL for the value is provided.
*
* @param octet_string Pointer to the octed string.
* @param value Pointer to the bytes to be copied to the octed
* string or NULL to initialize the octed string.
* @param length Count of bytes used to fill the octed string.
*
* @return true on success, false if the string exceeds capacity.
*/
bool octetstring_init(
BACNET_OCTET_STRING *octet_string, uint8_t *value, size_t length)
{
@@ -746,8 +972,12 @@ bool octetstring_init(
}
#if PRINT_ENABLED
/* converts an null terminated ASCII Hex string to an octet string.
returns true if successfully converted and fits; false if too long */
/** @brief Converts an null terminated ASCII Hex string to an octet string.
*
* @param octet_string Pointer to the octed string.
* @param ascii_hex Pointer to the HEx-ASCII string.
*
* @return true if successfully converted and fits; false if too long */
bool octetstring_init_ascii_hex(
BACNET_OCTET_STRING *octet_string, const char *ascii_hex)
{
@@ -756,7 +986,7 @@ bool octetstring_init_ascii_hex(
uint8_t value = 0;
char hex_pair_string[3] = "";
if (octet_string) {
if (octet_string && ascii_hex) {
octet_string->length = 0;
if (ascii_hex[0] == 0) {
/* nothing to decode, so success! */
@@ -793,14 +1023,31 @@ bool octetstring_init_ascii_hex(
}
#endif
/**
* Copy an octed string from source to destination.
*
* @param dest Pointer to the destination octed string.
* @param src Pointer to the source octed string.
*
* @return true on success, false otherwise.
*/
bool octetstring_copy(BACNET_OCTET_STRING *dest, BACNET_OCTET_STRING *src)
{
return octetstring_init(
dest, octetstring_value(src), octetstring_length(src));
}
/* returns the number of bytes copied, or 0 if the dest
cannot hold entire octetstring value */
/**
* @brief Copy bytes from the octed string to a byte buffer.
*
* @param dest Pointer to the byte buffer.
* @param length Bytes to be copied from the
* octed string to the buffer.
* @param src Pointer to the octed string.
*
* @return Returns the number of bytes copied, or 0 if
* the dest cannot hold entire octetstring value.
*/
size_t octetstring_copy_value(
uint8_t *dest, size_t length, BACNET_OCTET_STRING *src)
{
@@ -819,7 +1066,15 @@ size_t octetstring_copy_value(
return bytes_copied;
}
/* returns false if the string exceeds capacity */
/**
* @brief Append bytes to the end of the octed string.
*
* @param octet_string Pointer to the octed string.
* @param value Pointer to the byte buffer to be appended.
* @param length Bytes to be appended.
*
* @return false if the string exceeds capacity.
*/
bool octetstring_append(
BACNET_OCTET_STRING *octet_string, uint8_t *value, size_t length)
{
@@ -839,9 +1094,16 @@ bool octetstring_append(
return status;
}
/* This function sets a new length without changing the value.
If length exceeds capacity, no modification happens and
function returns false. */
/**
* @brief This function sets a new length without changing the value.
* If length exceeds capacity, no modification happens and the
* function returns false.
*
* @param octet_string Pointer to the octed string.
* @param length New length the octed string is trucated to.
*
* @return tur on success, false otherwise.
*/
bool octetstring_truncate(BACNET_OCTET_STRING *octet_string, size_t length)
{
bool status = false; /* return value */
@@ -856,7 +1118,14 @@ bool octetstring_truncate(BACNET_OCTET_STRING *octet_string, size_t length)
return status;
}
/* returns a pointer to the value. */
/**
* @brief Returns a pointer to the value (data) of
* the given octed string.
*
* @param octet_string Pointer to the octed string.
*
* @return Value as a pointer to a byte array or NULL on error.
*/
uint8_t *octetstring_value(BACNET_OCTET_STRING *octet_string)
{
uint8_t *value = NULL;
@@ -868,33 +1137,55 @@ uint8_t *octetstring_value(BACNET_OCTET_STRING *octet_string)
return value;
}
/* returns the length. */
/**
* @brief Returns the length in bytes of
* the given octed string.
*
* @param octet_string Pointer to the octed string.
*
* @return Length in bytes. Returns always 0 on error.
*/
size_t octetstring_length(BACNET_OCTET_STRING *octet_string)
{
size_t length = 0;
if (octet_string) {
/* FIXME: validate length is within bounds? */
length = octet_string->length;
/* Force length to be within bounds. */
if (length > MAX_OCTET_STRING_BYTES) {
length = MAX_OCTET_STRING_BYTES;
}
}
return length;
}
/* returns the maximum capacity. */
/**
* @brief Returns the maximum capacity of an octed string.
*
* @param octet_string Pointer to the octed string.
*
* @return Capacity in bytes. Returns always 0 on error.
*/
size_t octetstring_capacity(BACNET_OCTET_STRING *octet_string)
{
size_t length = 0;
if (octet_string) {
/* FIXME: validate length is within bounds? */
length = MAX_OCTET_STRING_BYTES;
}
return length;
}
/* returns true if the same length and contents */
/**
* @brief Returns true if the same length and contents.
*
* @param octet_string1 Pointer to the first octed string.
* @param octet_string2 Pointer to the second octed string.
*
* @return true if the octed strings are the same, false otherwise.
*/
bool octetstring_value_same(
BACNET_OCTET_STRING *octet_string1, BACNET_OCTET_STRING *octet_string2)
{
+6
View File
@@ -226,6 +226,9 @@ int cl_decode_apdu(uint8_t *apdu,
case BACNET_APPLICATION_TAG_BOOLEAN:
len = decode_context_boolean2(
&apdu[dec_len], 4, &bcl->Value.type.Boolean);
if (len < 0) {
return BACNET_STATUS_REJECT;
}
break;
case BACNET_APPLICATION_TAG_UNSIGNED_INT:
len = decode_context_unsigned(&apdu[dec_len], 4, &unsigned_value);
@@ -256,6 +259,9 @@ int cl_decode_apdu(uint8_t *apdu,
case BACNET_APPLICATION_TAG_BIT_STRING:
len = decode_context_bitstring(
&apdu[dec_len], 4, &bcl->Value.type.Bit_String);
if (len < 0) {
return BACNET_STATUS_REJECT;
}
break;
case BACNET_APPLICATION_TAG_ENUMERATED:
len = decode_context_enumerated(
+1 -1
View File
@@ -507,7 +507,7 @@ int event_notify_decode_service_request(
/* tag 9 - ackRequired */
section_length =
decode_context_boolean2(&apdu[len], 9, &data->ackRequired);
if (section_length == -1) {
if (section_length == BACNET_STATUS_ERROR) {
return -1;
}
len += section_length;