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 Update metadata of leaf nodes. 12 * 13 * @param dictionaries - dictionaries needed for encoding. 14 * @param parentDictionary - dictionary used by this node's parent. 15 * @param childPtr - a pointer to the leaf node. 16 * @param childIndex - if this node is an array element, this is the array 17 * index. 18 * @param dictStartingOffset - starting dictionary child offset value of this 19 * node's parent. 20 * @return 0 if successful. 21 */ 22 static int bejUpdateLeafNodeMetaData(const struct BejDictionaries* dictionaries, 23 const uint8_t* parentDictionary, 24 void* childPtr, uint16_t childIndex, 25 uint16_t dictStartingOffset) 26 { 27 // TODO: Implement this 28 (void)dictionaries; 29 (void)parentDictionary; 30 (void)childIndex; 31 (void)dictStartingOffset; 32 33 struct RedfishPropertyLeaf* chNode = childPtr; 34 switch (chNode->nodeAttr.format.principalDataType) 35 { 36 default: 37 fprintf(stderr, "Child type %u not supported\n", 38 chNode->nodeAttr.format.principalDataType); 39 return -1; 40 } 41 return 0; 42 } 43 44 /** 45 * @brief Update metadata of a parent node. 46 * 47 * @param dictionaries - dictionaries needed for encoding. 48 * @param parentDictionary - dictionary used by this node's parent. 49 * @param dictStartingOffset - starting dictionary child offset value of this 50 * node's parent. 51 * @param node - a pointer to the parent node. 52 * @param nodeIndex - If this node is an array element, this is the array index. 53 * @return 0 if successful. 54 */ 55 static int bejUpdateParentMetaData(const struct BejDictionaries* dictionaries, 56 const uint8_t* parentDictionary, 57 uint16_t dictStartingOffset, 58 struct RedfishPropertyParent* node, 59 uint16_t nodeIndex) 60 { 61 // TODO: Implement this 62 (void)dictionaries; 63 (void)parentDictionary; 64 (void)dictStartingOffset; 65 (void)node; 66 (void)nodeIndex; 67 68 return -1; 69 } 70 71 /** 72 * @brief Update metadata of child nodes. 73 * 74 * If a child node contains its own child nodes, it will be added to the stack 75 * and function will return. 76 * 77 * @param dictionaries - dictionaries needed for encoding. 78 * @param parent - parent node. 79 * @param stack - stack holding parent nodes. 80 * @return 0 if successful. 81 */ 82 static int bejProcessChildNodes(const struct BejDictionaries* dictionaries, 83 struct RedfishPropertyParent* parent, 84 struct BejPointerStackCallback* stack) 85 { 86 // Get the next child of the parent. 87 void* childPtr = parent->metaData.nextChild; 88 89 // Process all the children belongs to the parent. 90 while (childPtr != NULL) 91 { 92 // If we find a child with its own child nodes, add it to the stack and 93 // return. 94 if (bejTreeIsParentType(childPtr)) 95 { 96 RETURN_IF_IERROR(bejUpdateParentMetaData( 97 dictionaries, parent->metaData.dictionary, 98 parent->metaData.childrenDictPropOffset, childPtr, 99 parent->metaData.nextChildIndex)); 100 101 RETURN_IF_IERROR(stack->stackPush(childPtr, stack->stackContext)); 102 bejParentGoToNextChild(parent, childPtr); 103 return 0; 104 } 105 106 RETURN_IF_IERROR( 107 bejUpdateLeafNodeMetaData(dictionaries, parent->metaData.dictionary, 108 childPtr, parent->metaData.nextChildIndex, 109 parent->metaData.childrenDictPropOffset)); 110 // Use the child value size to update the parent value size. 111 struct RedfishPropertyLeaf* leafChild = childPtr; 112 // V: Include the child size in parent's value size. 113 parent->metaData.vSize += 114 (leafChild->metaData.sflSize + leafChild->metaData.vSize); 115 116 // Get the next child belongs to the parent. 117 childPtr = bejParentGoToNextChild(parent, childPtr); 118 } 119 return 0; 120 } 121 122 int bejUpdateNodeMetadata(const struct BejDictionaries* dictionaries, 123 uint16_t majorSchemaStartingOffset, 124 struct RedfishPropertyParent* root, 125 struct BejPointerStackCallback* stack) 126 { 127 // Decide the starting property offset of the dictionary. 128 uint16_t dictOffset = bejDictGetPropertyHeadOffset(); 129 if (majorSchemaStartingOffset != BEJ_DICTIONARY_START_AT_HEAD) 130 { 131 dictOffset = majorSchemaStartingOffset; 132 } 133 134 // Initialize root node metadata. 135 RETURN_IF_IERROR( 136 bejUpdateParentMetaData(dictionaries, dictionaries->schemaDictionary, 137 dictOffset, root, /*childIndex=*/0)); 138 139 // Push the root to the stack. Because we are not done with the parent node 140 // yet. Need to figure out all bytes need to encode children of this parent, 141 // and save it in the parent metadata. 142 RETURN_IF_IERROR(stack->stackPush(root, stack->stackContext)); 143 144 while (!stack->stackEmpty(stack->stackContext)) 145 { 146 // Get the parent at the top of the stack. Stack is only popped if the 147 // parent stack entry has no pending children; That is 148 // parent->metaData.nextChild == NULL. 149 struct RedfishPropertyParent* parent = 150 stack->stackPeek(stack->stackContext); 151 152 // Calculate metadata of all the child nodes of the current parent node. 153 // If one of these child nodes has its own child nodes, that child node 154 // will be added to the stack and this function will return. 155 RETURN_IF_IERROR(bejProcessChildNodes(dictionaries, parent, stack)); 156 157 // If a new node hasn't been added to the stack, we know that this 158 // parent's child nodes have been processed. If not, do not pop the 159 // stack. 160 if (parent != stack->stackPeek(stack->stackContext)) 161 { 162 continue; 163 } 164 165 // If we are here; 166 // Then "parent" is the top element of the stack. 167 // All the children of "parent" has been processed. 168 169 // Remove the "parent" from the stack. 170 parent = stack->stackPop(stack->stackContext); 171 // L: Add the length needed to store the number of bytes used for the 172 // parent's value. 173 parent->metaData.sflSize += 174 bejNnintEncodingSizeOfUInt(parent->metaData.vSize); 175 176 // Since we now know the total size needs to encode the node pointed by 177 // "parent" variable, we should add that to the value size of this 178 // node's parent. Since we already popped this node from the stack, top 179 // of the stack element is this nodes's parent. "parentsParent" can be 180 // NULL if the node pointed by "parent" variable is the root. 181 struct RedfishPropertyParent* parentsParent = 182 stack->stackPeek(stack->stackContext); 183 if (parentsParent != NULL) 184 { 185 // V: Include the total size to encode the current parent in its 186 // parent's value size. 187 parentsParent->metaData.vSize += 188 (parent->metaData.sflSize + parent->metaData.vSize); 189 } 190 } 191 return 0; 192 } 193