Initialize a parent node metadata
This adds the support needed to initialize a parent node metadata
properties.
Signed-off-by: Kasun Athukorala <kasunath@google.com>
Change-Id: Ibb90665064904cc7fe1bde6dd5590545592f7d41
diff --git a/include/libbej/bej_dictionary.h b/include/libbej/bej_dictionary.h
index ad6bee1..ddfaa81 100644
--- a/include/libbej/bej_dictionary.h
+++ b/include/libbej/bej_dictionary.h
@@ -96,6 +96,26 @@
const char* bejDictGetPropertyName(const uint8_t* dictionary,
uint16_t nameOffset, uint8_t nameLength);
+ /**
+ * @brief Get the property related to the given property name.
+ *
+ * @param[in] dictionary - dictionary containing the property.
+ * @param[in] startingPropertyOffset - offset of the starting property for
+ * the search.
+ * @param[in] propertyName - name of the searched property.
+ * @param[out] property - if the search is successful, this will point to a
+ * valid property.
+ * @param[out] propertyOffset - if the search is successful, this will point
+ * to the offset of the property within the dictionary. Can provide a NULL
+ * pointer if this is not needed.
+ * @return 0 if successful.
+ */
+ int bejDictGetPropertyByName(const uint8_t* dictionary,
+ uint16_t startingPropertyOffset,
+ const char* propertyName,
+ const struct BejDictionaryProperty** property,
+ uint16_t* propertyOffset);
+
#ifdef __cplusplus
}
#endif
diff --git a/src/bej_dictionary.c b/src/bej_dictionary.c
index a86720b..b4d99ae 100644
--- a/src/bej_dictionary.c
+++ b/src/bej_dictionary.c
@@ -2,6 +2,7 @@
#include <stdbool.h>
#include <stdio.h>
+#include <string.h>
/**
* @brief Get the index for a property offset. First property will be at index
@@ -19,10 +20,12 @@
/**
* @brief Validate a property offset.
*
+ * @param[in] dictionary - pointer to the dictionary.
* @param[in] propertyOffset - offset needed to be validated.
* @return true if propertyOffset is a valid offset.
*/
-static bool bejValidatePropertyOffset(uint16_t propertyOffset)
+static bool bejValidatePropertyOffset(const uint8_t* dictionary,
+ uint16_t propertyOffset)
{
// propertyOffset should be greater than or equal to first property offset.
if (propertyOffset < bejDictGetPropertyHeadOffset())
@@ -43,6 +46,18 @@
return false;
}
+ const struct BejDictionaryHeader* header =
+ (const struct BejDictionaryHeader*)dictionary;
+ uint16_t propertyIndex = bejGetPropertyEntryIndex(propertyOffset);
+ if (propertyIndex >= header->entryCount)
+ {
+ fprintf(stderr,
+ "Invalid property offset %u. It falls outside of dictionary "
+ "properties\n",
+ propertyOffset);
+ return false;
+ }
+
return true;
}
@@ -69,7 +84,7 @@
const struct BejDictionaryHeader* header =
(const struct BejDictionaryHeader*)dictionary;
- if (!bejValidatePropertyOffset(propertyOffset))
+ if (!bejValidatePropertyOffset(dictionary, propertyOffset))
{
return bejErrorInvalidPropertyOffset;
}
@@ -98,3 +113,43 @@
}
return (const char*)(dictionary + nameOffset);
}
+
+int bejDictGetPropertyByName(const uint8_t* dictionary,
+ uint16_t startingPropertyOffset,
+ const char* propertyName,
+ const struct BejDictionaryProperty** property,
+ uint16_t* propertyOffset)
+{
+ NULL_CHECK(property, "property in bejDictGetPropertyByName");
+
+ uint16_t curPropertyOffset = startingPropertyOffset;
+ const struct BejDictionaryHeader* header =
+ (const struct BejDictionaryHeader*)dictionary;
+
+ if (!bejValidatePropertyOffset(dictionary, curPropertyOffset))
+ {
+ return bejErrorInvalidPropertyOffset;
+ }
+ uint16_t propertyIndex = bejGetPropertyEntryIndex(curPropertyOffset);
+
+ for (uint16_t index = propertyIndex; index < header->entryCount; ++index)
+ {
+ const struct BejDictionaryProperty* p =
+ (const struct BejDictionaryProperty*)(dictionary +
+ curPropertyOffset);
+ if (strcmp(propertyName,
+ bejDictGetPropertyName(dictionary, p->nameOffset,
+ p->nameLength)) == 0)
+ {
+ *property = p;
+ // propertyOffset is an optional output.
+ if (propertyOffset != NULL)
+ {
+ *propertyOffset = curPropertyOffset;
+ }
+ return 0;
+ }
+ curPropertyOffset += sizeof(struct BejDictionaryProperty);
+ }
+ return bejErrorUnknownProperty;
+}
diff --git a/src/bej_encoder_metadata.c b/src/bej_encoder_metadata.c
index 16264c1..bb08874 100644
--- a/src/bej_encoder_metadata.c
+++ b/src/bej_encoder_metadata.c
@@ -8,6 +8,155 @@
#include <string.h>
/**
+ * @brief Check the name is an annotation type name.
+ *
+ * @param[in] name - property name.
+ * @return true for annotation name, false otherwise.
+ */
+static bool bejIsAnnotation(const char* name)
+{
+ if (name == NULL)
+ {
+ return false;
+ }
+ return name[0] == '@';
+}
+
+/**
+ * @brief Get the dictionary for the provided node.
+ *
+ * @param[in] dictionaries - available dictionaries for encoding.
+ * @param[in] parentDictionary - dictionary used for the parent of this node.
+ * @param[in] nodeName - name of the interested node. Can be NULL if the node
+ * doesn't have a name.
+ * @return a pointer to the dictionary to be used.
+ */
+static const uint8_t*
+ bejGetRelatedDictionary(const struct BejDictionaries* dictionaries,
+ const uint8_t* parentDictionary,
+ const char* nodeName)
+{
+ // If the node name is NULL, we have to use parent dictionary.
+ if (nodeName == NULL)
+ {
+ return parentDictionary;
+ }
+
+ // If the parent is using annotation dictionary, that means the parent is an
+ // annotation. Therefore the child (this node) should be an annotation too
+ // (Could this be false?). Therefore we should use the annotation dictionary
+ // for this node as well.
+ if (parentDictionary == dictionaries->annotationDictionary)
+ {
+ return dictionaries->annotationDictionary;
+ }
+ return bejIsAnnotation(nodeName) ? dictionaries->annotationDictionary
+ : dictionaries->schemaDictionary;
+}
+
+/**
+ * @brief Get dictionary data for the given node.
+ *
+ * @param[in] dictionaries - available dictionaries.
+ * @param[in] parentDictionary - the dictionary used by the provided node's
+ * parent.
+ * @param[in] node - node that caller is interested in.
+ * @param[in] nodeIndex - index of this node within its parent.
+ * @param[in] dictStartingOffset - starting dictionary child offset value of
+ * this node's parent.
+ * @param[out] sequenceNumber - sequence number of the node. bit0 specifies the
+ * dictionary schema type: [major|annotation].
+ * @param[out] nodeDictionary - if not NULL, return a pointer to the dictionary
+ * used for the node.
+ * @param[out] childEntryOffset - if not NULL, return the dictionary starting
+ * offset used for this nodes children. If this node is not supposed to have
+ * children, caller should ignore this value.
+ * @return 0 if successful.
+ */
+static int bejFindSeqNumAndChildDictOffset(
+ const struct BejDictionaries* dictionaries, const uint8_t* parentDictionary,
+ struct RedfishPropertyNode* node, uint16_t nodeIndex,
+ uint16_t dictStartingOffset, uint32_t* sequenceNumber,
+ const uint8_t** nodeDictionary, uint16_t* childEntryOffset)
+{
+ // If the node doesn't have a name, we can't use a dictionary. So we can use
+ // its parent's info.
+ if (node->name == NULL || node->name[0] == '\0')
+ {
+ if (nodeDictionary != NULL)
+ {
+ *nodeDictionary = parentDictionary;
+ }
+
+ if (childEntryOffset != NULL)
+ {
+ *childEntryOffset = dictStartingOffset;
+ }
+
+ // If the property doesn't have a name, it has to be an element of an
+ // array. In that case, sequence number is the array index.
+ *sequenceNumber = (uint32_t)nodeIndex << 1;
+ if (dictionaries->annotationDictionary == parentDictionary)
+ {
+ *sequenceNumber |= 1;
+ }
+ return 0;
+ }
+
+ // If we are here, the property has a name.
+ const uint8_t* dictionary =
+ bejGetRelatedDictionary(dictionaries, parentDictionary, node->name);
+ bool isAnnotation = dictionary == dictionaries->annotationDictionary;
+ // If this node's dictionary and its parent's dictionary is different,
+ // this node should start searching from the beginning of its
+ // dictionary. This should only happen for property annotations of form
+ // property@annotation_class.annotation_name.
+ if (dictionary != parentDictionary)
+ {
+ // Redundancy check.
+ if (!isAnnotation)
+ {
+ fprintf(stderr,
+ "Dictionary for property %s should be the annotation "
+ "dictionary. Might be a encoding failure. Maybe the "
+ "JSON tree is not created correctly.",
+ node->name);
+ return -1;
+ }
+ dictStartingOffset = bejDictGetFirstAnnotatedPropertyOffset();
+ }
+
+ const struct BejDictionaryProperty* property;
+ int ret = bejDictGetPropertyByName(dictionary, dictStartingOffset,
+ node->name, &property, NULL);
+ if (ret != 0)
+ {
+ fprintf(stderr,
+ "Failed to find dictionary entry for name %s. Search started "
+ "at offset: %u. ret: %d\n",
+ node->name, dictStartingOffset, ret);
+ return ret;
+ }
+
+ if (nodeDictionary != NULL)
+ {
+ *nodeDictionary = dictionary;
+ }
+
+ if (childEntryOffset != NULL)
+ {
+ *childEntryOffset = property->childPointerOffset;
+ }
+
+ *sequenceNumber = (uint32_t)(property->sequenceNumber) << 1;
+ if (isAnnotation)
+ {
+ *sequenceNumber |= 1;
+ }
+ return 0;
+}
+
+/**
* @brief Update metadata of leaf nodes.
*
* @param dictionaries - dictionaries needed for encoding.
@@ -58,14 +207,36 @@
struct RedfishPropertyParent* node,
uint16_t nodeIndex)
{
- // TODO: Implement this
- (void)dictionaries;
- (void)parentDictionary;
- (void)dictStartingOffset;
- (void)node;
- (void)nodeIndex;
+ const uint8_t* nodeDictionary;
+ uint16_t childEntryOffset;
+ uint32_t sequenceNumber;
- return -1;
+ // Get the dictionary related data from the node.
+ RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
+ dictionaries, parentDictionary, &node->nodeAttr, nodeIndex,
+ dictStartingOffset, &sequenceNumber, &nodeDictionary,
+ &childEntryOffset));
+
+ node->metaData.sequenceNumber = sequenceNumber;
+ node->metaData.childrenDictPropOffset = childEntryOffset;
+ node->metaData.nextChild = node->firstChild;
+ node->metaData.nextChildIndex = 0;
+ node->metaData.dictionary = nodeDictionary;
+ node->metaData.vSize = 0;
+
+ // S: Size needed for encoding sequence number.
+ node->metaData.sflSize =
+ bejNnintEncodingSizeOfUInt(node->metaData.sequenceNumber);
+ // F: Size of the format byte is 1.
+ node->metaData.sflSize += 1;
+ // V: Only for bejArray and bejSet types, value size should include the
+ // children count. We need to add the size needs to encode all the children
+ // later.
+ if (node->nodeAttr.format.principalDataType != bejPropertyAnnotation)
+ {
+ node->metaData.vSize = bejNnintEncodingSizeOfUInt(node->nChildren);
+ }
+ return 0;
}
/**