blob: e7dff3af55d0e8fb2d91252cbccef425e6e7eb2c [file] [log] [blame]
kasunathd073aa12022-05-12 16:08:49 -07001#include "bej_dictionary.h"
2
3#include <stdbool.h>
Kasun Athukorala8c4332a2025-07-15 06:17:01 +00004#include <stddef.h>
kasunathd073aa12022-05-12 16:08:49 -07005#include <stdio.h>
kasunathf68be952023-08-01 17:29:58 -07006#include <string.h>
kasunathd073aa12022-05-12 16:08:49 -07007
8/**
9 * @brief Get the index for a property offset. First property will be at index
10 * 0.
11 *
12 * @param[in] propertyOffset - a valid property offset.
13 * @return index of the property.
14 */
15static uint16_t bejGetPropertyEntryIndex(uint16_t propertyOffset)
16{
17 return (propertyOffset - bejDictGetPropertyHeadOffset()) /
18 sizeof(struct BejDictionaryProperty);
19}
20
21/**
22 * @brief Validate a property offset.
23 *
kasunathf68be952023-08-01 17:29:58 -070024 * @param[in] dictionary - pointer to the dictionary.
kasunathd073aa12022-05-12 16:08:49 -070025 * @param[in] propertyOffset - offset needed to be validated.
26 * @return true if propertyOffset is a valid offset.
27 */
kasunathf68be952023-08-01 17:29:58 -070028static bool bejValidatePropertyOffset(const uint8_t* dictionary,
29 uint16_t propertyOffset)
kasunathd073aa12022-05-12 16:08:49 -070030{
31 // propertyOffset should be greater than or equal to first property offset.
32 if (propertyOffset < bejDictGetPropertyHeadOffset())
33 {
34 fprintf(
35 stderr,
36 "Invalid property offset. Pointing to Dictionary header data\n");
37 return false;
38 }
39
40 // propertyOffset should be a multiple of sizeof(BejDictionaryProperty)
41 // starting from first property within the dictionary.
42 if ((propertyOffset - bejDictGetPropertyHeadOffset()) %
43 sizeof(struct BejDictionaryProperty))
44 {
45 fprintf(stderr, "Invalid property offset. Does not point to beginning "
46 "of property\n");
47 return false;
48 }
49
kasunathf68be952023-08-01 17:29:58 -070050 const struct BejDictionaryHeader* header =
51 (const struct BejDictionaryHeader*)dictionary;
52 uint16_t propertyIndex = bejGetPropertyEntryIndex(propertyOffset);
53 if (propertyIndex >= header->entryCount)
54 {
55 fprintf(stderr,
56 "Invalid property offset %u. It falls outside of dictionary "
57 "properties\n",
58 propertyOffset);
59 return false;
60 }
61
kasunathd073aa12022-05-12 16:08:49 -070062 return true;
63}
64
Kasun Athukorala8c4332a2025-07-15 06:17:01 +000065static bool bejValidatePropertyNameLength(
66 const uint8_t* dictionary, uint32_t dictionarySize, uint16_t nameOffset,
67 uint8_t nameLength)
68{
69 if (nameLength == 0)
70 {
71 return true;
72 }
73 // After the property names, the dictionary has at least the
74 // uint8 CopyrightLength field. So we compare with dictionarySize - 1.
75 // nameOffset is uint16_t and nameLength is uint8_t so it cannot overflow
76 // uint32_t dictionarySize here.
77 if (((uint32_t)nameOffset) + (uint32_t)(nameLength) > (dictionarySize - 1))
78 {
79 fprintf(stderr, "Property name length goes beyond dictionary size\n");
80 return false;
81 }
82
83 // nameLength includes the NULL terminating. So the actual string size
84 // should be nameLength - 1.
85 const char* name = (const char*)dictionary + nameOffset;
86 const void* nullTerminator = memchr(name, '\0', nameLength);
87 if (nullTerminator == NULL ||
88 ((const char*)nullTerminator - name) != (ptrdiff_t)(nameLength - 1))
89 {
90 fprintf(stderr, "Property name length doesn't match actual length\n");
91 return false;
92 }
93 return true;
94}
95
Jayanth Othayoth716c7412024-12-19 06:13:35 -060096uint16_t bejDictGetPropertyHeadOffset(void)
kasunathd073aa12022-05-12 16:08:49 -070097{
98 // First property is present soon after the dictionary header.
99 return sizeof(struct BejDictionaryHeader);
100}
101
Jayanth Othayoth716c7412024-12-19 06:13:35 -0600102uint16_t bejDictGetFirstAnnotatedPropertyOffset(void)
kasunathd073aa12022-05-12 16:08:49 -0700103{
104 // The first property available is the "Annotations" set which is the parent
105 // for all properties. Next immediate property is the first property we
106 // need.
107 return sizeof(struct BejDictionaryHeader) +
108 sizeof(struct BejDictionaryProperty);
109}
110
111int bejDictGetProperty(const uint8_t* dictionary,
112 uint16_t startingPropertyOffset, uint16_t sequenceNumber,
113 const struct BejDictionaryProperty** property)
114{
115 uint16_t propertyOffset = startingPropertyOffset;
116 const struct BejDictionaryHeader* header =
117 (const struct BejDictionaryHeader*)dictionary;
118
kasunathf68be952023-08-01 17:29:58 -0700119 if (!bejValidatePropertyOffset(dictionary, propertyOffset))
kasunathd073aa12022-05-12 16:08:49 -0700120 {
121 return bejErrorInvalidPropertyOffset;
122 }
123 uint16_t propertyIndex = bejGetPropertyEntryIndex(propertyOffset);
124
125 for (uint16_t index = propertyIndex; index < header->entryCount; ++index)
126 {
127 const struct BejDictionaryProperty* p =
128 (const struct BejDictionaryProperty*)(dictionary + propertyOffset);
129 if (p->sequenceNumber == sequenceNumber)
130 {
Kasun Athukorala8c4332a2025-07-15 06:17:01 +0000131 if (!bejValidatePropertyNameLength(dictionary,
132 header->dictionarySize,
133 p->nameOffset, p->nameLength))
134 {
135 return bejErrorInvalidSize;
136 }
137
kasunathd073aa12022-05-12 16:08:49 -0700138 *property = p;
139 return 0;
140 }
141 propertyOffset += sizeof(struct BejDictionaryProperty);
142 }
143 return bejErrorUnknownProperty;
144}
145
146const char* bejDictGetPropertyName(const uint8_t* dictionary,
147 uint16_t nameOffset, uint8_t nameLength)
148{
149 if (nameLength == 0)
150 {
151 return "";
152 }
153 return (const char*)(dictionary + nameOffset);
154}
kasunathf68be952023-08-01 17:29:58 -0700155
Patrick Williamsbe27f2e2024-08-16 15:22:35 -0400156int bejDictGetPropertyByName(
157 const uint8_t* dictionary, uint16_t startingPropertyOffset,
158 const char* propertyName, const struct BejDictionaryProperty** property,
159 uint16_t* propertyOffset)
kasunathf68be952023-08-01 17:29:58 -0700160{
161 NULL_CHECK(property, "property in bejDictGetPropertyByName");
162
163 uint16_t curPropertyOffset = startingPropertyOffset;
164 const struct BejDictionaryHeader* header =
165 (const struct BejDictionaryHeader*)dictionary;
166
167 if (!bejValidatePropertyOffset(dictionary, curPropertyOffset))
168 {
169 return bejErrorInvalidPropertyOffset;
170 }
171 uint16_t propertyIndex = bejGetPropertyEntryIndex(curPropertyOffset);
172
173 for (uint16_t index = propertyIndex; index < header->entryCount; ++index)
174 {
175 const struct BejDictionaryProperty* p =
176 (const struct BejDictionaryProperty*)(dictionary +
177 curPropertyOffset);
178 if (strcmp(propertyName,
179 bejDictGetPropertyName(dictionary, p->nameOffset,
180 p->nameLength)) == 0)
181 {
182 *property = p;
183 // propertyOffset is an optional output.
184 if (propertyOffset != NULL)
185 {
186 *propertyOffset = curPropertyOffset;
187 }
188 return 0;
189 }
190 curPropertyOffset += sizeof(struct BejDictionaryProperty);
191 }
192 return bejErrorUnknownProperty;
193}