1 #include "bej_dictionary.h" 2 3 #include <stdbool.h> 4 #include <stdio.h> 5 #include <string.h> 6 7 /** 8 * @brief Get the index for a property offset. First property will be at index 9 * 0. 10 * 11 * @param[in] propertyOffset - a valid property offset. 12 * @return index of the property. 13 */ 14 static uint16_t bejGetPropertyEntryIndex(uint16_t propertyOffset) 15 { 16 return (propertyOffset - bejDictGetPropertyHeadOffset()) / 17 sizeof(struct BejDictionaryProperty); 18 } 19 20 /** 21 * @brief Validate a property offset. 22 * 23 * @param[in] dictionary - pointer to the dictionary. 24 * @param[in] propertyOffset - offset needed to be validated. 25 * @return true if propertyOffset is a valid offset. 26 */ 27 static bool bejValidatePropertyOffset(const uint8_t* dictionary, 28 uint16_t propertyOffset) 29 { 30 // propertyOffset should be greater than or equal to first property offset. 31 if (propertyOffset < bejDictGetPropertyHeadOffset()) 32 { 33 fprintf( 34 stderr, 35 "Invalid property offset. Pointing to Dictionary header data\n"); 36 return false; 37 } 38 39 // propertyOffset should be a multiple of sizeof(BejDictionaryProperty) 40 // starting from first property within the dictionary. 41 if ((propertyOffset - bejDictGetPropertyHeadOffset()) % 42 sizeof(struct BejDictionaryProperty)) 43 { 44 fprintf(stderr, "Invalid property offset. Does not point to beginning " 45 "of property\n"); 46 return false; 47 } 48 49 const struct BejDictionaryHeader* header = 50 (const struct BejDictionaryHeader*)dictionary; 51 uint16_t propertyIndex = bejGetPropertyEntryIndex(propertyOffset); 52 if (propertyIndex >= header->entryCount) 53 { 54 fprintf(stderr, 55 "Invalid property offset %u. It falls outside of dictionary " 56 "properties\n", 57 propertyOffset); 58 return false; 59 } 60 61 return true; 62 } 63 64 uint16_t bejDictGetPropertyHeadOffset() 65 { 66 // First property is present soon after the dictionary header. 67 return sizeof(struct BejDictionaryHeader); 68 } 69 70 uint16_t bejDictGetFirstAnnotatedPropertyOffset() 71 { 72 // The first property available is the "Annotations" set which is the parent 73 // for all properties. Next immediate property is the first property we 74 // need. 75 return sizeof(struct BejDictionaryHeader) + 76 sizeof(struct BejDictionaryProperty); 77 } 78 79 int bejDictGetProperty(const uint8_t* dictionary, 80 uint16_t startingPropertyOffset, uint16_t sequenceNumber, 81 const struct BejDictionaryProperty** property) 82 { 83 uint16_t propertyOffset = startingPropertyOffset; 84 const struct BejDictionaryHeader* header = 85 (const struct BejDictionaryHeader*)dictionary; 86 87 if (!bejValidatePropertyOffset(dictionary, propertyOffset)) 88 { 89 return bejErrorInvalidPropertyOffset; 90 } 91 uint16_t propertyIndex = bejGetPropertyEntryIndex(propertyOffset); 92 93 for (uint16_t index = propertyIndex; index < header->entryCount; ++index) 94 { 95 const struct BejDictionaryProperty* p = 96 (const struct BejDictionaryProperty*)(dictionary + propertyOffset); 97 if (p->sequenceNumber == sequenceNumber) 98 { 99 *property = p; 100 return 0; 101 } 102 propertyOffset += sizeof(struct BejDictionaryProperty); 103 } 104 return bejErrorUnknownProperty; 105 } 106 107 const char* bejDictGetPropertyName(const uint8_t* dictionary, 108 uint16_t nameOffset, uint8_t nameLength) 109 { 110 if (nameLength == 0) 111 { 112 return ""; 113 } 114 return (const char*)(dictionary + nameOffset); 115 } 116 117 int bejDictGetPropertyByName(const uint8_t* dictionary, 118 uint16_t startingPropertyOffset, 119 const char* propertyName, 120 const struct BejDictionaryProperty** property, 121 uint16_t* propertyOffset) 122 { 123 NULL_CHECK(property, "property in bejDictGetPropertyByName"); 124 125 uint16_t curPropertyOffset = startingPropertyOffset; 126 const struct BejDictionaryHeader* header = 127 (const struct BejDictionaryHeader*)dictionary; 128 129 if (!bejValidatePropertyOffset(dictionary, curPropertyOffset)) 130 { 131 return bejErrorInvalidPropertyOffset; 132 } 133 uint16_t propertyIndex = bejGetPropertyEntryIndex(curPropertyOffset); 134 135 for (uint16_t index = propertyIndex; index < header->entryCount; ++index) 136 { 137 const struct BejDictionaryProperty* p = 138 (const struct BejDictionaryProperty*)(dictionary + 139 curPropertyOffset); 140 if (strcmp(propertyName, 141 bejDictGetPropertyName(dictionary, p->nameOffset, 142 p->nameLength)) == 0) 143 { 144 *property = p; 145 // propertyOffset is an optional output. 146 if (propertyOffset != NULL) 147 { 148 *propertyOffset = curPropertyOffset; 149 } 150 return 0; 151 } 152 curPropertyOffset += sizeof(struct BejDictionaryProperty); 153 } 154 return bejErrorUnknownProperty; 155 } 156