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 */
bejGetPropertyEntryIndex(uint16_t propertyOffset)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 */
bejValidatePropertyOffset(const uint8_t * dictionary,uint16_t propertyOffset)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
bejDictGetPropertyHeadOffset()64 uint16_t bejDictGetPropertyHeadOffset()
65 {
66 // First property is present soon after the dictionary header.
67 return sizeof(struct BejDictionaryHeader);
68 }
69
bejDictGetFirstAnnotatedPropertyOffset()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
bejDictGetProperty(const uint8_t * dictionary,uint16_t startingPropertyOffset,uint16_t sequenceNumber,const struct BejDictionaryProperty ** property)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
bejDictGetPropertyName(const uint8_t * dictionary,uint16_t nameOffset,uint8_t nameLength)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
bejDictGetPropertyByName(const uint8_t * dictionary,uint16_t startingPropertyOffset,const char * propertyName,const struct BejDictionaryProperty ** property,uint16_t * propertyOffset)117 int bejDictGetPropertyByName(
118 const uint8_t* dictionary, uint16_t startingPropertyOffset,
119 const char* propertyName, const struct BejDictionaryProperty** property,
120 uint16_t* propertyOffset)
121 {
122 NULL_CHECK(property, "property in bejDictGetPropertyByName");
123
124 uint16_t curPropertyOffset = startingPropertyOffset;
125 const struct BejDictionaryHeader* header =
126 (const struct BejDictionaryHeader*)dictionary;
127
128 if (!bejValidatePropertyOffset(dictionary, curPropertyOffset))
129 {
130 return bejErrorInvalidPropertyOffset;
131 }
132 uint16_t propertyIndex = bejGetPropertyEntryIndex(curPropertyOffset);
133
134 for (uint16_t index = propertyIndex; index < header->entryCount; ++index)
135 {
136 const struct BejDictionaryProperty* p =
137 (const struct BejDictionaryProperty*)(dictionary +
138 curPropertyOffset);
139 if (strcmp(propertyName,
140 bejDictGetPropertyName(dictionary, p->nameOffset,
141 p->nameLength)) == 0)
142 {
143 *property = p;
144 // propertyOffset is an optional output.
145 if (propertyOffset != NULL)
146 {
147 *propertyOffset = curPropertyOffset;
148 }
149 return 0;
150 }
151 curPropertyOffset += sizeof(struct BejDictionaryProperty);
152 }
153 return bejErrorUnknownProperty;
154 }
155