xref: /openbmc/libbej/src/bej_dictionary.c (revision 6f3082ea)
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