1 #include "bej_encoder_metadata.h" 2 3 #include "bej_common.h" 4 #include "bej_dictionary.h" 5 6 #include <stdint.h> 7 #include <stdio.h> 8 #include <string.h> 9 10 /** 11 * @brief bejTupleL size of an integer. 12 * 13 * Maximum bytes possible for an integer is 8. Therefore to encode the length of 14 * an integer using a nnint, we only need two bytes. [byte1: nnint length, 15 * byte2: integer length [0-8]] 16 */ 17 #define BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER 2 18 19 /** 20 * @brief bejTupleL size of a bool. 21 * 22 * 1byte for the nnint length and 1 byte for the value. 23 */ 24 #define BEJ_TUPLE_L_SIZE_FOR_BEJ_BOOL 2 25 26 /** 27 * @brief Check the name is an annotation type name. 28 * 29 * @param[in] name - property name. 30 * @return true for annotation name, false otherwise. 31 */ 32 static bool bejIsAnnotation(const char* name) 33 { 34 if (name == NULL) 35 { 36 return false; 37 } 38 return name[0] == '@'; 39 } 40 41 /** 42 * @brief Get the dictionary for the provided node. 43 * 44 * @param[in] dictionaries - available dictionaries for encoding. 45 * @param[in] parentDictionary - dictionary used for the parent of this node. 46 * @param[in] nodeName - name of the interested node. Can be NULL if the node 47 * doesn't have a name. 48 * @return a pointer to the dictionary to be used. 49 */ 50 static const uint8_t* 51 bejGetRelatedDictionary(const struct BejDictionaries* dictionaries, 52 const uint8_t* parentDictionary, 53 const char* nodeName) 54 { 55 // If the node name is NULL, we have to use parent dictionary. 56 if (nodeName == NULL) 57 { 58 return parentDictionary; 59 } 60 61 // If the parent is using annotation dictionary, that means the parent is an 62 // annotation. Therefore the child (this node) should be an annotation too 63 // (Could this be false?). Therefore we should use the annotation dictionary 64 // for this node as well. 65 if (parentDictionary == dictionaries->annotationDictionary) 66 { 67 return dictionaries->annotationDictionary; 68 } 69 return bejIsAnnotation(nodeName) ? dictionaries->annotationDictionary 70 : dictionaries->schemaDictionary; 71 } 72 73 /** 74 * @brief Get dictionary data for the given node. 75 * 76 * @param[in] dictionaries - available dictionaries. 77 * @param[in] parentDictionary - the dictionary used by the provided node's 78 * parent. 79 * @param[in] node - node that caller is interested in. 80 * @param[in] nodeIndex - index of this node within its parent. 81 * @param[in] dictStartingOffset - starting dictionary child offset value of 82 * this node's parent. 83 * @param[out] sequenceNumber - sequence number of the node. bit0 specifies the 84 * dictionary schema type: [major|annotation]. 85 * @param[out] nodeDictionary - if not NULL, return a pointer to the dictionary 86 * used for the node. 87 * @param[out] childEntryOffset - if not NULL, return the dictionary starting 88 * offset used for this nodes children. If this node is not supposed to have 89 * children, caller should ignore this value. 90 * @return 0 if successful. 91 */ 92 static int bejFindSeqNumAndChildDictOffset( 93 const struct BejDictionaries* dictionaries, const uint8_t* parentDictionary, 94 struct RedfishPropertyNode* node, uint16_t nodeIndex, 95 uint16_t dictStartingOffset, uint32_t* sequenceNumber, 96 const uint8_t** nodeDictionary, uint16_t* childEntryOffset) 97 { 98 // If the node doesn't have a name, we can't use a dictionary. So we can use 99 // its parent's info. 100 if (node->name == NULL || node->name[0] == '\0') 101 { 102 if (nodeDictionary != NULL) 103 { 104 *nodeDictionary = parentDictionary; 105 } 106 107 if (childEntryOffset != NULL) 108 { 109 *childEntryOffset = dictStartingOffset; 110 } 111 112 // If the property doesn't have a name, it has to be an element of an 113 // array. In that case, sequence number is the array index. 114 *sequenceNumber = (uint32_t)nodeIndex << 1; 115 if (dictionaries->annotationDictionary == parentDictionary) 116 { 117 *sequenceNumber |= 1; 118 } 119 return 0; 120 } 121 122 // If we are here, the property has a name. 123 const uint8_t* dictionary = 124 bejGetRelatedDictionary(dictionaries, parentDictionary, node->name); 125 bool isAnnotation = dictionary == dictionaries->annotationDictionary; 126 // If this node's dictionary and its parent's dictionary is different, 127 // this node should start searching from the beginning of its 128 // dictionary. This should only happen for property annotations of form 129 // property@annotation_class.annotation_name. 130 if (dictionary != parentDictionary) 131 { 132 // Redundancy check. 133 if (!isAnnotation) 134 { 135 fprintf(stderr, 136 "Dictionary for property %s should be the annotation " 137 "dictionary. Might be a encoding failure. Maybe the " 138 "JSON tree is not created correctly.", 139 node->name); 140 return -1; 141 } 142 dictStartingOffset = bejDictGetFirstAnnotatedPropertyOffset(); 143 } 144 145 const struct BejDictionaryProperty* property; 146 int ret = bejDictGetPropertyByName(dictionary, dictStartingOffset, 147 node->name, &property, NULL); 148 if (ret != 0) 149 { 150 fprintf(stderr, 151 "Failed to find dictionary entry for name %s. Search started " 152 "at offset: %u. ret: %d\n", 153 node->name, dictStartingOffset, ret); 154 return ret; 155 } 156 157 if (nodeDictionary != NULL) 158 { 159 *nodeDictionary = dictionary; 160 } 161 162 if (childEntryOffset != NULL) 163 { 164 *childEntryOffset = property->childPointerOffset; 165 } 166 167 *sequenceNumber = (uint32_t)(property->sequenceNumber) << 1; 168 if (isAnnotation) 169 { 170 *sequenceNumber |= 1; 171 } 172 return 0; 173 } 174 175 static int bejUpdateIntMetaData(const struct BejDictionaries* dictionaries, 176 const uint8_t* parentDictionary, 177 struct RedfishPropertyLeafInt* node, 178 uint16_t nodeIndex, uint16_t dictStartingOffset) 179 { 180 uint32_t sequenceNumber; 181 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset( 182 dictionaries, parentDictionary, &node->leaf.nodeAttr, nodeIndex, 183 dictStartingOffset, &sequenceNumber, NULL, NULL)); 184 node->leaf.metaData.sequenceNumber = sequenceNumber; 185 186 // Calculate the size for encoding this in a SFLV tuple. 187 // S: Size needed for encoding sequence number. 188 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber); 189 // F: Size of the format byte is 1. 190 node->leaf.metaData.sflSize += 1; 191 // L: Length needed for the value. 192 node->leaf.metaData.sflSize += BEJ_TUPLE_L_SIZE_FOR_BEJ_INTEGER; 193 // V: Bytes used for the value. 194 node->leaf.metaData.vSize = bejIntLengthOfValue(node->value); 195 return 0; 196 } 197 198 static int bejUpdateStringMetaData(const struct BejDictionaries* dictionaries, 199 const uint8_t* parentDictionary, 200 struct RedfishPropertyLeafString* node, 201 uint16_t nodeIndex, 202 uint16_t dictStartingOffset) 203 { 204 uint32_t sequenceNumber; 205 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset( 206 dictionaries, parentDictionary, &(node->leaf.nodeAttr), nodeIndex, 207 dictStartingOffset, &sequenceNumber, NULL, NULL)); 208 node->leaf.metaData.sequenceNumber = sequenceNumber; 209 210 // Calculate the size for encoding this in a SFLV tuple. 211 // S: Size needed for encoding sequence number. 212 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber); 213 // F: Size of the format byte is 1. 214 node->leaf.metaData.sflSize += 1; 215 // L: Length needed for the string including the NULL character. Length is 216 // in nnint format. 217 size_t strLenWithNull = strlen(node->value) + 1; 218 node->leaf.metaData.sflSize += bejNnintEncodingSizeOfUInt(strLenWithNull); 219 // V: Bytes used for the value. 220 node->leaf.metaData.vSize = strLenWithNull; 221 return 0; 222 } 223 224 static int bejUpdateEnumMetaData(const struct BejDictionaries* dictionaries, 225 const uint8_t* parentDictionary, 226 struct RedfishPropertyLeafEnum* node, 227 uint16_t nodeIndex, 228 uint16_t dictStartingOffset) 229 { 230 const uint8_t* nodeDictionary; 231 uint16_t childEntryOffset; 232 uint32_t sequenceNumber; 233 // If the enum property doesn't have a name, this will simply return the 234 // nodeIndex encoded as the sequence number. If not, this will return the 235 // sequence number in the dictionary and the starting dictionary index for 236 // the enum values. 237 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset( 238 dictionaries, parentDictionary, &(node->leaf.nodeAttr), nodeIndex, 239 dictStartingOffset, &sequenceNumber, &nodeDictionary, 240 &childEntryOffset)); 241 // Update the sequence number of the property. 242 node->leaf.metaData.sequenceNumber = sequenceNumber; 243 244 // Get the sequence number for the Enum value. 245 if (node->leaf.nodeAttr.name != NULL && node->leaf.nodeAttr.name[0] != '\0') 246 { 247 dictStartingOffset = childEntryOffset; 248 } 249 const struct BejDictionaryProperty* enumValueProperty; 250 int ret = bejDictGetPropertyByName(nodeDictionary, dictStartingOffset, 251 node->value, &enumValueProperty, NULL); 252 if (ret != 0) 253 { 254 fprintf( 255 stderr, 256 "Failed to find dictionary entry for enum value %s. Search started " 257 "at offset: %u. ret: %d\n", 258 node->value, dictStartingOffset, ret); 259 return ret; 260 } 261 node->enumValueSeq = enumValueProperty->sequenceNumber; 262 263 // Calculate the size for encoding this in a SFLV tuple. 264 // S: Size needed for encoding sequence number. 265 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber); 266 // F: Size of the format byte is 1. 267 node->leaf.metaData.sflSize += 1; 268 // V: Bytes used for the value. 269 node->leaf.metaData.vSize = 270 bejNnintEncodingSizeOfUInt(enumValueProperty->sequenceNumber); 271 // L: Length needed for the value nnint. 272 node->leaf.metaData.sflSize += 273 bejNnintEncodingSizeOfUInt(node->leaf.metaData.vSize); 274 return 0; 275 } 276 277 static int bejUpdateBoolMetaData(const struct BejDictionaries* dictionaries, 278 const uint8_t* parentDictionary, 279 struct RedfishPropertyLeafBool* node, 280 uint16_t nodeIndex, 281 uint16_t dictStartingOffset) 282 { 283 uint32_t sequenceNumber; 284 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset( 285 dictionaries, parentDictionary, &node->leaf.nodeAttr, nodeIndex, 286 dictStartingOffset, &sequenceNumber, NULL, NULL)); 287 node->leaf.metaData.sequenceNumber = sequenceNumber; 288 289 // Calculate the size for encoding this in a SFLV tuple. 290 // S: Size needed for encoding sequence number. 291 node->leaf.metaData.sflSize = bejNnintEncodingSizeOfUInt(sequenceNumber); 292 // F: Size of the format byte is 1. 293 node->leaf.metaData.sflSize += 1; 294 // L: Length needed for the value. 295 node->leaf.metaData.sflSize += BEJ_TUPLE_L_SIZE_FOR_BEJ_BOOL; 296 // V: Bytes used for the value; 0x00 or 0xFF. 297 node->leaf.metaData.vSize = 1; 298 return 0; 299 } 300 301 /** 302 * @brief Update metadata of leaf nodes. 303 * 304 * @param dictionaries - dictionaries needed for encoding. 305 * @param parentDictionary - dictionary used by this node's parent. 306 * @param childPtr - a pointer to the leaf node. 307 * @param childIndex - if this node is an array element, this is the array 308 * index. 309 * @param dictStartingOffset - starting dictionary child offset value of this 310 * node's parent. 311 * @return 0 if successful. 312 */ 313 static int bejUpdateLeafNodeMetaData(const struct BejDictionaries* dictionaries, 314 const uint8_t* parentDictionary, 315 void* childPtr, uint16_t childIndex, 316 uint16_t dictStartingOffset) 317 { 318 struct RedfishPropertyLeaf* chNode = childPtr; 319 320 switch (chNode->nodeAttr.format.principalDataType) 321 { 322 case bejInteger: 323 RETURN_IF_IERROR( 324 bejUpdateIntMetaData(dictionaries, parentDictionary, childPtr, 325 childIndex, dictStartingOffset)); 326 break; 327 case bejString: 328 RETURN_IF_IERROR(bejUpdateStringMetaData( 329 dictionaries, parentDictionary, childPtr, childIndex, 330 dictStartingOffset)); 331 break; 332 case bejEnum: 333 RETURN_IF_IERROR( 334 bejUpdateEnumMetaData(dictionaries, parentDictionary, childPtr, 335 childIndex, dictStartingOffset)); 336 break; 337 case bejBoolean: 338 RETURN_IF_IERROR( 339 bejUpdateBoolMetaData(dictionaries, parentDictionary, childPtr, 340 childIndex, dictStartingOffset)); 341 break; 342 default: 343 fprintf(stderr, "Child type %u not supported\n", 344 chNode->nodeAttr.format.principalDataType); 345 return -1; 346 } 347 return 0; 348 } 349 350 /** 351 * @brief Update metadata of a parent node. 352 * 353 * @param dictionaries - dictionaries needed for encoding. 354 * @param parentDictionary - dictionary used by this node's parent. 355 * @param dictStartingOffset - starting dictionary child offset value of this 356 * node's parent. 357 * @param node - a pointer to the parent node. 358 * @param nodeIndex - If this node is an array element, this is the array index. 359 * @return 0 if successful. 360 */ 361 static int bejUpdateParentMetaData(const struct BejDictionaries* dictionaries, 362 const uint8_t* parentDictionary, 363 uint16_t dictStartingOffset, 364 struct RedfishPropertyParent* node, 365 uint16_t nodeIndex) 366 { 367 const uint8_t* nodeDictionary; 368 uint16_t childEntryOffset; 369 uint32_t sequenceNumber; 370 371 // Get the dictionary related data from the node. 372 RETURN_IF_IERROR(bejFindSeqNumAndChildDictOffset( 373 dictionaries, parentDictionary, &node->nodeAttr, nodeIndex, 374 dictStartingOffset, &sequenceNumber, &nodeDictionary, 375 &childEntryOffset)); 376 377 node->metaData.sequenceNumber = sequenceNumber; 378 node->metaData.childrenDictPropOffset = childEntryOffset; 379 node->metaData.nextChild = node->firstChild; 380 node->metaData.nextChildIndex = 0; 381 node->metaData.dictionary = nodeDictionary; 382 node->metaData.vSize = 0; 383 384 // S: Size needed for encoding sequence number. 385 node->metaData.sflSize = 386 bejNnintEncodingSizeOfUInt(node->metaData.sequenceNumber); 387 // F: Size of the format byte is 1. 388 node->metaData.sflSize += 1; 389 // V: Only for bejArray and bejSet types, value size should include the 390 // children count. We need to add the size needs to encode all the children 391 // later. 392 if (node->nodeAttr.format.principalDataType != bejPropertyAnnotation) 393 { 394 node->metaData.vSize = bejNnintEncodingSizeOfUInt(node->nChildren); 395 } 396 return 0; 397 } 398 399 /** 400 * @brief Update metadata of child nodes. 401 * 402 * If a child node contains its own child nodes, it will be added to the stack 403 * and function will return. 404 * 405 * @param dictionaries - dictionaries needed for encoding. 406 * @param parent - parent node. 407 * @param stack - stack holding parent nodes. 408 * @return 0 if successful. 409 */ 410 static int bejProcessChildNodes(const struct BejDictionaries* dictionaries, 411 struct RedfishPropertyParent* parent, 412 struct BejPointerStackCallback* stack) 413 { 414 // Get the next child of the parent. 415 void* childPtr = parent->metaData.nextChild; 416 417 // Process all the children belongs to the parent. 418 while (childPtr != NULL) 419 { 420 // If we find a child with its own child nodes, add it to the stack and 421 // return. 422 if (bejTreeIsParentType(childPtr)) 423 { 424 RETURN_IF_IERROR(bejUpdateParentMetaData( 425 dictionaries, parent->metaData.dictionary, 426 parent->metaData.childrenDictPropOffset, childPtr, 427 parent->metaData.nextChildIndex)); 428 429 RETURN_IF_IERROR(stack->stackPush(childPtr, stack->stackContext)); 430 bejParentGoToNextChild(parent, childPtr); 431 return 0; 432 } 433 434 RETURN_IF_IERROR( 435 bejUpdateLeafNodeMetaData(dictionaries, parent->metaData.dictionary, 436 childPtr, parent->metaData.nextChildIndex, 437 parent->metaData.childrenDictPropOffset)); 438 // Use the child value size to update the parent value size. 439 struct RedfishPropertyLeaf* leafChild = childPtr; 440 // V: Include the child size in parent's value size. 441 parent->metaData.vSize += 442 (leafChild->metaData.sflSize + leafChild->metaData.vSize); 443 444 // Get the next child belongs to the parent. 445 childPtr = bejParentGoToNextChild(parent, childPtr); 446 } 447 return 0; 448 } 449 450 int bejUpdateNodeMetadata(const struct BejDictionaries* dictionaries, 451 uint16_t majorSchemaStartingOffset, 452 struct RedfishPropertyParent* root, 453 struct BejPointerStackCallback* stack) 454 { 455 // Decide the starting property offset of the dictionary. 456 uint16_t dictOffset = bejDictGetPropertyHeadOffset(); 457 if (majorSchemaStartingOffset != BEJ_DICTIONARY_START_AT_HEAD) 458 { 459 dictOffset = majorSchemaStartingOffset; 460 } 461 462 // Initialize root node metadata. 463 RETURN_IF_IERROR( 464 bejUpdateParentMetaData(dictionaries, dictionaries->schemaDictionary, 465 dictOffset, root, /*childIndex=*/0)); 466 467 // Push the root to the stack. Because we are not done with the parent node 468 // yet. Need to figure out all bytes need to encode children of this parent, 469 // and save it in the parent metadata. 470 RETURN_IF_IERROR(stack->stackPush(root, stack->stackContext)); 471 472 while (!stack->stackEmpty(stack->stackContext)) 473 { 474 // Get the parent at the top of the stack. Stack is only popped if the 475 // parent stack entry has no pending children; That is 476 // parent->metaData.nextChild == NULL. 477 struct RedfishPropertyParent* parent = 478 stack->stackPeek(stack->stackContext); 479 480 // Calculate metadata of all the child nodes of the current parent node. 481 // If one of these child nodes has its own child nodes, that child node 482 // will be added to the stack and this function will return. 483 RETURN_IF_IERROR(bejProcessChildNodes(dictionaries, parent, stack)); 484 485 // If a new node hasn't been added to the stack, we know that this 486 // parent's child nodes have been processed. If not, do not pop the 487 // stack. 488 if (parent != stack->stackPeek(stack->stackContext)) 489 { 490 continue; 491 } 492 493 // If we are here; 494 // Then "parent" is the top element of the stack. 495 // All the children of "parent" has been processed. 496 497 // Remove the "parent" from the stack. 498 parent = stack->stackPop(stack->stackContext); 499 // L: Add the length needed to store the number of bytes used for the 500 // parent's value. 501 parent->metaData.sflSize += 502 bejNnintEncodingSizeOfUInt(parent->metaData.vSize); 503 504 // Since we now know the total size needs to encode the node pointed by 505 // "parent" variable, we should add that to the value size of this 506 // node's parent. Since we already popped this node from the stack, top 507 // of the stack element is this nodes's parent. "parentsParent" can be 508 // NULL if the node pointed by "parent" variable is the root. 509 struct RedfishPropertyParent* parentsParent = 510 stack->stackPeek(stack->stackContext); 511 if (parentsParent != NULL) 512 { 513 // V: Include the total size to encode the current parent in its 514 // parent's value size. 515 parentsParent->metaData.vSize += 516 (parent->metaData.sflSize + parent->metaData.vSize); 517 } 518 } 519 return 0; 520 } 521