xref: /openbmc/libbej/src/bej_encoder_metadata.c (revision 99bd6c90)
1 #include "bej_encoder_metadata.h"
2 
3 #include "bej_common.h"
4 #include "bej_dictionary.h"
5 
6 #include <stdint.h>
7 #include <stdio.h>
8 #include <string.h>
9 
10 /**
11  * @brief Update metadata of leaf nodes.
12  *
13  * @param dictionaries - dictionaries needed for encoding.
14  * @param parentDictionary - dictionary used by this node's parent.
15  * @param childPtr - a pointer to the leaf node.
16  * @param childIndex - if this node is an array element, this is the array
17  * index.
18  * @param dictStartingOffset - starting dictionary child offset value of this
19  * node's parent.
20  * @return 0 if successful.
21  */
22 static int bejUpdateLeafNodeMetaData(const struct BejDictionaries* dictionaries,
23                                      const uint8_t* parentDictionary,
24                                      void* childPtr, uint16_t childIndex,
25                                      uint16_t dictStartingOffset)
26 {
27     // TODO: Implement this
28     (void)dictionaries;
29     (void)parentDictionary;
30     (void)childIndex;
31     (void)dictStartingOffset;
32 
33     struct RedfishPropertyLeaf* chNode = childPtr;
34     switch (chNode->nodeAttr.format.principalDataType)
35     {
36         default:
37             fprintf(stderr, "Child type %u not supported\n",
38                     chNode->nodeAttr.format.principalDataType);
39             return -1;
40     }
41     return 0;
42 }
43 
44 /**
45  * @brief Update metadata of a parent node.
46  *
47  * @param dictionaries - dictionaries needed for encoding.
48  * @param parentDictionary - dictionary used by this node's parent.
49  * @param dictStartingOffset - starting dictionary child offset value of this
50  * node's parent.
51  * @param node - a pointer to the parent node.
52  * @param nodeIndex - If this node is an array element, this is the array index.
53  * @return 0 if successful.
54  */
55 static int bejUpdateParentMetaData(const struct BejDictionaries* dictionaries,
56                                    const uint8_t* parentDictionary,
57                                    uint16_t dictStartingOffset,
58                                    struct RedfishPropertyParent* node,
59                                    uint16_t nodeIndex)
60 {
61     // TODO: Implement this
62     (void)dictionaries;
63     (void)parentDictionary;
64     (void)dictStartingOffset;
65     (void)node;
66     (void)nodeIndex;
67 
68     return -1;
69 }
70 
71 /**
72  * @brief Update metadata of child nodes.
73  *
74  * If a child node contains its own child nodes, it will be added to the stack
75  * and function will return.
76  *
77  * @param dictionaries - dictionaries needed for encoding.
78  * @param parent - parent node.
79  * @param stack - stack holding parent nodes.
80  * @return 0 if successful.
81  */
82 static int bejProcessChildNodes(const struct BejDictionaries* dictionaries,
83                                 struct RedfishPropertyParent* parent,
84                                 struct BejPointerStackCallback* stack)
85 {
86     // Get the next child of the parent.
87     void* childPtr = parent->metaData.nextChild;
88 
89     // Process all the children belongs to the parent.
90     while (childPtr != NULL)
91     {
92         // If we find a child with its own child nodes, add it to the stack and
93         // return.
94         if (bejTreeIsParentType(childPtr))
95         {
96             RETURN_IF_IERROR(bejUpdateParentMetaData(
97                 dictionaries, parent->metaData.dictionary,
98                 parent->metaData.childrenDictPropOffset, childPtr,
99                 parent->metaData.nextChildIndex));
100 
101             RETURN_IF_IERROR(stack->stackPush(childPtr, stack->stackContext));
102             bejParentGoToNextChild(parent, childPtr);
103             return 0;
104         }
105 
106         RETURN_IF_IERROR(
107             bejUpdateLeafNodeMetaData(dictionaries, parent->metaData.dictionary,
108                                       childPtr, parent->metaData.nextChildIndex,
109                                       parent->metaData.childrenDictPropOffset));
110         // Use the child value size to update the parent value size.
111         struct RedfishPropertyLeaf* leafChild = childPtr;
112         // V: Include the child size in parent's value size.
113         parent->metaData.vSize +=
114             (leafChild->metaData.sflSize + leafChild->metaData.vSize);
115 
116         // Get the next child belongs to the parent.
117         childPtr = bejParentGoToNextChild(parent, childPtr);
118     }
119     return 0;
120 }
121 
122 int bejUpdateNodeMetadata(const struct BejDictionaries* dictionaries,
123                           uint16_t majorSchemaStartingOffset,
124                           struct RedfishPropertyParent* root,
125                           struct BejPointerStackCallback* stack)
126 {
127     // Decide the starting property offset of the dictionary.
128     uint16_t dictOffset = bejDictGetPropertyHeadOffset();
129     if (majorSchemaStartingOffset != BEJ_DICTIONARY_START_AT_HEAD)
130     {
131         dictOffset = majorSchemaStartingOffset;
132     }
133 
134     // Initialize root node metadata.
135     RETURN_IF_IERROR(
136         bejUpdateParentMetaData(dictionaries, dictionaries->schemaDictionary,
137                                 dictOffset, root, /*childIndex=*/0));
138 
139     // Push the root to the stack. Because we are not done with the parent node
140     // yet. Need to figure out all bytes need to encode children of this parent,
141     // and save it in the parent metadata.
142     RETURN_IF_IERROR(stack->stackPush(root, stack->stackContext));
143 
144     while (!stack->stackEmpty(stack->stackContext))
145     {
146         // Get the parent at the top of the stack. Stack is only popped if the
147         // parent stack entry has no pending children; That is
148         // parent->metaData.nextChild == NULL.
149         struct RedfishPropertyParent* parent =
150             stack->stackPeek(stack->stackContext);
151 
152         // Calculate metadata of all the child nodes of the current parent node.
153         // If one of these child nodes has its own child nodes, that child node
154         // will be added to the stack and this function will return.
155         RETURN_IF_IERROR(bejProcessChildNodes(dictionaries, parent, stack));
156 
157         // If a new node hasn't been added to the stack, we know that this
158         // parent's child nodes have been processed. If not, do not pop the
159         // stack.
160         if (parent != stack->stackPeek(stack->stackContext))
161         {
162             continue;
163         }
164 
165         // If we are here;
166         // Then "parent" is the top element of the stack.
167         // All the children of "parent" has been processed.
168 
169         // Remove the "parent" from the stack.
170         parent = stack->stackPop(stack->stackContext);
171         // L: Add the length needed to store the number of bytes used for the
172         // parent's value.
173         parent->metaData.sflSize +=
174             bejNnintEncodingSizeOfUInt(parent->metaData.vSize);
175 
176         // Since we now know the total size needs to encode the node pointed by
177         // "parent" variable, we should add that to the value size of this
178         // node's parent. Since we already popped this node from the stack, top
179         // of the stack element is this nodes's parent. "parentsParent" can be
180         // NULL if the node pointed by "parent" variable is the root.
181         struct RedfishPropertyParent* parentsParent =
182             stack->stackPeek(stack->stackContext);
183         if (parentsParent != NULL)
184         {
185             // V: Include the total size to encode the current parent in its
186             // parent's value size.
187             parentsParent->metaData.vSize +=
188                 (parent->metaData.sflSize + parent->metaData.vSize);
189         }
190     }
191     return 0;
192 }
193