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 */ 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 */ 61 static 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 */ 103 static 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 186 static 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. 201 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE; 202 // 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 209 static 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. 225 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE; 226 // 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 235 static 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 316 static 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. 359 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE; 360 // 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 369 static 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. 385 node->leaf.metaData.sflSize += BEJ_TUPLE_F_SIZE; 386 // 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 393 static 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 417 /** 418 * @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 */ 429 static int bejUpdateLeafNodeMetaData(const struct BejDictionaries* dictionaries, 430 const uint8_t* parentDictionary, 431 void* childPtr, uint16_t childIndex, 432 uint16_t dictStartingOffset) 433 { 434 struct RedfishPropertyLeaf* chNode = childPtr; 435 436 switch (chNode->nodeAttr.format.principalDataType) 437 { 438 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; 448 case bejReal: 449 RETURN_IF_IERROR( 450 bejUpdateRealMetaData(dictionaries, parentDictionary, childPtr, 451 childIndex, dictStartingOffset)); 452 break; 453 case bejEnum: 454 RETURN_IF_IERROR( 455 bejUpdateEnumMetaData(dictionaries, parentDictionary, childPtr, 456 childIndex, dictStartingOffset)); 457 break; 458 case bejBoolean: 459 RETURN_IF_IERROR( 460 bejUpdateBoolMetaData(dictionaries, parentDictionary, childPtr, 461 childIndex, dictStartingOffset)); 462 break; 463 case bejNull: 464 RETURN_IF_IERROR( 465 bejUpdateNullMetaData(dictionaries, parentDictionary, childPtr, 466 childIndex, dictStartingOffset)); 467 break; 468 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 */ 487 static int bejUpdateParentMetaData(const struct BejDictionaries* dictionaries, 488 const uint8_t* parentDictionary, 489 uint16_t dictStartingOffset, 490 struct RedfishPropertyParent* node, 491 uint16_t nodeIndex) 492 { 493 const uint8_t* nodeDictionary; 494 uint16_t childEntryOffset; 495 uint32_t sequenceNumber; 496 497 // 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; 523 } 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 */ 536 static 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 576 int 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 } 647