xref: /openbmc/libbej/src/bej_decoder_json.cpp (revision b81dcec4)
1*b81dcec4Skasunath #include "bej_decoder_json.hpp"
2*b81dcec4Skasunath 
3*b81dcec4Skasunath namespace libbej
4*b81dcec4Skasunath {
5*b81dcec4Skasunath 
6*b81dcec4Skasunath /**
7*b81dcec4Skasunath  * @brief This structure is used to pass additional data to callback functions.
8*b81dcec4Skasunath  */
9*b81dcec4Skasunath struct BejJsonParam
10*b81dcec4Skasunath {
11*b81dcec4Skasunath     bool* isPrevAnnotated;
12*b81dcec4Skasunath     std::string* output;
13*b81dcec4Skasunath };
14*b81dcec4Skasunath 
15*b81dcec4Skasunath /**
16*b81dcec4Skasunath  * @brief Add a property name to output buffer.
17*b81dcec4Skasunath  *
18*b81dcec4Skasunath  * @param[in] params - a valid BejJsonParam struct.
19*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
20*b81dcec4Skasunath  */
addPropertyNameToOutput(struct BejJsonParam * params,const char * propertyName)21*b81dcec4Skasunath static void addPropertyNameToOutput(struct BejJsonParam* params,
22*b81dcec4Skasunath                                     const char* propertyName)
23*b81dcec4Skasunath {
24*b81dcec4Skasunath     if (propertyName[0] == '\0')
25*b81dcec4Skasunath     {
26*b81dcec4Skasunath         return;
27*b81dcec4Skasunath     }
28*b81dcec4Skasunath     if (!(*params->isPrevAnnotated))
29*b81dcec4Skasunath     {
30*b81dcec4Skasunath         params->output->push_back('\"');
31*b81dcec4Skasunath     }
32*b81dcec4Skasunath     params->output->append(propertyName);
33*b81dcec4Skasunath     params->output->append("\":");
34*b81dcec4Skasunath }
35*b81dcec4Skasunath 
36*b81dcec4Skasunath /**
37*b81dcec4Skasunath  * @brief Callback for bejSet start.
38*b81dcec4Skasunath  *
39*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
40*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
41*b81dcec4Skasunath  * @return 0 if successful.
42*b81dcec4Skasunath  */
callbackSetStart(const char * propertyName,void * dataPtr)43*b81dcec4Skasunath static int callbackSetStart(const char* propertyName, void* dataPtr)
44*b81dcec4Skasunath {
45*b81dcec4Skasunath     struct BejJsonParam* params =
46*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
47*b81dcec4Skasunath     addPropertyNameToOutput(params, propertyName);
48*b81dcec4Skasunath     params->output->push_back('{');
49*b81dcec4Skasunath     *params->isPrevAnnotated = false;
50*b81dcec4Skasunath     return 0;
51*b81dcec4Skasunath }
52*b81dcec4Skasunath 
53*b81dcec4Skasunath /**
54*b81dcec4Skasunath  * @brief Callback for bejSet end.
55*b81dcec4Skasunath  *
56*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
57*b81dcec4Skasunath  * @return 0 if successful.
58*b81dcec4Skasunath  */
callbackSetEnd(void * dataPtr)59*b81dcec4Skasunath static int callbackSetEnd(void* dataPtr)
60*b81dcec4Skasunath {
61*b81dcec4Skasunath     struct BejJsonParam* params =
62*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
63*b81dcec4Skasunath     params->output->push_back('}');
64*b81dcec4Skasunath     return 0;
65*b81dcec4Skasunath }
66*b81dcec4Skasunath 
67*b81dcec4Skasunath /**
68*b81dcec4Skasunath  * @brief Callback for bejArray start.
69*b81dcec4Skasunath  *
70*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
71*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
72*b81dcec4Skasunath  * @return 0 if successful.
73*b81dcec4Skasunath  */
callbackArrayStart(const char * propertyName,void * dataPtr)74*b81dcec4Skasunath static int callbackArrayStart(const char* propertyName, void* dataPtr)
75*b81dcec4Skasunath {
76*b81dcec4Skasunath     struct BejJsonParam* params =
77*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
78*b81dcec4Skasunath     addPropertyNameToOutput(params, propertyName);
79*b81dcec4Skasunath     params->output->push_back('[');
80*b81dcec4Skasunath     *params->isPrevAnnotated = false;
81*b81dcec4Skasunath     return 0;
82*b81dcec4Skasunath }
83*b81dcec4Skasunath 
84*b81dcec4Skasunath /**
85*b81dcec4Skasunath  * @brief Callback for bejArray end.
86*b81dcec4Skasunath  *
87*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
88*b81dcec4Skasunath  * @return 0 if successful.
89*b81dcec4Skasunath  */
callbackArrayEnd(void * dataPtr)90*b81dcec4Skasunath static int callbackArrayEnd(void* dataPtr)
91*b81dcec4Skasunath {
92*b81dcec4Skasunath     struct BejJsonParam* params =
93*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
94*b81dcec4Skasunath     params->output->push_back(']');
95*b81dcec4Skasunath     return 0;
96*b81dcec4Skasunath }
97*b81dcec4Skasunath 
98*b81dcec4Skasunath /**
99*b81dcec4Skasunath  * @brief Callback when an end of a property is detected.
100*b81dcec4Skasunath  *
101*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
102*b81dcec4Skasunath  * @return 0 if successful.
103*b81dcec4Skasunath  */
callbackPropertyEnd(void * dataPtr)104*b81dcec4Skasunath static int callbackPropertyEnd(void* dataPtr)
105*b81dcec4Skasunath {
106*b81dcec4Skasunath     struct BejJsonParam* params =
107*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
108*b81dcec4Skasunath     // Not a section ending. So add a comma.
109*b81dcec4Skasunath     params->output->push_back(',');
110*b81dcec4Skasunath     return 0;
111*b81dcec4Skasunath }
112*b81dcec4Skasunath 
113*b81dcec4Skasunath /**
114*b81dcec4Skasunath  * @brief Callback for bejNull type.
115*b81dcec4Skasunath  *
116*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
117*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
118*b81dcec4Skasunath  * @return 0 if successful.
119*b81dcec4Skasunath  */
callbackNull(const char * propertyName,void * dataPtr)120*b81dcec4Skasunath static int callbackNull(const char* propertyName, void* dataPtr)
121*b81dcec4Skasunath {
122*b81dcec4Skasunath     struct BejJsonParam* params =
123*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
124*b81dcec4Skasunath     addPropertyNameToOutput(params, propertyName);
125*b81dcec4Skasunath     params->output->append("null");
126*b81dcec4Skasunath     *params->isPrevAnnotated = false;
127*b81dcec4Skasunath     return 0;
128*b81dcec4Skasunath }
129*b81dcec4Skasunath 
130*b81dcec4Skasunath /**
131*b81dcec4Skasunath  * @brief Callback for bejInteger type.
132*b81dcec4Skasunath  *
133*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
134*b81dcec4Skasunath  * @param[in] value - integer value.
135*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
136*b81dcec4Skasunath  * @return 0 if successful.
137*b81dcec4Skasunath  */
callbackInteger(const char * propertyName,int64_t value,void * dataPtr)138*b81dcec4Skasunath static int callbackInteger(const char* propertyName, int64_t value,
139*b81dcec4Skasunath                            void* dataPtr)
140*b81dcec4Skasunath {
141*b81dcec4Skasunath     struct BejJsonParam* params =
142*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
143*b81dcec4Skasunath     addPropertyNameToOutput(params, propertyName);
144*b81dcec4Skasunath     params->output->append(std::to_string(value));
145*b81dcec4Skasunath     *params->isPrevAnnotated = false;
146*b81dcec4Skasunath     return 0;
147*b81dcec4Skasunath }
148*b81dcec4Skasunath 
149*b81dcec4Skasunath /**
150*b81dcec4Skasunath  * @brief Callback for bejEnum type.
151*b81dcec4Skasunath  *
152*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
153*b81dcec4Skasunath  * @param[in] value - a NULL terminated string.
154*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
155*b81dcec4Skasunath  * @return 0 if successful.
156*b81dcec4Skasunath  */
callbackEnum(const char * propertyName,const char * value,void * dataPtr)157*b81dcec4Skasunath static int callbackEnum(const char* propertyName, const char* value,
158*b81dcec4Skasunath                         void* dataPtr)
159*b81dcec4Skasunath {
160*b81dcec4Skasunath     struct BejJsonParam* params =
161*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
162*b81dcec4Skasunath     addPropertyNameToOutput(params, propertyName);
163*b81dcec4Skasunath     params->output->push_back('\"');
164*b81dcec4Skasunath     params->output->append(value);
165*b81dcec4Skasunath     params->output->push_back('\"');
166*b81dcec4Skasunath     *params->isPrevAnnotated = false;
167*b81dcec4Skasunath     return 0;
168*b81dcec4Skasunath }
169*b81dcec4Skasunath 
170*b81dcec4Skasunath /**
171*b81dcec4Skasunath  * @brief Callback for bejString type.
172*b81dcec4Skasunath  *
173*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
174*b81dcec4Skasunath  * @param[in] value - a NULL terminated string.
175*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
176*b81dcec4Skasunath  * @return 0 if successful.
177*b81dcec4Skasunath  */
callbackString(const char * propertyName,const char * value,void * dataPtr)178*b81dcec4Skasunath static int callbackString(const char* propertyName, const char* value,
179*b81dcec4Skasunath                           void* dataPtr)
180*b81dcec4Skasunath {
181*b81dcec4Skasunath     struct BejJsonParam* params =
182*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
183*b81dcec4Skasunath     addPropertyNameToOutput(params, propertyName);
184*b81dcec4Skasunath     params->output->push_back('\"');
185*b81dcec4Skasunath     params->output->append(value);
186*b81dcec4Skasunath     params->output->push_back('\"');
187*b81dcec4Skasunath     *params->isPrevAnnotated = false;
188*b81dcec4Skasunath     return 0;
189*b81dcec4Skasunath }
190*b81dcec4Skasunath 
191*b81dcec4Skasunath /**
192*b81dcec4Skasunath  * @brief Callback for bejReal type.
193*b81dcec4Skasunath  *
194*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
195*b81dcec4Skasunath  * @param[in] value - pointing to a valid BejReal.
196*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
197*b81dcec4Skasunath  * @return 0 if successful.
198*b81dcec4Skasunath  */
callbackReal(const char * propertyName,const struct BejReal * value,void * dataPtr)199*b81dcec4Skasunath static int callbackReal(const char* propertyName, const struct BejReal* value,
200*b81dcec4Skasunath                         void* dataPtr)
201*b81dcec4Skasunath {
202*b81dcec4Skasunath     struct BejJsonParam* params =
203*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
204*b81dcec4Skasunath 
205*b81dcec4Skasunath     addPropertyNameToOutput(params, propertyName);
206*b81dcec4Skasunath     params->output->append(std::to_string(value->whole));
207*b81dcec4Skasunath     params->output->push_back('.');
208*b81dcec4Skasunath     params->output->insert(params->output->cend(), value->zeroCount, '0');
209*b81dcec4Skasunath     params->output->append(std::to_string(value->fract));
210*b81dcec4Skasunath     if (value->expLen != 0)
211*b81dcec4Skasunath     {
212*b81dcec4Skasunath         params->output->push_back('e');
213*b81dcec4Skasunath         params->output->append(std::to_string(value->exp));
214*b81dcec4Skasunath     }
215*b81dcec4Skasunath     *params->isPrevAnnotated = false;
216*b81dcec4Skasunath     return 0;
217*b81dcec4Skasunath }
218*b81dcec4Skasunath 
219*b81dcec4Skasunath /**
220*b81dcec4Skasunath  * @brief Callback for bejBoolean type.
221*b81dcec4Skasunath  *
222*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
223*b81dcec4Skasunath  * @param[in] value - boolean value.
224*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
225*b81dcec4Skasunath  * @return 0 if successful.
226*b81dcec4Skasunath  */
callbackBool(const char * propertyName,bool value,void * dataPtr)227*b81dcec4Skasunath static int callbackBool(const char* propertyName, bool value, void* dataPtr)
228*b81dcec4Skasunath {
229*b81dcec4Skasunath     struct BejJsonParam* params =
230*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
231*b81dcec4Skasunath     addPropertyNameToOutput(params, propertyName);
232*b81dcec4Skasunath     params->output->append(value ? "true" : "false");
233*b81dcec4Skasunath     *params->isPrevAnnotated = false;
234*b81dcec4Skasunath     return 0;
235*b81dcec4Skasunath }
236*b81dcec4Skasunath 
237*b81dcec4Skasunath /**
238*b81dcec4Skasunath  * @brief Callback for bejPropertyAnnotation type.
239*b81dcec4Skasunath  *
240*b81dcec4Skasunath  * @param[in] propertyName - a NULL terminated string.
241*b81dcec4Skasunath  * @param[in] dataPtr - pointing to a valid BejJsonParam struct.
242*b81dcec4Skasunath  * @return 0 if successful.
243*b81dcec4Skasunath  */
callbackAnnotation(const char * propertyName,void * dataPtr)244*b81dcec4Skasunath static int callbackAnnotation(const char* propertyName, void* dataPtr)
245*b81dcec4Skasunath {
246*b81dcec4Skasunath     struct BejJsonParam* params =
247*b81dcec4Skasunath         reinterpret_cast<struct BejJsonParam*>(dataPtr);
248*b81dcec4Skasunath     params->output->push_back('\"');
249*b81dcec4Skasunath     params->output->append(propertyName);
250*b81dcec4Skasunath 
251*b81dcec4Skasunath     // bejPropertyAnnotation type has the form "Status@Message.ExtendedInfo".
252*b81dcec4Skasunath     // First the decoder will see "Status" part of the annotated property. This
253*b81dcec4Skasunath     // will be in its own SFLV tuple. The remainder of the property name,
254*b81dcec4Skasunath     // @Message.ExtendedInfo will be contained in the next bej SFLV tuple.
255*b81dcec4Skasunath     // Therefore to add the inverted commas to the complete property name,
256*b81dcec4Skasunath     // Status@Message.ExtendedInfo, we need to know that the previous property
257*b81dcec4Skasunath     // we processed is a start to an annotation property. We can use
258*b81dcec4Skasunath     // isPrevAnnotated to pass this information.
259*b81dcec4Skasunath     // Here we are adding: "propertyName
260*b81dcec4Skasunath     // If isPrevAnnotated is true, next property should add: propertyNameNext"
261*b81dcec4Skasunath     *params->isPrevAnnotated = true;
262*b81dcec4Skasunath     return 0;
263*b81dcec4Skasunath }
264*b81dcec4Skasunath 
265*b81dcec4Skasunath /**
266*b81dcec4Skasunath  * @brief Callback for stackEmpty.
267*b81dcec4Skasunath  *
268*b81dcec4Skasunath  * @param[in] dataPtr - pointer to a valid std::vector<BejStackProperty>
269*b81dcec4Skasunath  * @return true if the stack is empty.
270*b81dcec4Skasunath  */
stackEmpty(void * dataPtr)271*b81dcec4Skasunath static bool stackEmpty(void* dataPtr)
272*b81dcec4Skasunath {
273*b81dcec4Skasunath     std::vector<BejStackProperty>* stack =
274*b81dcec4Skasunath         reinterpret_cast<std::vector<BejStackProperty>*>(dataPtr);
275*b81dcec4Skasunath     return stack->empty();
276*b81dcec4Skasunath }
277*b81dcec4Skasunath 
278*b81dcec4Skasunath /**
279*b81dcec4Skasunath  * @brief Callback for stackPeek.
280*b81dcec4Skasunath  *
281*b81dcec4Skasunath  * @param[in] dataPtr - pointer to a valid std::vector<BejStackProperty>
282*b81dcec4Skasunath  * @return a const reference to the stack top.
283*b81dcec4Skasunath  */
stackPeek(void * dataPtr)284*b81dcec4Skasunath static const struct BejStackProperty* stackPeek(void* dataPtr)
285*b81dcec4Skasunath {
286*b81dcec4Skasunath     std::vector<BejStackProperty>* stack =
287*b81dcec4Skasunath         reinterpret_cast<std::vector<BejStackProperty>*>(dataPtr);
288*b81dcec4Skasunath     if (stack->empty())
289*b81dcec4Skasunath     {
290*b81dcec4Skasunath         return nullptr;
291*b81dcec4Skasunath     }
292*b81dcec4Skasunath     return &(stack->back());
293*b81dcec4Skasunath }
294*b81dcec4Skasunath 
295*b81dcec4Skasunath /**
296*b81dcec4Skasunath  * @brief Callback for stackPop. Remove the top element from the stack.
297*b81dcec4Skasunath  *
298*b81dcec4Skasunath  * @param[in] dataPtr - pointer to a valid std::vector<BejStackProperty>
299*b81dcec4Skasunath  */
stackPop(void * dataPtr)300*b81dcec4Skasunath static void stackPop(void* dataPtr)
301*b81dcec4Skasunath {
302*b81dcec4Skasunath     std::vector<BejStackProperty>* stack =
303*b81dcec4Skasunath         reinterpret_cast<std::vector<BejStackProperty>*>(dataPtr);
304*b81dcec4Skasunath     if (stack->empty())
305*b81dcec4Skasunath     {
306*b81dcec4Skasunath         return;
307*b81dcec4Skasunath     }
308*b81dcec4Skasunath     stack->pop_back();
309*b81dcec4Skasunath }
310*b81dcec4Skasunath 
311*b81dcec4Skasunath /**
312*b81dcec4Skasunath  * @brief Callback for stackPush. Push a new element to the top of the stack.
313*b81dcec4Skasunath  *
314*b81dcec4Skasunath  * @param[in] property - property to push.
315*b81dcec4Skasunath  * @param[in] dataPtr - pointer to a valid std::vector<BejStackProperty>
316*b81dcec4Skasunath  * @return 0 if successful.
317*b81dcec4Skasunath  */
stackPush(const struct BejStackProperty * const property,void * dataPtr)318*b81dcec4Skasunath static int stackPush(const struct BejStackProperty* const property,
319*b81dcec4Skasunath                      void* dataPtr)
320*b81dcec4Skasunath {
321*b81dcec4Skasunath     std::vector<BejStackProperty>* stack =
322*b81dcec4Skasunath         reinterpret_cast<std::vector<BejStackProperty>*>(dataPtr);
323*b81dcec4Skasunath     stack->push_back(*property);
324*b81dcec4Skasunath     return 0;
325*b81dcec4Skasunath }
326*b81dcec4Skasunath 
decode(const BejDictionaries & dictionaries,const std::span<const uint8_t> encodedPldmBlock)327*b81dcec4Skasunath int BejDecoderJson::decode(const BejDictionaries& dictionaries,
328*b81dcec4Skasunath                            const std::span<const uint8_t> encodedPldmBlock)
329*b81dcec4Skasunath {
330*b81dcec4Skasunath     // Clear the previous output if any.
331*b81dcec4Skasunath     output.clear();
332*b81dcec4Skasunath 
333*b81dcec4Skasunath     // The dictionaries have to be traversed in a depth first manner. This is
334*b81dcec4Skasunath     // using a stack to implement it non-recursively. Going into a set or an
335*b81dcec4Skasunath     // array or a property annotation section means that we have to jump to the
336*b81dcec4Skasunath     // child dictionary offset start point but needs to retrieve the parent
337*b81dcec4Skasunath     // dictionary offset start once all the children are processed. This stack
338*b81dcec4Skasunath     // will hold the parent dictionary offsets and endings for each section.
339*b81dcec4Skasunath     stack.clear();
340*b81dcec4Skasunath 
341*b81dcec4Skasunath     struct BejStackCallback stackCallback = {
342*b81dcec4Skasunath         .stackEmpty = stackEmpty,
343*b81dcec4Skasunath         .stackPeek = stackPeek,
344*b81dcec4Skasunath         .stackPop = stackPop,
345*b81dcec4Skasunath         .stackPush = stackPush,
346*b81dcec4Skasunath     };
347*b81dcec4Skasunath 
348*b81dcec4Skasunath     struct BejDecodedCallback decodedCallback = {
349*b81dcec4Skasunath         .callbackSetStart = callbackSetStart,
350*b81dcec4Skasunath         .callbackSetEnd = callbackSetEnd,
351*b81dcec4Skasunath         .callbackArrayStart = callbackArrayStart,
352*b81dcec4Skasunath         .callbackArrayEnd = callbackArrayEnd,
353*b81dcec4Skasunath         .callbackPropertyEnd = callbackPropertyEnd,
354*b81dcec4Skasunath         .callbackNull = callbackNull,
355*b81dcec4Skasunath         .callbackInteger = callbackInteger,
356*b81dcec4Skasunath         .callbackEnum = callbackEnum,
357*b81dcec4Skasunath         .callbackString = callbackString,
358*b81dcec4Skasunath         .callbackReal = callbackReal,
359*b81dcec4Skasunath         .callbackBool = callbackBool,
360*b81dcec4Skasunath         .callbackAnnotation = callbackAnnotation,
361*b81dcec4Skasunath         .callbackReadonlyProperty = nullptr,
362*b81dcec4Skasunath     };
363*b81dcec4Skasunath 
364*b81dcec4Skasunath     isPrevAnnotated = false;
365*b81dcec4Skasunath     struct BejJsonParam callbackData = {
366*b81dcec4Skasunath         .isPrevAnnotated = &isPrevAnnotated,
367*b81dcec4Skasunath         .output = &output,
368*b81dcec4Skasunath     };
369*b81dcec4Skasunath 
370*b81dcec4Skasunath     return bejDecodePldmBlock(&dictionaries, encodedPldmBlock.data(),
371*b81dcec4Skasunath                               encodedPldmBlock.size_bytes(), &stackCallback,
372*b81dcec4Skasunath                               &decodedCallback, (void*)(&callbackData),
373*b81dcec4Skasunath                               (void*)(&stack));
374*b81dcec4Skasunath }
375*b81dcec4Skasunath 
getOutput()376*b81dcec4Skasunath std::string BejDecoderJson::getOutput()
377*b81dcec4Skasunath {
378*b81dcec4Skasunath     return output;
379*b81dcec4Skasunath }
380*b81dcec4Skasunath 
381*b81dcec4Skasunath } // namespace libbej
382