blob: 5e5ce2321a5139a44e61d22612a553c0c8baed35 [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
kasunathbde1bfa2023-08-18 00:38:36 -0700393static int bejUpdateNullMetaData(const struct BejDictionaries* dictionaries,
394 const uint8_t* parentDictionary,
395 struct RedfishPropertyLeafNull* node,
396 uint16_t nodeIndex,
397 uint16_t dictStartingOffset)
398{
399 uint32_t sequenceNumber;
400 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
401 dictionaries, parentDictionary, &node->leaf.nodeAttr, nodeIndex,
402 dictStartingOffset, &sequenceNumber, NULL, NULL));
403 node->leaf.metaData.sequenceNumber = sequenceNumber;
404
405 // Calculate the size for encoding this in a SFLV tuple.
406 // S: Size needed for encoding sequence number.
407 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber);
408 // F: Size of the format byte is 1.
409 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE;
410 // L: Length needed for the value. Value length for NULL type is 0. So we
411 // need to encode [0x01 0x00]
412 node->leaf.metaData.sflSize += BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER;
413 node->leaf.metaData.vSize = 0;
414 return 0;
415}
416
kasunathf68be952023-08-01 17:29:58 -0700417/**
kasunath99bd6c92023-07-30 18:19:00 -0700418 * @brief Update metadata of leaf nodes.
419 *
420 * @param dictionaries - dictionaries needed for encoding.
421 * @param parentDictionary - dictionary used by this node's parent.
422 * @param childPtr - a pointer to the leaf node.
423 * @param childIndex - if this node is an array element, this is the array
424 * index.
425 * @param dictStartingOffset - starting dictionary child offset value of this
426 * node's parent.
427 * @return 0 if successful.
428 */
429static int bejUpdateLeafNodeMetaData(const struct BejDictionaries* dictionaries,
430 const uint8_t* parentDictionary,
431 void* childPtr, uint16_t childIndex,
432 uint16_t dictStartingOffset)
433{
kasunath99bd6c92023-07-30 18:19:00 -0700434 struct RedfishPropertyLeaf* chNode = childPtr;
kasunath061fbc62023-08-01 18:09:08 -0700435
kasunath99bd6c92023-07-30 18:19:00 -0700436 switch (chNode->nodeAttr.format.principalDataType)
437 {
kasunath061fbc62023-08-01 18:09:08 -0700438 case bejInteger:
439 RETURN_IF_IERROR(
440 bejUpdateIntMetaData(dictionaries, parentDictionary, childPtr,
441 childIndex, dictStartingOffset));
442 break;
443 case bejString:
444 RETURN_IF_IERROR(bejUpdateStringMetaData(
445 dictionaries, parentDictionary, childPtr, childIndex,
446 dictStartingOffset));
447 break;
kasunathde02e7d2023-08-18 00:17:08 -0700448 case bejReal:
449 RETURN_IF_IERROR(
450 bejUpdateRealMetaData(dictionaries, parentDictionary, childPtr,
451 childIndex, dictStartingOffset));
452 break;
kasunathb250dd52023-08-01 18:13:55 -0700453 case bejEnum:
454 RETURN_IF_IERROR(
455 bejUpdateEnumMetaData(dictionaries, parentDictionary, childPtr,
456 childIndex, dictStartingOffset));
457 break;
kasunath061fbc62023-08-01 18:09:08 -0700458 case bejBoolean:
459 RETURN_IF_IERROR(
460 bejUpdateBoolMetaData(dictionaries, parentDictionary, childPtr,
461 childIndex, dictStartingOffset));
462 break;
kasunathbde1bfa2023-08-18 00:38:36 -0700463 case bejNull:
464 RETURN_IF_IERROR(
465 bejUpdateNullMetaData(dictionaries, parentDictionary, childPtr,
466 childIndex, dictStartingOffset));
467 break;
kasunath99bd6c92023-07-30 18:19:00 -0700468 default:
469 fprintf(stderr, "Child type %u not supported\n",
470 chNode->nodeAttr.format.principalDataType);
471 return -1;
472 }
473 return 0;
474}
475
476/**
477 * @brief Update metadata of a parent node.
478 *
479 * @param dictionaries - dictionaries needed for encoding.
480 * @param parentDictionary - dictionary used by this node's parent.
481 * @param dictStartingOffset - starting dictionary child offset value of this
482 * node's parent.
483 * @param node - a pointer to the parent node.
484 * @param nodeIndex - If this node is an array element, this is the array index.
485 * @return 0 if successful.
486 */
487static int bejUpdateParentMetaData(const struct BejDictionaries* dictionaries,
488 const uint8_t* parentDictionary,
489 uint16_t dictStartingOffset,
490 struct RedfishPropertyParent* node,
491 uint16_t nodeIndex)
492{
kasunathf68be952023-08-01 17:29:58 -0700493 const uint8_t* nodeDictionary;
494 uint16_t childEntryOffset;
495 uint32_t sequenceNumber;
kasunath99bd6c92023-07-30 18:19:00 -0700496
kasunathf68be952023-08-01 17:29:58 -0700497 // Get the dictionary related data from the node.
498 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset(
499 dictionaries, parentDictionary, &node->nodeAttr, nodeIndex,
500 dictStartingOffset, &sequenceNumber, &nodeDictionary,
501 &childEntryOffset));
502
503 node->metaData.sequenceNumber = sequenceNumber;
504 node->metaData.childrenDictPropOffset = childEntryOffset;
505 node->metaData.nextChild = node->firstChild;
506 node->metaData.nextChildIndex = 0;
507 node->metaData.dictionary = nodeDictionary;
508 node->metaData.vSize = 0;
509
510 // S: Size needed for encoding sequence number.
511 node->metaData.sflSize =
512 bejNnintEncodingSizeOfUInt(node->metaData.sequenceNumber);
513 // F: Size of the format byte is 1.
514 node->metaData.sflSize += 1;
515 // V: Only for bejArray and bejSet types, value size should include the
516 // children count. We need to add the size needs to encode all the children
517 // later.
518 if (node->nodeAttr.format.principalDataType != bejPropertyAnnotation)
519 {
520 node->metaData.vSize = bejNnintEncodingSizeOfUInt(node->nChildren);
521 }
522 return 0;
kasunath99bd6c92023-07-30 18:19:00 -0700523}
524
525/**
526 * @brief Update metadata of child nodes.
527 *
528 * If a child node contains its own child nodes, it will be added to the stack
529 * and function will return.
530 *
531 * @param dictionaries - dictionaries needed for encoding.
532 * @param parent - parent node.
533 * @param stack - stack holding parent nodes.
534 * @return 0 if successful.
535 */
536static int bejProcessChildNodes(const struct BejDictionaries* dictionaries,
537 struct RedfishPropertyParent* parent,
538 struct BejPointerStackCallback* stack)
539{
540 // Get the next child of the parent.
541 void* childPtr = parent->metaData.nextChild;
542
543 // Process all the children belongs to the parent.
544 while (childPtr != NULL)
545 {
546 // If we find a child with its own child nodes, add it to the stack and
547 // return.
548 if (bejTreeIsParentType(childPtr))
549 {
550 RETURN_IF_IERROR(bejUpdateParentMetaData(
551 dictionaries, parent->metaData.dictionary,
552 parent->metaData.childrenDictPropOffset, childPtr,
553 parent->metaData.nextChildIndex));
554
555 RETURN_IF_IERROR(stack->stackPush(childPtr, stack->stackContext));
556 bejParentGoToNextChild(parent, childPtr);
557 return 0;
558 }
559
560 RETURN_IF_IERROR(
561 bejUpdateLeafNodeMetaData(dictionaries, parent->metaData.dictionary,
562 childPtr, parent->metaData.nextChildIndex,
563 parent->metaData.childrenDictPropOffset));
564 // Use the child value size to update the parent value size.
565 struct RedfishPropertyLeaf* leafChild = childPtr;
566 // V: Include the child size in parent's value size.
567 parent->metaData.vSize +=
568 (leafChild->metaData.sflSize + leafChild->metaData.vSize);
569
570 // Get the next child belongs to the parent.
571 childPtr = bejParentGoToNextChild(parent, childPtr);
572 }
573 return 0;
574}
575
576int bejUpdateNodeMetadata(const struct BejDictionaries* dictionaries,
577 uint16_t majorSchemaStartingOffset,
578 struct RedfishPropertyParent* root,
579 struct BejPointerStackCallback* stack)
580{
581 // Decide the starting property offset of the dictionary.
582 uint16_t dictOffset = bejDictGetPropertyHeadOffset();
583 if (majorSchemaStartingOffset != BEJ_DICTIONARY_START_AT_HEAD)
584 {
585 dictOffset = majorSchemaStartingOffset;
586 }
587
588 // Initialize root node metadata.
589 RETURN_IF_IERROR(
590 bejUpdateParentMetaData(dictionaries, dictionaries->schemaDictionary,
591 dictOffset, root, /*childIndex=*/0));
592
593 // Push the root to the stack. Because we are not done with the parent node
594 // yet. Need to figure out all bytes need to encode children of this parent,
595 // and save it in the parent metadata.
596 RETURN_IF_IERROR(stack->stackPush(root, stack->stackContext));
597
598 while (!stack->stackEmpty(stack->stackContext))
599 {
600 // Get the parent at the top of the stack. Stack is only popped if the
601 // parent stack entry has no pending children; That is
602 // parent->metaData.nextChild == NULL.
603 struct RedfishPropertyParent* parent =
604 stack->stackPeek(stack->stackContext);
605
606 // Calculate metadata of all the child nodes of the current parent node.
607 // If one of these child nodes has its own child nodes, that child node
608 // will be added to the stack and this function will return.
609 RETURN_IF_IERROR(bejProcessChildNodes(dictionaries, parent, stack));
610
611 // If a new node hasn't been added to the stack, we know that this
612 // parent's child nodes have been processed. If not, do not pop the
613 // stack.
614 if (parent != stack->stackPeek(stack->stackContext))
615 {
616 continue;
617 }
618
619 // If we are here;
620 // Then "parent" is the top element of the stack.
621 // All the children of "parent" has been processed.
622
623 // Remove the "parent" from the stack.
624 parent = stack->stackPop(stack->stackContext);
625 // L: Add the length needed to store the number of bytes used for the
626 // parent's value.
627 parent->metaData.sflSize +=
628 bejNnintEncodingSizeOfUInt(parent->metaData.vSize);
629
630 // Since we now know the total size needs to encode the node pointed by
631 // "parent" variable, we should add that to the value size of this
632 // node's parent. Since we already popped this node from the stack, top
633 // of the stack element is this nodes's parent. "parentsParent" can be
634 // NULL if the node pointed by "parent" variable is the root.
635 struct RedfishPropertyParent* parentsParent =
636 stack->stackPeek(stack->stackContext);
637 if (parentsParent != NULL)
638 {
639 // V: Include the total size to encode the current parent in its
640 // parent's value size.
641 parentsParent->metaData.vSize +=
642 (parent->metaData.sflSize + parent->metaData.vSize);
643 }
644 }
645 return 0;
646}