Get metadata for BEJ integer, string and bool
This change adds the support to derive bejInteger, bejString and
bejBool node metadata.
Signed-off-by: Kasun Athukorala <kasunath@google.com>
Change-Id: Ib6efcd29bf7cb2acc9913f95756e60ee65f16c6d
diff --git a/include/libbej/bej_common.h b/include/libbej/bej_common.h
index 96f1a66..6db5fd1 100644
--- a/include/libbej/bej_common.h
+++ b/include/libbej/bej_common.h
@@ -246,6 +246,17 @@
uint8_t bejGetNnintSize(const uint8_t* nnint);
/**
+ * @brief Get the bytes needed represent the value as a bejInteger.
+ *
+ * This will return the number of bytes needed to encode the signed value
+ * into a bejInteger type.
+ *
+ * @param val - signed value needed to encode.
+ * @return size of the bejInteger.
+ */
+ uint8_t bejIntLengthOfValue(int64_t val);
+
+ /**
* @brief Get the total bytes needed to encode an unsigned value using nnint
* format.
*
diff --git a/src/bej_common.c b/src/bej_common.c
index 0e1cf10..ca4a849 100644
--- a/src/bej_common.c
+++ b/src/bej_common.c
@@ -24,6 +24,45 @@
return *nnint + sizeof(uint8_t);
}
+uint8_t bejIntLengthOfValue(int64_t val)
+{
+ // Only need to encode 0x00 or 0xFF
+ if (val == 0 || val == -1)
+ {
+ return 1;
+ }
+
+ // Starts at the MSB. LSB index is 0.
+ uint8_t byteIndex = sizeof(uint64_t) - 1;
+ const uint8_t bitsPerByte = 8;
+ // The current byte being looked at. Starts at MSB.
+ uint8_t currentByte = (val >> (bitsPerByte * byteIndex)) & 0xFF;
+ uint8_t byteLength = sizeof(int64_t);
+
+ while ((val > 0 && currentByte == 0) || (val < 0 && currentByte == 0xFF))
+ {
+ byteLength--;
+ byteIndex--;
+ currentByte = (val >> (bitsPerByte * byteIndex)) & 0xFF;
+ }
+
+ // If the value is positive and encoded MSBbit is 1 we need to add 0x00 to
+ // the encoded value as padding.
+ if (val > 0 && (currentByte & 0x80))
+ {
+ byteLength++;
+ }
+
+ // If the value is negative and encoded MSBbit is 0 we need to add 0xFF to
+ // the encoded value as padding.
+ if (val < 0 && !(currentByte & 0x80))
+ {
+ byteLength++;
+ }
+
+ return byteLength;
+}
+
uint8_t bejNnintEncodingSizeOfUInt(uint64_t val)
{
uint8_t bytes = 0;
diff --git a/src/bej_encoder_metadata.c b/src/bej_encoder_metadata.c
index bb08874..3c32f80 100644
--- a/src/bej_encoder_metadata.c
+++ b/src/bej_encoder_metadata.c
@@ -8,6 +8,22 @@
#include <string.h>
/**
+ * @brief bejTupleL size of an integer.
+ *
+ * Maximum bytes possible for an integer is 8. Therefore to encode the length of
+ * an integer using a nnint, we only need two bytes. [byte1: nnint length,
+ * byte2: integer length [0-8]]
+ */
+#define BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER 2
+
+/**
+ * @brief bejTupleL size of a bool.
+ *
+ * 1byte for the nnint length and 1 byte for the value.
+ */
+#define BEJ_TUPLE_L_SIZE_FOR_BEJ_BOOL 2
+
+/**
* @brief Check the name is an annotation type name.
*
* @param[in] name - property name.
@@ -156,6 +172,79 @@
return 0;
}
+static int bejUpdateIntMetaData(const struct BejDictionaries* dictionaries,
+ const uint8_t* parentDictionary,
+ struct RedfishPropertyLeafInt* node,
+ uint16_t nodeIndex, uint16_t dictStartingOffset)
+{
+ uint32_t sequenceNumber;
+ RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
+ dictionaries, parentDictionary, &node->leaf.nodeAttr, nodeIndex,
+ dictStartingOffset, &sequenceNumber, NULL, NULL));
+ node->leaf.metaData.sequenceNumber = sequenceNumber;
+
+ // Calculate the size for encoding this in a SFLV tuple.
+ // S: Size needed for encoding sequence number.
+ node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
+ // F: Size of the format byte is 1.
+ node->leaf.metaData.sflSize += 1;
+ // L: Length needed for the value.
+ node->leaf.metaData.sflSize += BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER;
+ // V: Bytes used for the value.
+ node->leaf.metaData.vSize = bejIntLengthOfValue(node->value);
+ return 0;
+}
+
+static int bejUpdateStringMetaData(const struct BejDictionaries* dictionaries,
+ const uint8_t* parentDictionary,
+ struct RedfishPropertyLeafString* node,
+ uint16_t nodeIndex,
+ uint16_t dictStartingOffset)
+{
+ uint32_t sequenceNumber;
+ RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
+ dictionaries, parentDictionary, &(node->leaf.nodeAttr), nodeIndex,
+ dictStartingOffset, &sequenceNumber, NULL, NULL));
+ node->leaf.metaData.sequenceNumber = sequenceNumber;
+
+ // Calculate the size for encoding this in a SFLV tuple.
+ // S: Size needed for encoding sequence number.
+ node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
+ // F: Size of the format byte is 1.
+ node->leaf.metaData.sflSize += 1;
+ // L: Length needed for the string including the NULL character. Length is
+ // in nnint format.
+ size_t strLenWithNull = strlen(node->value) + 1;
+ node->leaf.metaData.sflSize += bejNnintEncodingSizeOfUInt(strLenWithNull);
+ // V: Bytes used for the value.
+ node->leaf.metaData.vSize = strLenWithNull;
+ return 0;
+}
+
+static int bejUpdateBoolMetaData(const struct BejDictionaries* dictionaries,
+ const uint8_t* parentDictionary,
+ struct RedfishPropertyLeafBool* node,
+ uint16_t nodeIndex,
+ uint16_t dictStartingOffset)
+{
+ uint32_t sequenceNumber;
+ RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
+ dictionaries, parentDictionary, &node->leaf.nodeAttr, nodeIndex,
+ dictStartingOffset, &sequenceNumber, NULL, NULL));
+ node->leaf.metaData.sequenceNumber = sequenceNumber;
+
+ // Calculate the size for encoding this in a SFLV tuple.
+ // S: Size needed for encoding sequence number.
+ node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
+ // F: Size of the format byte is 1.
+ node->leaf.metaData.sflSize += 1;
+ // L: Length needed for the value.
+ node->leaf.metaData.sflSize += BEJ_TUPLE_L_SIZE_FOR_BEJ_BOOL;
+ // V: Bytes used for the value; 0x00 or 0xFF.
+ node->leaf.metaData.vSize = 1;
+ return 0;
+}
+
/**
* @brief Update metadata of leaf nodes.
*
@@ -173,15 +262,25 @@
void* childPtr, uint16_t childIndex,
uint16_t dictStartingOffset)
{
- // TODO: Implement this
- (void)dictionaries;
- (void)parentDictionary;
- (void)childIndex;
- (void)dictStartingOffset;
-
struct RedfishPropertyLeaf* chNode = childPtr;
+
switch (chNode->nodeAttr.format.principalDataType)
{
+ case bejInteger:
+ RETURN_IF_IERROR(
+ bejUpdateIntMetaData(dictionaries, parentDictionary, childPtr,
+ childIndex, dictStartingOffset));
+ break;
+ case bejString:
+ RETURN_IF_IERROR(bejUpdateStringMetaData(
+ dictionaries, parentDictionary, childPtr, childIndex,
+ dictStartingOffset));
+ break;
+ case bejBoolean:
+ RETURN_IF_IERROR(
+ bejUpdateBoolMetaData(dictionaries, parentDictionary, childPtr,
+ childIndex, dictStartingOffset));
+ break;
default:
fprintf(stderr, "Child type %u not supported\n",
chNode->nodeAttr.format.principalDataType);