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