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/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;
}
/**