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