blob: 098c5e7d7a4274235dbf1a9a060e4d7cd2d08acd [file] [log] [blame]
kasunath99bd6c92023-07-30 18:19:00 -07001#include "bej_encoder_metadata.h"
2
3#include "bej_common.h"
4#include "bej_dictionary.h"
5
kasunathde02e7d2023-08-18 00:17:08 -07006#include <math.h>
kasunath99bd6c92023-07-30 18:19:00 -07007#include <stdint.h>
8#include <stdio.h>
9#include <string.h>
10
11/**
kasunathde02e7d2023-08-18 00:17:08 -070012 * @brief Maximum digits supported in the fractional part of a real number.
13 */
14#define BEJ_REAL_PRECISION 16
15
16/**
kasunath061fbc62023-08-01 18:09:08 -070017 * @brief bejTupleL size of an integer.
18 *
19 * Maximum bytes possible for an integer is 8. Therefore to encode the length of
20 * an integer using a nnint, we only need two bytes. [byte1: nnint length,
21 * byte2: integer length [0-8]]
22 */
23#define BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER 2
24
25/**
26 * @brief bejTupleL size of a bool.
27 *
28 * 1byte for the nnint length and 1 byte for the value.
29 */
30#define BEJ_TUPLE_L_SIZE_FOR_BEJ_BOOL 2
31
32/**
kasunathde02e7d2023-08-18 00:17:08 -070033 * @brief bejTupleF size.
34 */
35#define BEJ_TUPLE_F_SIZE 1
36
37/**
kasunathf68be952023-08-01 17:29:58 -070038 * @brief Check the name is an annotation type name.
39 *
40 * @param[in] name - property name.
41 * @return true for annotation name, false otherwise.
42 */
43static bool bejIsAnnotation(const char* name)
44{
45 if (name == NULL)
46 {
47 return false;
48 }
49 return name[0] == '@';
50}
51
52/**
53 * @brief Get the dictionary for the provided node.
54 *
55 * @param[in] dictionaries - available dictionaries for encoding.
56 * @param[in] parentDictionary - dictionary used for the parent of this node.
57 * @param[in] nodeName - name of the interested node. Can be NULL if the node
58 * doesn't have a name.
59 * @return a pointer to the dictionary to be used.
60 */
61static const uint8_t*
62 bejGetRelatedDictionary(const struct BejDictionaries* dictionaries,
63 const uint8_t* parentDictionary,
64 const char* nodeName)
65{
66 // If the node name is NULL, we have to use parent dictionary.
67 if (nodeName == NULL)
68 {
69 return parentDictionary;
70 }
71
72 // If the parent is using annotation dictionary, that means the parent is an
73 // annotation. Therefore the child (this node) should be an annotation too
74 // (Could this be false?). Therefore we should use the annotation dictionary
75 // for this node as well.
76 if (parentDictionary == dictionaries->annotationDictionary)
77 {
78 return dictionaries->annotationDictionary;
79 }
80 return bejIsAnnotation(nodeName) ? dictionaries->annotationDictionary
81 : dictionaries->schemaDictionary;
82}
83
84/**
85 * @brief Get dictionary data for the given node.
86 *
87 * @param[in] dictionaries - available dictionaries.
88 * @param[in] parentDictionary - the dictionary used by the provided node's
89 * parent.
90 * @param[in] node - node that caller is interested in.
91 * @param[in] nodeIndex - index of this node within its parent.
92 * @param[in] dictStartingOffset - starting dictionary child offset value of
93 * this node's parent.
94 * @param[out] sequenceNumber - sequence number of the node. bit0 specifies the
95 * dictionary schema type: [major|annotation].
96 * @param[out] nodeDictionary - if not NULL, return a pointer to the dictionary
97 * used for the node.
98 * @param[out] childEntryOffset - if not NULL, return the dictionary starting
99 * offset used for this nodes children. If this node is not supposed to have
100 * children, caller should ignore this value.
101 * @return 0 if successful.
102 */
103static int bejFindSeqNumAndChildDictOffset(
104 const struct BejDictionaries* dictionaries, const uint8_t* parentDictionary,
105 struct RedfishPropertyNode* node, uint16_t nodeIndex,
106 uint16_t dictStartingOffset, uint32_t* sequenceNumber,
107 const uint8_t** nodeDictionary, uint16_t* childEntryOffset)
108{
109 // If the node doesn't have a name, we can't use a dictionary. So we can use
110 // its parent's info.
111 if (node->name == NULL || node->name[0] == '\0')
112 {
113 if (nodeDictionary != NULL)
114 {
115 *nodeDictionary = parentDictionary;
116 }
117
118 if (childEntryOffset != NULL)
119 {
120 *childEntryOffset = dictStartingOffset;
121 }
122
123 // If the property doesn't have a name, it has to be an element of an
124 // array. In that case, sequence number is the array index.
125 *sequenceNumber = (uint32_t)nodeIndex << 1;
126 if (dictionaries->annotationDictionary == parentDictionary)
127 {
128 *sequenceNumber |= 1;
129 }
130 return 0;
131 }
132
133 // If we are here, the property has a name.
134 const uint8_t* dictionary =
135 bejGetRelatedDictionary(dictionaries, parentDictionary, node->name);
136 bool isAnnotation = dictionary == dictionaries->annotationDictionary;
137 // If this node's dictionary and its parent's dictionary is different,
138 // this node should start searching from the beginning of its
139 // dictionary. This should only happen for property annotations of form
140 // property@annotation_class.annotation_name.
141 if (dictionary != parentDictionary)
142 {
143 // Redundancy check.
144 if (!isAnnotation)
145 {
146 fprintf(stderr,
147 "Dictionary for property %s should be the annotation "
148 "dictionary. Might be a encoding failure. Maybe the "
149 "JSON tree is not created correctly.",
150 node->name);
151 return -1;
152 }
153 dictStartingOffset = bejDictGetFirstAnnotatedPropertyOffset();
154 }
155
156 const struct BejDictionaryProperty* property;
157 int ret = bejDictGetPropertyByName(dictionary, dictStartingOffset,
158 node->name, &property, NULL);
159 if (ret != 0)
160 {
161 fprintf(stderr,
162 "Failed to find dictionary entry for name %s. Search started "
163 "at offset: %u. ret: %d\n",
164 node->name, dictStartingOffset, ret);
165 return ret;
166 }
167
168 if (nodeDictionary != NULL)
169 {
170 *nodeDictionary = dictionary;
171 }
172
173 if (childEntryOffset != NULL)
174 {
175 *childEntryOffset = property->childPointerOffset;
176 }
177
178 *sequenceNumber = (uint32_t)(property->sequenceNumber) << 1;
179 if (isAnnotation)
180 {
181 *sequenceNumber |= 1;
182 }
183 return 0;
184}
185
kasunath061fbc62023-08-01 18:09:08 -0700186static int bejUpdateIntMetaData(const struct BejDictionaries* dictionaries,
187 const uint8_t* parentDictionary,
188 struct RedfishPropertyLeafInt* node,
189 uint16_t nodeIndex, uint16_t dictStartingOffset)
190{
191 uint32_t sequenceNumber;
192 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
193 dictionaries, parentDictionary, &node->leaf.nodeAttr, nodeIndex,
194 dictStartingOffset, &sequenceNumber, NULL, NULL));
195 node->leaf.metaData.sequenceNumber = sequenceNumber;
196
197 // Calculate the size for encoding this in a SFLV tuple.
198 // S: Size needed for encoding sequence number.
199 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
200 // F: Size of the format byte is 1.
kasunathde02e7d2023-08-18 00:17:08 -0700201 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
kasunath061fbc62023-08-01 18:09:08 -0700202 // L: Length needed for the value.
203 node->leaf.metaData.sflSize += BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER;
204 // V: Bytes used for the value.
205 node->leaf.metaData.vSize = bejIntLengthOfValue(node->value);
206 return 0;
207}
208
209static int bejUpdateStringMetaData(const struct BejDictionaries* dictionaries,
210 const uint8_t* parentDictionary,
211 struct RedfishPropertyLeafString* node,
212 uint16_t nodeIndex,
213 uint16_t dictStartingOffset)
214{
215 uint32_t sequenceNumber;
216 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
217 dictionaries, parentDictionary, &(node->leaf.nodeAttr), nodeIndex,
218 dictStartingOffset, &sequenceNumber, NULL, NULL));
219 node->leaf.metaData.sequenceNumber = sequenceNumber;
220
221 // Calculate the size for encoding this in a SFLV tuple.
222 // S: Size needed for encoding sequence number.
223 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
224 // F: Size of the format byte is 1.
kasunathde02e7d2023-08-18 00:17:08 -0700225 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
kasunath061fbc62023-08-01 18:09:08 -0700226 // L: Length needed for the string including the NULL character. Length is
227 // in nnint format.
228 size_t strLenWithNull = strlen(node->value) + 1;
229 node->leaf.metaData.sflSize += bejNnintEncodingSizeOfUInt(strLenWithNull);
230 // V: Bytes used for the value.
231 node->leaf.metaData.vSize = strLenWithNull;
232 return 0;
233}
234
kasunathde02e7d2023-08-18 00:17:08 -0700235static int bejUpdateRealMetaData(const struct BejDictionaries* dictionaries,
236 const uint8_t* parentDictionary,
237 struct RedfishPropertyLeafReal* node,
238 uint16_t nodeIndex,
239 uint16_t dictStartingOffset)
240{
241 uint32_t sequenceNumber;
242 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
243 dictionaries, parentDictionary, &(node->leaf.nodeAttr), nodeIndex,
244 dictStartingOffset, &sequenceNumber, NULL, NULL));
245 node->leaf.metaData.sequenceNumber = sequenceNumber;
246
247 if (node->value > (double)INT64_MAX)
248 {
249 // TODO: We should use the exponent.
250 fprintf(
251 stderr,
252 "Need to add support to encode double value larger than INT64_MAX\n");
253 return -1;
254 }
255
256 // Calculate the size for encoding this in a SFLV tuple.
257 // S: Size needed for encoding sequence number.
258 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
259 // F: Size of the format byte is 1.
260 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
261 // We need to breakdown the real number to bejReal type to determine the
262 // length. We are not gonna add an exponent. It will only be the whole part
263 // and the fraction part. Get the whole part
264 double originalWhole;
265 double originalFract = modf(node->value, &originalWhole);
266
267 // Convert the fraction to a whole value for encoding.
268 // Create a new value by multiplying the original fraction by 10. Do this
269 // until the fraction of the new value is 0 or we reach the precision. Eg
270 // 0.00105: This fraction value has two leading zeros. We will keep
271 // multiplying this by 10 until the fraction of the result of that
272 // multiplication is 0.
273 double originalFactConvertedToWhole = fabs(originalFract);
274 double fract = originalFract;
275 double intPart;
276 uint32_t leadingZeros = 0;
277 uint32_t precision = 0;
278 while (fract != 0 && precision < BEJ_REAL_PRECISION)
279 {
280 originalFactConvertedToWhole = originalFactConvertedToWhole * 10;
281 fract = modf(originalFactConvertedToWhole, &intPart);
282 // If the integer portion is 0, that means we still have leading zeros.
283 if (intPart == 0)
284 {
285 ++leadingZeros;
286 }
287 ++precision;
288 }
289 node->bejReal.whole = (int64_t)originalWhole;
290 node->bejReal.zeroCount = leadingZeros;
291 node->bejReal.fract = (int64_t)originalFactConvertedToWhole;
292 // We are omitting exp. So the exp length should be 0.
293 node->bejReal.expLen = 0;
294 node->bejReal.exp = 0;
295
296 // Calculate the sizes needed for storing bejReal fields.
297 // nnint for the length of the "whole" value.
298 node->leaf.metaData.vSize = BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER;
299 // Length needed for the "whole" value.
300 node->leaf.metaData.vSize += bejIntLengthOfValue((int64_t)originalWhole);
301 // nnint for leading zero count.
302 node->leaf.metaData.vSize += bejNnintEncodingSizeOfUInt(leadingZeros);
303 // nnint for the factional part.
304 node->leaf.metaData.vSize +=
305 bejNnintEncodingSizeOfUInt((int64_t)originalFactConvertedToWhole);
306 // nnint for the exp length. We are omitting exp. So the exp length should
307 // be 0.
308 node->leaf.metaData.vSize += bejNnintEncodingSizeOfUInt(0);
309
310 // L: nnint for the size needed for encoding the bejReal value.
311 node->leaf.metaData.sflSize +=
312 bejNnintEncodingSizeOfUInt(node->leaf.metaData.vSize);
313 return 0;
314}
315
kasunathb250dd52023-08-01 18:13:55 -0700316static int bejUpdateEnumMetaData(const struct BejDictionaries* dictionaries,
317 const uint8_t* parentDictionary,
318 struct RedfishPropertyLeafEnum* node,
319 uint16_t nodeIndex,
320 uint16_t dictStartingOffset)
321{
322 const uint8_t* nodeDictionary;
323 uint16_t childEntryOffset;
324 uint32_t sequenceNumber;
325 // If the enum property doesn't have a name, this will simply return the
326 // nodeIndex encoded as the sequence number. If not, this will return the
327 // sequence number in the dictionary and the starting dictionary index for
328 // the enum values.
329 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
330 dictionaries, parentDictionary, &(node->leaf.nodeAttr), nodeIndex,
331 dictStartingOffset, &sequenceNumber, &nodeDictionary,
332 &childEntryOffset));
333 // Update the sequence number of the property.
334 node->leaf.metaData.sequenceNumber = sequenceNumber;
335
336 // Get the sequence number for the Enum value.
337 if (node->leaf.nodeAttr.name != NULL && node->leaf.nodeAttr.name[0] != '\0')
338 {
339 dictStartingOffset = childEntryOffset;
340 }
341 const struct BejDictionaryProperty* enumValueProperty;
342 int ret = bejDictGetPropertyByName(nodeDictionary, dictStartingOffset,
343 node->value, &enumValueProperty, NULL);
344 if (ret != 0)
345 {
346 fprintf(
347 stderr,
348 "Failed to find dictionary entry for enum value %s. Search started "
349 "at offset: %u. ret: %d\n",
350 node->value, dictStartingOffset, ret);
351 return ret;
352 }
353 node->enumValueSeq = enumValueProperty->sequenceNumber;
354
355 // Calculate the size for encoding this in a SFLV tuple.
356 // S: Size needed for encoding sequence number.
357 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
358 // F: Size of the format byte is 1.
kasunathde02e7d2023-08-18 00:17:08 -0700359 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
kasunathb250dd52023-08-01 18:13:55 -0700360 // V: Bytes used for the value.
361 node->leaf.metaData.vSize =
362 bejNnintEncodingSizeOfUInt(enumValueProperty->sequenceNumber);
363 // L: Length needed for the value nnint.
364 node->leaf.metaData.sflSize +=
365 bejNnintEncodingSizeOfUInt(node->leaf.metaData.vSize);
366 return 0;
367}
368
kasunath061fbc62023-08-01 18:09:08 -0700369static int bejUpdateBoolMetaData(const struct BejDictionaries* dictionaries,
370 const uint8_t* parentDictionary,
371 struct RedfishPropertyLeafBool* node,
372 uint16_t nodeIndex,
373 uint16_t dictStartingOffset)
374{
375 uint32_t sequenceNumber;
376 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
377 dictionaries, parentDictionary, &node->leaf.nodeAttr, nodeIndex,
378 dictStartingOffset, &sequenceNumber, NULL, NULL));
379 node->leaf.metaData.sequenceNumber = sequenceNumber;
380
381 // Calculate the size for encoding this in a SFLV tuple.
382 // S: Size needed for encoding sequence number.
383 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
384 // F: Size of the format byte is 1.
kasunathde02e7d2023-08-18 00:17:08 -0700385 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
kasunath061fbc62023-08-01 18:09:08 -0700386 // L: Length needed for the value.
387 node->leaf.metaData.sflSize += BEJ_TUPLE_L_SIZE_FOR_BEJ_BOOL;
388 // V: Bytes used for the value; 0x00 or 0xFF.
389 node->leaf.metaData.vSize = 1;
390 return 0;
391}
392
kasunathf68be952023-08-01 17:29:58 -0700393/**
kasunath99bd6c92023-07-30 18:19:00 -0700394 * @brief Update metadata of leaf nodes.
395 *
396 * @param dictionaries - dictionaries needed for encoding.
397 * @param parentDictionary - dictionary used by this node's parent.
398 * @param childPtr - a pointer to the leaf node.
399 * @param childIndex - if this node is an array element, this is the array
400 * index.
401 * @param dictStartingOffset - starting dictionary child offset value of this
402 * node's parent.
403 * @return 0 if successful.
404 */
405static int bejUpdateLeafNodeMetaData(const struct BejDictionaries* dictionaries,
406 const uint8_t* parentDictionary,
407 void* childPtr, uint16_t childIndex,
408 uint16_t dictStartingOffset)
409{
kasunath99bd6c92023-07-30 18:19:00 -0700410 struct RedfishPropertyLeaf* chNode = childPtr;
kasunath061fbc62023-08-01 18:09:08 -0700411
kasunath99bd6c92023-07-30 18:19:00 -0700412 switch (chNode->nodeAttr.format.principalDataType)
413 {
kasunath061fbc62023-08-01 18:09:08 -0700414 case bejInteger:
415 RETURN_IF_IERROR(
416 bejUpdateIntMetaData(dictionaries, parentDictionary, childPtr,
417 childIndex, dictStartingOffset));
418 break;
419 case bejString:
420 RETURN_IF_IERROR(bejUpdateStringMetaData(
421 dictionaries, parentDictionary, childPtr, childIndex,
422 dictStartingOffset));
423 break;
kasunathde02e7d2023-08-18 00:17:08 -0700424 case bejReal:
425 RETURN_IF_IERROR(
426 bejUpdateRealMetaData(dictionaries, parentDictionary, childPtr,
427 childIndex, dictStartingOffset));
428 break;
kasunathb250dd52023-08-01 18:13:55 -0700429 case bejEnum:
430 RETURN_IF_IERROR(
431 bejUpdateEnumMetaData(dictionaries, parentDictionary, childPtr,
432 childIndex, dictStartingOffset));
433 break;
kasunath061fbc62023-08-01 18:09:08 -0700434 case bejBoolean:
435 RETURN_IF_IERROR(
436 bejUpdateBoolMetaData(dictionaries, parentDictionary, childPtr,
437 childIndex, dictStartingOffset));
438 break;
kasunath99bd6c92023-07-30 18:19:00 -0700439 default:
440 fprintf(stderr, "Child type %u not supported\n",
441 chNode->nodeAttr.format.principalDataType);
442 return -1;
443 }
444 return 0;
445}
446
447/**
448 * @brief Update metadata of a parent node.
449 *
450 * @param dictionaries - dictionaries needed for encoding.
451 * @param parentDictionary - dictionary used by this node's parent.
452 * @param dictStartingOffset - starting dictionary child offset value of this
453 * node's parent.
454 * @param node - a pointer to the parent node.
455 * @param nodeIndex - If this node is an array element, this is the array index.
456 * @return 0 if successful.
457 */
458static int bejUpdateParentMetaData(const struct BejDictionaries* dictionaries,
459 const uint8_t* parentDictionary,
460 uint16_t dictStartingOffset,
461 struct RedfishPropertyParent* node,
462 uint16_t nodeIndex)
463{
kasunathf68be952023-08-01 17:29:58 -0700464 const uint8_t* nodeDictionary;
465 uint16_t childEntryOffset;
466 uint32_t sequenceNumber;
kasunath99bd6c92023-07-30 18:19:00 -0700467
kasunathf68be952023-08-01 17:29:58 -0700468 // Get the dictionary related data from the node.
469 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
470 dictionaries, parentDictionary, &node->nodeAttr, nodeIndex,
471 dictStartingOffset, &sequenceNumber, &nodeDictionary,
472 &childEntryOffset));
473
474 node->metaData.sequenceNumber = sequenceNumber;
475 node->metaData.childrenDictPropOffset = childEntryOffset;
476 node->metaData.nextChild = node->firstChild;
477 node->metaData.nextChildIndex = 0;
478 node->metaData.dictionary = nodeDictionary;
479 node->metaData.vSize = 0;
480
481 // S: Size needed for encoding sequence number.
482 node->metaData.sflSize =
483 bejNnintEncodingSizeOfUInt(node->metaData.sequenceNumber);
484 // F: Size of the format byte is 1.
485 node->metaData.sflSize += 1;
486 // V: Only for bejArray and bejSet types, value size should include the
487 // children count. We need to add the size needs to encode all the children
488 // later.
489 if (node->nodeAttr.format.principalDataType != bejPropertyAnnotation)
490 {
491 node->metaData.vSize = bejNnintEncodingSizeOfUInt(node->nChildren);
492 }
493 return 0;
kasunath99bd6c92023-07-30 18:19:00 -0700494}
495
496/**
497 * @brief Update metadata of child nodes.
498 *
499 * If a child node contains its own child nodes, it will be added to the stack
500 * and function will return.
501 *
502 * @param dictionaries - dictionaries needed for encoding.
503 * @param parent - parent node.
504 * @param stack - stack holding parent nodes.
505 * @return 0 if successful.
506 */
507static int bejProcessChildNodes(const struct BejDictionaries* dictionaries,
508 struct RedfishPropertyParent* parent,
509 struct BejPointerStackCallback* stack)
510{
511 // Get the next child of the parent.
512 void* childPtr = parent->metaData.nextChild;
513
514 // Process all the children belongs to the parent.
515 while (childPtr != NULL)
516 {
517 // If we find a child with its own child nodes, add it to the stack and
518 // return.
519 if (bejTreeIsParentType(childPtr))
520 {
521 RETURN_IF_IERROR(bejUpdateParentMetaData(
522 dictionaries, parent->metaData.dictionary,
523 parent->metaData.childrenDictPropOffset, childPtr,
524 parent->metaData.nextChildIndex));
525
526 RETURN_IF_IERROR(stack->stackPush(childPtr, stack->stackContext));
527 bejParentGoToNextChild(parent, childPtr);
528 return 0;
529 }
530
531 RETURN_IF_IERROR(
532 bejUpdateLeafNodeMetaData(dictionaries, parent->metaData.dictionary,
533 childPtr, parent->metaData.nextChildIndex,
534 parent->metaData.childrenDictPropOffset));
535 // Use the child value size to update the parent value size.
536 struct RedfishPropertyLeaf* leafChild = childPtr;
537 // V: Include the child size in parent's value size.
538 parent->metaData.vSize +=
539 (leafChild->metaData.sflSize + leafChild->metaData.vSize);
540
541 // Get the next child belongs to the parent.
542 childPtr = bejParentGoToNextChild(parent, childPtr);
543 }
544 return 0;
545}
546
547int bejUpdateNodeMetadata(const struct BejDictionaries* dictionaries,
548 uint16_t majorSchemaStartingOffset,
549 struct RedfishPropertyParent* root,
550 struct BejPointerStackCallback* stack)
551{
552 // Decide the starting property offset of the dictionary.
553 uint16_t dictOffset = bejDictGetPropertyHeadOffset();
554 if (majorSchemaStartingOffset != BEJ_DICTIONARY_START_AT_HEAD)
555 {
556 dictOffset = majorSchemaStartingOffset;
557 }
558
559 // Initialize root node metadata.
560 RETURN_IF_IERROR(
561 bejUpdateParentMetaData(dictionaries, dictionaries->schemaDictionary,
562 dictOffset, root, /*childIndex=*/0));
563
564 // Push the root to the stack. Because we are not done with the parent node
565 // yet. Need to figure out all bytes need to encode children of this parent,
566 // and save it in the parent metadata.
567 RETURN_IF_IERROR(stack->stackPush(root, stack->stackContext));
568
569 while (!stack->stackEmpty(stack->stackContext))
570 {
571 // Get the parent at the top of the stack. Stack is only popped if the
572 // parent stack entry has no pending children; That is
573 // parent->metaData.nextChild == NULL.
574 struct RedfishPropertyParent* parent =
575 stack->stackPeek(stack->stackContext);
576
577 // Calculate metadata of all the child nodes of the current parent node.
578 // If one of these child nodes has its own child nodes, that child node
579 // will be added to the stack and this function will return.
580 RETURN_IF_IERROR(bejProcessChildNodes(dictionaries, parent, stack));
581
582 // If a new node hasn't been added to the stack, we know that this
583 // parent's child nodes have been processed. If not, do not pop the
584 // stack.
585 if (parent != stack->stackPeek(stack->stackContext))
586 {
587 continue;
588 }
589
590 // If we are here;
591 // Then "parent" is the top element of the stack.
592 // All the children of "parent" has been processed.
593
594 // Remove the "parent" from the stack.
595 parent = stack->stackPop(stack->stackContext);
596 // L: Add the length needed to store the number of bytes used for the
597 // parent's value.
598 parent->metaData.sflSize +=
599 bejNnintEncodingSizeOfUInt(parent->metaData.vSize);
600
601 // Since we now know the total size needs to encode the node pointed by
602 // "parent" variable, we should add that to the value size of this
603 // node's parent. Since we already popped this node from the stack, top
604 // of the stack element is this nodes's parent. "parentsParent" can be
605 // NULL if the node pointed by "parent" variable is the root.
606 struct RedfishPropertyParent* parentsParent =
607 stack->stackPeek(stack->stackContext);
608 if (parentsParent != NULL)
609 {
610 // V: Include the total size to encode the current parent in its
611 // parent's value size.
612 parentsParent->metaData.vSize +=
613 (parent->metaData.sflSize + parent->metaData.vSize);
614 }
615 }
616 return 0;
617}