164cb1973Skasunath #include "bej_decoder_core.h"
264cb1973Skasunath
364cb1973Skasunath #include "bej_dictionary.h"
464cb1973Skasunath #include "stdio.h"
564cb1973Skasunath
664cb1973Skasunath #include <inttypes.h>
764cb1973Skasunath #include <stdbool.h>
864cb1973Skasunath #include <stdlib.h>
964cb1973Skasunath #include <string.h>
1064cb1973Skasunath
1164cb1973Skasunath // TODO: Support nested annotations for version 0xF1F1F000
1264cb1973Skasunath const uint32_t supportedBejVersions[] = {0xF1F0F000};
1364cb1973Skasunath
1464cb1973Skasunath /**
1564cb1973Skasunath * @brief Call a callback function. If the callback function is NULL, this will
1664cb1973Skasunath * not do anything. If the callback function returns a non-zero value, this will
1764cb1973Skasunath * cause the caller to return with the non-zero status.
1864cb1973Skasunath */
1964cb1973Skasunath #define RETURN_IF_CALLBACK_IERROR(function, ...) \
2064cb1973Skasunath do \
2164cb1973Skasunath { \
2264cb1973Skasunath if ((function) != NULL) \
2364cb1973Skasunath { \
2464cb1973Skasunath int __status = ((function)(__VA_ARGS__)); \
2564cb1973Skasunath if (__status != 0) \
2664cb1973Skasunath { \
2764cb1973Skasunath return __status; \
2864cb1973Skasunath } \
2964cb1973Skasunath } \
3064cb1973Skasunath } while (0)
3164cb1973Skasunath
3264cb1973Skasunath /**
3334a096dbSkasunath * @brief Get the integer value from BEJ byte stream.
3434a096dbSkasunath *
3534a096dbSkasunath * @param[in] bytes - valid pointer to a byte stream in little-endian format.
3634a096dbSkasunath * @param[in] numOfBytes - number of bytes belongs to the value. Maximum value
3734a096dbSkasunath * supported is 8 bytes.
3834a096dbSkasunath * @return signed 64bit representation of the value.
3934a096dbSkasunath */
bejGetIntegerValue(const uint8_t * bytes,uint8_t numOfBytes)4034a096dbSkasunath static int64_t bejGetIntegerValue(const uint8_t* bytes, uint8_t numOfBytes)
4134a096dbSkasunath {
4234a096dbSkasunath if (numOfBytes == 0)
4334a096dbSkasunath {
4434a096dbSkasunath return 0;
4534a096dbSkasunath }
460aa36d82Skasunath uint64_t value = bejGetUnsignedInteger(bytes, numOfBytes);
4734a096dbSkasunath uint8_t bitsInVal = numOfBytes * 8;
4834a096dbSkasunath // Since numOfBytes > 0, bitsInVal is non negative.
4934a096dbSkasunath uint64_t mask = (uint64_t)1 << (uint8_t)(bitsInVal - 1);
507daa5f8eSkasunath return (int64_t)((value ^ mask) - mask);
5134a096dbSkasunath }
5234a096dbSkasunath
5334a096dbSkasunath /**
5464cb1973Skasunath * @brief Get offsets of SFLV fields with respect to the enSegment start.
5564cb1973Skasunath *
5664cb1973Skasunath * @param[in] enSegment - a valid pointer to a start of a SFLV bejTuple.
5764cb1973Skasunath * @param[out] offsets - this will hold the local offsets.
5864cb1973Skasunath */
bejGetLocalBejSFLVOffsets(const uint8_t * enSegment,struct BejSFLVOffset * offsets)5964cb1973Skasunath static void bejGetLocalBejSFLVOffsets(const uint8_t* enSegment,
6064cb1973Skasunath struct BejSFLVOffset* offsets)
6164cb1973Skasunath {
6264cb1973Skasunath // Structure of the SFLV.
6364cb1973Skasunath // [Number of bytes need to represent the sequence number] - uint8_t
6464cb1973Skasunath // [SequenceNumber] - multi byte
6564cb1973Skasunath // [Format] - uint8_t
6664cb1973Skasunath // [Number of bytes need to represent the value length] - uint8_t
6764cb1973Skasunath // [Value length] - multi byte
6864cb1973Skasunath
6964cb1973Skasunath // Number of bytes need to represent the sequence number.
7064cb1973Skasunath const uint8_t seqSize = *enSegment;
7164cb1973Skasunath // Start of format.
7264cb1973Skasunath const uint32_t formatOffset = sizeof(uint8_t) + seqSize;
7364cb1973Skasunath // Start of length of the value-length bytes.
7464cb1973Skasunath const uint32_t valueLenNnintOffset = formatOffset + sizeof(uint8_t);
7564cb1973Skasunath // Number of bytes need to represent the value length.
7664cb1973Skasunath const uint8_t valueLengthSize = *(enSegment + valueLenNnintOffset);
7764cb1973Skasunath // Start of the Value.
78be27f2e9SPatrick Williams const uint32_t valueOffset =
79be27f2e9SPatrick Williams valueLenNnintOffset + sizeof(uint8_t) + valueLengthSize;
8064cb1973Skasunath
8164cb1973Skasunath offsets->formatOffset = formatOffset;
8264cb1973Skasunath offsets->valueLenNnintOffset = valueLenNnintOffset;
8364cb1973Skasunath offsets->valueOffset = valueOffset;
8464cb1973Skasunath }
8564cb1973Skasunath
8664cb1973Skasunath /**
8764cb1973Skasunath * @brief Initialize sflv struct in params struct.
8864cb1973Skasunath *
8964cb1973Skasunath * @param[inout] params - a valid BejHandleTypeFuncParam struct with
9064cb1973Skasunath * params->state.encodedSubStream pointing to the start of the encoded stream
9164cb1973Skasunath * and params->state.encodedStreamOffset pointing to the current bejTuple.
9264cb1973Skasunath */
bejInitSFLVStruct(struct BejHandleTypeFuncParam * params)9364cb1973Skasunath static void bejInitSFLVStruct(struct BejHandleTypeFuncParam* params)
9464cb1973Skasunath {
9564cb1973Skasunath struct BejSFLVOffset localOffset;
9664cb1973Skasunath // Get offsets of different SFLV fields with respect to start of the encoded
9764cb1973Skasunath // segment.
9864cb1973Skasunath bejGetLocalBejSFLVOffsets(params->state.encodedSubStream, &localOffset);
9964cb1973Skasunath struct BejSFLV* sflv = ¶ms->sflv;
1000aa36d82Skasunath const uint32_t valueLength = (uint32_t)(bejGetNnint(
10164cb1973Skasunath params->state.encodedSubStream + localOffset.valueLenNnintOffset));
10264cb1973Skasunath // Sequence number itself should be 16bits. Using 32bits for
10364cb1973Skasunath // [sequence_number + schema_type].
1040aa36d82Skasunath uint32_t tupleS = (uint32_t)(bejGetNnint(params->state.encodedSubStream));
10564cb1973Skasunath sflv->tupleS.schema = (uint8_t)(tupleS & DICTIONARY_TYPE_MASK);
10664cb1973Skasunath sflv->tupleS.sequenceNumber =
10764cb1973Skasunath (uint16_t)((tupleS & (~DICTIONARY_TYPE_MASK)) >>
10864cb1973Skasunath DICTIONARY_SEQ_NUM_SHIFT);
10964cb1973Skasunath sflv->format = *(struct BejTupleF*)(params->state.encodedSubStream +
11064cb1973Skasunath localOffset.formatOffset);
11164cb1973Skasunath sflv->valueLength = valueLength;
11264cb1973Skasunath sflv->valueEndOffset = params->state.encodedStreamOffset +
11364cb1973Skasunath localOffset.valueOffset + valueLength;
11464cb1973Skasunath sflv->value = params->state.encodedSubStream + localOffset.valueOffset;
11564cb1973Skasunath }
11664cb1973Skasunath
11764cb1973Skasunath /**
11834a096dbSkasunath * @brief Get the offset to the first tuple of a bejArray or bejSet.
11934a096dbSkasunath *
12034a096dbSkasunath * The first part of the value of a bejArray or a bejSet contains an nnint
12134a096dbSkasunath * providing the number of elements/tuples. Offset is with respect to the start
12234a096dbSkasunath * of the encoded stream.
12334a096dbSkasunath *
12434a096dbSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
12534a096dbSkasunath * @return offset with respect to the start of the encoded stream.
12634a096dbSkasunath */
bejGetFirstTupleOffset(const struct BejHandleTypeFuncParam * params)127*045a2d65SPatrick Williams static uint32_t bejGetFirstTupleOffset(
128*045a2d65SPatrick Williams const struct BejHandleTypeFuncParam* params)
12934a096dbSkasunath {
13034a096dbSkasunath struct BejSFLVOffset localOffset;
13134a096dbSkasunath // Get the offset of the value with respect to the current encoded segment
13234a096dbSkasunath // being decoded.
13334a096dbSkasunath bejGetLocalBejSFLVOffsets(params->state.encodedSubStream, &localOffset);
13434a096dbSkasunath return params->state.encodedStreamOffset + localOffset.valueOffset +
1350aa36d82Skasunath bejGetNnintSize(params->sflv.value);
13634a096dbSkasunath }
13734a096dbSkasunath
13834a096dbSkasunath /**
13934a096dbSkasunath * @brief Get the correct property and the dictionary it belongs to.
14034a096dbSkasunath *
14134a096dbSkasunath * @param[in] params - a BejHandleTypeFuncParam struct pointing to valid
14234a096dbSkasunath * dictionaries.
14334a096dbSkasunath * @param[in] schemaType - indicate whether to use the annotation dictionary or
14434a096dbSkasunath * the main schema dictionary.
14534a096dbSkasunath * @param[in] sequenceNumber - sequence number to use for property search. Not
14634a096dbSkasunath * using the params->sflv.tupleS.sequenceNumber from the provided params struct.
14734a096dbSkasunath * @param[out] dictionary - if the function is successful, this will point to a
14834a096dbSkasunath * valid dictionary to be used.
14934a096dbSkasunath * @param[out] prop - if the function is successful, this will point to a valid
15034a096dbSkasunath * property in a dictionary.
15134a096dbSkasunath * @return 0 if successful.
15234a096dbSkasunath */
bejGetDictionaryAndProperty(const struct BejHandleTypeFuncParam * params,uint8_t schemaType,uint32_t sequenceNumber,const uint8_t ** dictionary,const struct BejDictionaryProperty ** prop)153be27f2e9SPatrick Williams static int bejGetDictionaryAndProperty(
154be27f2e9SPatrick Williams const struct BejHandleTypeFuncParam* params, uint8_t schemaType,
155be27f2e9SPatrick Williams uint32_t sequenceNumber, const uint8_t** dictionary,
15634a096dbSkasunath const struct BejDictionaryProperty** prop)
15734a096dbSkasunath {
15834a096dbSkasunath uint16_t dictPropOffset;
15934a096dbSkasunath // We need to pick the correct dictionary.
16034a096dbSkasunath if (schemaType == bejPrimary)
16134a096dbSkasunath {
16234a096dbSkasunath *dictionary = params->mainDictionary;
16334a096dbSkasunath dictPropOffset = params->state.mainDictPropOffset;
16434a096dbSkasunath }
16534a096dbSkasunath else if (schemaType == bejAnnotation)
16634a096dbSkasunath {
16734a096dbSkasunath *dictionary = params->annotDictionary;
16834a096dbSkasunath dictPropOffset = params->state.annoDictPropOffset;
16934a096dbSkasunath }
17034a096dbSkasunath else
17134a096dbSkasunath {
17234a096dbSkasunath fprintf(stderr, "Failed to select a dictionary. schema type: %u\n",
17334a096dbSkasunath schemaType);
17434a096dbSkasunath return bejErrorInvalidSchemaType;
17534a096dbSkasunath }
17634a096dbSkasunath
177be27f2e9SPatrick Williams int ret =
178be27f2e9SPatrick Williams bejDictGetProperty(*dictionary, dictPropOffset, sequenceNumber, prop);
17934a096dbSkasunath if (ret != 0)
18034a096dbSkasunath {
18134a096dbSkasunath fprintf(stderr, "Failed to get dictionary property for offset: %u\n",
18234a096dbSkasunath dictPropOffset);
18334a096dbSkasunath return ret;
18434a096dbSkasunath }
18534a096dbSkasunath return 0;
18634a096dbSkasunath }
18734a096dbSkasunath
18834a096dbSkasunath /**
189e2260cd6Skasunath * @brief Find and return the property name of the current encoded segment. If
190e2260cd6Skasunath * the params->state.addPropertyName is false, this will return an empty string.
19134a096dbSkasunath *
19234a096dbSkasunath * @param[in] params - a valid populated BejHandleTypeFuncParam.
19334a096dbSkasunath * @return 0 if successful.
19434a096dbSkasunath */
bejGetPropName(struct BejHandleTypeFuncParam * params)195e2260cd6Skasunath static const char* bejGetPropName(struct BejHandleTypeFuncParam* params)
19634a096dbSkasunath {
19734a096dbSkasunath const uint8_t* dictionary;
19834a096dbSkasunath const struct BejDictionaryProperty* prop;
199e2260cd6Skasunath if (!params->state.addPropertyName ||
200e2260cd6Skasunath (bejGetDictionaryAndProperty(params, params->sflv.tupleS.schema,
20134a096dbSkasunath params->sflv.tupleS.sequenceNumber,
202e2260cd6Skasunath &dictionary, &prop) != 0))
20334a096dbSkasunath {
20434a096dbSkasunath return "";
20534a096dbSkasunath }
20634a096dbSkasunath return bejDictGetPropertyName(dictionary, prop->nameOffset,
20734a096dbSkasunath prop->nameLength);
20834a096dbSkasunath }
20934a096dbSkasunath
21034a096dbSkasunath /**
21134a096dbSkasunath * @brief Look for section endings.
21234a096dbSkasunath *
21334a096dbSkasunath * This figures out whether the current encoded segment marks a section
21434a096dbSkasunath * ending. If so, this function will update the decoder state and pop the stack
21534a096dbSkasunath * used to memorize endings. This function should be called after updating the
21634a096dbSkasunath * encodedStreamOffset to the end of decoded SFLV tuple.
21734a096dbSkasunath *
21834a096dbSkasunath * @param[in] params - a valid BejHandleTypeFuncParam which contains the decoder
21934a096dbSkasunath * state.
22034a096dbSkasunath * @param[in] canBeEmpty - if true, the stack being empty is not an error. If
22134a096dbSkasunath * false, stack cannot be empty.
22234a096dbSkasunath * @return 0 if successful.
22334a096dbSkasunath */
bejProcessEnding(struct BejHandleTypeFuncParam * params,bool canBeEmpty)22434a096dbSkasunath static int bejProcessEnding(struct BejHandleTypeFuncParam* params,
22534a096dbSkasunath bool canBeEmpty)
22634a096dbSkasunath {
22734a096dbSkasunath if (params->stackCallback->stackEmpty(params->stackDataPtr) && !canBeEmpty)
22834a096dbSkasunath {
22934a096dbSkasunath // If bejProcessEnding has been called after adding an appropriate JSON
23034a096dbSkasunath // property, then stack cannot be empty.
23134a096dbSkasunath fprintf(stderr, "Ending stack cannot be empty.\n");
23234a096dbSkasunath return bejErrorUnknown;
23334a096dbSkasunath }
23434a096dbSkasunath
23534a096dbSkasunath while (!params->stackCallback->stackEmpty(params->stackDataPtr))
23634a096dbSkasunath {
23734a096dbSkasunath const struct BejStackProperty* const ending =
23834a096dbSkasunath params->stackCallback->stackPeek(params->stackDataPtr);
23934a096dbSkasunath // Check whether the current offset location matches the expected ending
24034a096dbSkasunath // offset. If so, we are done with that section.
24134a096dbSkasunath if (params->state.encodedStreamOffset == ending->streamEndOffset)
24234a096dbSkasunath {
24334a096dbSkasunath // Since we are going out of a section, we need to reset the
24434a096dbSkasunath // dictionary property offsets to this section's parent property
24534a096dbSkasunath // start.
24634a096dbSkasunath params->state.mainDictPropOffset = ending->mainDictPropOffset;
24734a096dbSkasunath params->state.annoDictPropOffset = ending->annoDictPropOffset;
24834a096dbSkasunath params->state.addPropertyName = ending->addPropertyName;
24934a096dbSkasunath
25034a096dbSkasunath if (ending->sectionType == bejSectionSet)
25134a096dbSkasunath {
25234a096dbSkasunath RETURN_IF_CALLBACK_IERROR(
25334a096dbSkasunath params->decodedCallback->callbackSetEnd,
25434a096dbSkasunath params->callbacksDataPtr);
25534a096dbSkasunath }
25634a096dbSkasunath else if (ending->sectionType == bejSectionArray)
25734a096dbSkasunath {
25834a096dbSkasunath RETURN_IF_CALLBACK_IERROR(
25934a096dbSkasunath params->decodedCallback->callbackArrayEnd,
26034a096dbSkasunath params->callbacksDataPtr);
26134a096dbSkasunath }
26234a096dbSkasunath params->stackCallback->stackPop(params->stackDataPtr);
26334a096dbSkasunath }
26434a096dbSkasunath else
26534a096dbSkasunath {
26634a096dbSkasunath RETURN_IF_CALLBACK_IERROR(
26734a096dbSkasunath params->decodedCallback->callbackPropertyEnd,
26834a096dbSkasunath params->callbacksDataPtr);
26934a096dbSkasunath // Do not change the parent dictionary property offset since we are
27034a096dbSkasunath // still inside the same section.
27134a096dbSkasunath return 0;
27234a096dbSkasunath }
27334a096dbSkasunath }
27434a096dbSkasunath return 0;
27534a096dbSkasunath }
27634a096dbSkasunath
27734a096dbSkasunath /**
27834a096dbSkasunath * @brief Check whether the current encoded segment being decoded is an array
27934a096dbSkasunath * element.
28034a096dbSkasunath *
28134a096dbSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
28234a096dbSkasunath * @return true if the encoded segment is an array element. Else false.
28334a096dbSkasunath */
bejIsArrayElement(const struct BejHandleTypeFuncParam * params)28434a096dbSkasunath static bool bejIsArrayElement(const struct BejHandleTypeFuncParam* params)
28534a096dbSkasunath {
28634a096dbSkasunath // If the encoded segment enters an array section, we are adding a
28734a096dbSkasunath // BejSectionArray to the stack. Therefore if the stack is empty, encoded
28834a096dbSkasunath // segment cannot be an array element.
28934a096dbSkasunath if (params->stackCallback->stackEmpty(params->stackDataPtr))
29034a096dbSkasunath {
29134a096dbSkasunath return false;
29234a096dbSkasunath }
29334a096dbSkasunath const struct BejStackProperty* const ending =
29434a096dbSkasunath params->stackCallback->stackPeek(params->stackDataPtr);
29534a096dbSkasunath // If the stack top element holds a BejSectionArray, encoded segment is
29634a096dbSkasunath // an array element.
29734a096dbSkasunath return ending->sectionType == bejSectionArray;
29834a096dbSkasunath }
29934a096dbSkasunath
30034a096dbSkasunath /**
30134a096dbSkasunath * @brief Decodes a BejSet type SFLV BEJ tuple.
30234a096dbSkasunath *
303b8ca265aSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
30434a096dbSkasunath * @return 0 if successful.
30534a096dbSkasunath */
bejHandleBejSet(struct BejHandleTypeFuncParam * params)30634a096dbSkasunath static int bejHandleBejSet(struct BejHandleTypeFuncParam* params)
30734a096dbSkasunath {
30834a096dbSkasunath uint16_t sequenceNumber = params->sflv.tupleS.sequenceNumber;
30934a096dbSkasunath // Check whether this BejSet is an array element or not.
31034a096dbSkasunath if (bejIsArrayElement(params))
31134a096dbSkasunath {
31234a096dbSkasunath // Dictionary only contains an entry for element 0.
31334a096dbSkasunath sequenceNumber = 0;
31434a096dbSkasunath }
31534a096dbSkasunath const uint8_t* dictionary;
31634a096dbSkasunath const struct BejDictionaryProperty* prop;
31734a096dbSkasunath RETURN_IF_IERROR(
31834a096dbSkasunath bejGetDictionaryAndProperty(params, params->sflv.tupleS.schema,
31934a096dbSkasunath sequenceNumber, &dictionary, &prop));
32034a096dbSkasunath
32134a096dbSkasunath const char* propName = "";
32234a096dbSkasunath if (params->state.addPropertyName)
32334a096dbSkasunath {
32434a096dbSkasunath propName = bejDictGetPropertyName(dictionary, prop->nameOffset,
32534a096dbSkasunath prop->nameLength);
32634a096dbSkasunath }
32734a096dbSkasunath
32834a096dbSkasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackSetStart,
32934a096dbSkasunath propName, params->callbacksDataPtr);
33034a096dbSkasunath
331c14fab6eSkasunath // Move the offset to the next SFLV tuple (or end). Make sure that this is
332c14fab6eSkasunath // called before calling bejProcessEnding.
333c14fab6eSkasunath params->state.encodedStreamOffset = bejGetFirstTupleOffset(params);
334c14fab6eSkasunath
3350aa36d82Skasunath uint64_t elements = bejGetNnint(params->sflv.value);
33634a096dbSkasunath // If its an empty set, we are done here.
33734a096dbSkasunath if (elements == 0)
33834a096dbSkasunath {
33934a096dbSkasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackSetEnd,
34034a096dbSkasunath params->callbacksDataPtr);
341c14fab6eSkasunath // Since this is an ending of a property (empty array), we should call
342c14fab6eSkasunath // bejProcessEnding. Unless the whole JSON object is an empty set (which
343c14fab6eSkasunath // shouldn't be the case), stack cannot be empty.
344c14fab6eSkasunath bejProcessEnding(params, /*canBeEmpty=*/false);
345c14fab6eSkasunath return 0;
34634a096dbSkasunath }
347c14fab6eSkasunath
34834a096dbSkasunath // Update the states for the next encoding segment.
34934a096dbSkasunath struct BejStackProperty newEnding = {
35034a096dbSkasunath .sectionType = bejSectionSet,
35134a096dbSkasunath .addPropertyName = params->state.addPropertyName,
35234a096dbSkasunath .mainDictPropOffset = params->state.mainDictPropOffset,
35334a096dbSkasunath .annoDictPropOffset = params->state.annoDictPropOffset,
35434a096dbSkasunath .streamEndOffset = params->sflv.valueEndOffset,
35534a096dbSkasunath };
35634a096dbSkasunath RETURN_IF_IERROR(
35734a096dbSkasunath params->stackCallback->stackPush(&newEnding, params->stackDataPtr));
35834a096dbSkasunath params->state.addPropertyName = true;
35934a096dbSkasunath if (params->sflv.tupleS.schema == bejAnnotation)
36034a096dbSkasunath {
36134a096dbSkasunath // Since this set is an annotated type, we need to advance the
36234a096dbSkasunath // annotation dictionary for decoding the next segment.
36334a096dbSkasunath params->state.annoDictPropOffset = prop->childPointerOffset;
36434a096dbSkasunath }
36534a096dbSkasunath else
36634a096dbSkasunath {
36734a096dbSkasunath params->state.mainDictPropOffset = prop->childPointerOffset;
36834a096dbSkasunath }
36934a096dbSkasunath return 0;
37034a096dbSkasunath }
37134a096dbSkasunath
37234a096dbSkasunath /**
373e2260cd6Skasunath * @brief Decodes a BejArray type SFLV BEJ tuple.
374e2260cd6Skasunath *
375b8ca265aSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
376e2260cd6Skasunath * @return 0 if successful.
377e2260cd6Skasunath */
bejHandleBejArray(struct BejHandleTypeFuncParam * params)378e2260cd6Skasunath static int bejHandleBejArray(struct BejHandleTypeFuncParam* params)
379e2260cd6Skasunath {
380e2260cd6Skasunath const uint8_t* dictionary;
381e2260cd6Skasunath const struct BejDictionaryProperty* prop;
382e2260cd6Skasunath RETURN_IF_IERROR(bejGetDictionaryAndProperty(
383e2260cd6Skasunath params, params->sflv.tupleS.schema, params->sflv.tupleS.sequenceNumber,
384e2260cd6Skasunath &dictionary, &prop));
385e2260cd6Skasunath
386e2260cd6Skasunath const char* propName = "";
387e2260cd6Skasunath if (params->state.addPropertyName)
388e2260cd6Skasunath {
389e2260cd6Skasunath propName = bejDictGetPropertyName(dictionary, prop->nameOffset,
390e2260cd6Skasunath prop->nameLength);
391e2260cd6Skasunath }
392e2260cd6Skasunath
393e2260cd6Skasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackArrayStart,
394e2260cd6Skasunath propName, params->callbacksDataPtr);
395e2260cd6Skasunath
396c14fab6eSkasunath // Move the offset to the next SFLV tuple (or end). Make sure that this is
397c14fab6eSkasunath // called before calling bejProcessEnding.
398c14fab6eSkasunath params->state.encodedStreamOffset = bejGetFirstTupleOffset(params);
399c14fab6eSkasunath
4000aa36d82Skasunath uint64_t elements = bejGetNnint(params->sflv.value);
401e2260cd6Skasunath // If its an empty array, we are done here.
402e2260cd6Skasunath if (elements == 0)
403e2260cd6Skasunath {
404e2260cd6Skasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackArrayEnd,
405e2260cd6Skasunath params->callbacksDataPtr);
406c14fab6eSkasunath // Since this is an ending of a property (empty array), we should call
407c14fab6eSkasunath // bejProcessEnding. Stack cannot be empty since there should be at
408c14fab6eSkasunath // least 1 parent in the stack.
409c14fab6eSkasunath bejProcessEnding(params, /*canBeEmpty=*/false);
410c14fab6eSkasunath return 0;
411e2260cd6Skasunath }
412c14fab6eSkasunath
413e2260cd6Skasunath // Update the state for next segment decoding.
414e2260cd6Skasunath struct BejStackProperty newEnding = {
415e2260cd6Skasunath .sectionType = bejSectionArray,
416e2260cd6Skasunath .addPropertyName = params->state.addPropertyName,
417e2260cd6Skasunath .mainDictPropOffset = params->state.mainDictPropOffset,
418e2260cd6Skasunath .annoDictPropOffset = params->state.annoDictPropOffset,
419e2260cd6Skasunath .streamEndOffset = params->sflv.valueEndOffset,
420e2260cd6Skasunath };
421e2260cd6Skasunath RETURN_IF_IERROR(
422e2260cd6Skasunath params->stackCallback->stackPush(&newEnding, params->stackDataPtr));
423e2260cd6Skasunath // We do not add property names for array elements.
424e2260cd6Skasunath params->state.addPropertyName = false;
425e2260cd6Skasunath if (params->sflv.tupleS.schema == bejAnnotation)
426e2260cd6Skasunath {
427e2260cd6Skasunath // Since this array is an annotated type, we need to advance the
428e2260cd6Skasunath // annotation dictionary for decoding the next segment.
429e2260cd6Skasunath params->state.annoDictPropOffset = prop->childPointerOffset;
430e2260cd6Skasunath }
431e2260cd6Skasunath else
432e2260cd6Skasunath {
433e2260cd6Skasunath params->state.mainDictPropOffset = prop->childPointerOffset;
434e2260cd6Skasunath }
435e2260cd6Skasunath return 0;
436e2260cd6Skasunath }
437e2260cd6Skasunath
438e2260cd6Skasunath /**
439e2260cd6Skasunath * @brief Decodes a BejNull type SFLV BEJ tuple.
440e2260cd6Skasunath *
441b8ca265aSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
442e2260cd6Skasunath * @return 0 if successful.
443e2260cd6Skasunath */
bejHandleBejNull(struct BejHandleTypeFuncParam * params)444e2260cd6Skasunath static int bejHandleBejNull(struct BejHandleTypeFuncParam* params)
445e2260cd6Skasunath {
446e2260cd6Skasunath const char* propName = bejGetPropName(params);
447e2260cd6Skasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackNull, propName,
448e2260cd6Skasunath params->callbacksDataPtr);
449e2260cd6Skasunath params->state.encodedStreamOffset = params->sflv.valueEndOffset;
450e2260cd6Skasunath return bejProcessEnding(params, /*canBeEmpty=*/false);
451e2260cd6Skasunath }
452e2260cd6Skasunath
453e2260cd6Skasunath /**
45434a096dbSkasunath * @brief Decodes a BejInteger type SFLV BEJ tuple.
45534a096dbSkasunath *
456b8ca265aSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
45734a096dbSkasunath * @return 0 if successful.
45834a096dbSkasunath */
bejHandleBejInteger(struct BejHandleTypeFuncParam * params)45934a096dbSkasunath static int bejHandleBejInteger(struct BejHandleTypeFuncParam* params)
46034a096dbSkasunath {
461e2260cd6Skasunath const char* propName = bejGetPropName(params);
46234a096dbSkasunath
46334a096dbSkasunath if (params->sflv.valueLength == 0)
46434a096dbSkasunath {
46534a096dbSkasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackNull,
46634a096dbSkasunath propName, params->callbacksDataPtr);
46734a096dbSkasunath }
46834a096dbSkasunath else
46934a096dbSkasunath {
47034a096dbSkasunath RETURN_IF_CALLBACK_IERROR(
47134a096dbSkasunath params->decodedCallback->callbackInteger, propName,
47234a096dbSkasunath bejGetIntegerValue(params->sflv.value, params->sflv.valueLength),
47334a096dbSkasunath params->callbacksDataPtr);
47434a096dbSkasunath }
47534a096dbSkasunath params->state.encodedStreamOffset = params->sflv.valueEndOffset;
47634a096dbSkasunath return bejProcessEnding(params, /*canBeEmpty=*/false);
47734a096dbSkasunath }
47834a096dbSkasunath
47934a096dbSkasunath /**
480b8ca265aSkasunath * @brief Decodes a BejEnum type SFLV BEJ tuple.
481b8ca265aSkasunath *
482b8ca265aSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
483b8ca265aSkasunath * @return 0 if successful.
484b8ca265aSkasunath */
bejHandleBejEnum(struct BejHandleTypeFuncParam * params)485b8ca265aSkasunath static int bejHandleBejEnum(struct BejHandleTypeFuncParam* params)
486b8ca265aSkasunath {
487b8ca265aSkasunath uint16_t sequenceNumber = params->sflv.tupleS.sequenceNumber;
488b8ca265aSkasunath if (bejIsArrayElement(params))
489b8ca265aSkasunath {
490b8ca265aSkasunath sequenceNumber = 0;
491b8ca265aSkasunath }
492b8ca265aSkasunath const uint8_t* dictionary;
493b8ca265aSkasunath const struct BejDictionaryProperty* prop;
494b8ca265aSkasunath RETURN_IF_IERROR(
495b8ca265aSkasunath bejGetDictionaryAndProperty(params, params->sflv.tupleS.schema,
496b8ca265aSkasunath sequenceNumber, &dictionary, &prop));
497b8ca265aSkasunath
498b8ca265aSkasunath const char* propName = "";
499b8ca265aSkasunath if (params->state.addPropertyName)
500b8ca265aSkasunath {
501b8ca265aSkasunath propName = bejDictGetPropertyName(dictionary, prop->nameOffset,
502b8ca265aSkasunath prop->nameLength);
503b8ca265aSkasunath }
504b8ca265aSkasunath
505b8ca265aSkasunath if (params->sflv.valueLength == 0)
506b8ca265aSkasunath {
507b8ca265aSkasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackNull,
508b8ca265aSkasunath propName, params->callbacksDataPtr);
509b8ca265aSkasunath }
510b8ca265aSkasunath else
511b8ca265aSkasunath {
512b8ca265aSkasunath // Get the string for enum value.
513b8ca265aSkasunath uint16_t enumValueSequenceN =
5140aa36d82Skasunath (uint16_t)(bejGetNnint(params->sflv.value));
515b8ca265aSkasunath const struct BejDictionaryProperty* enumValueProp;
516b8ca265aSkasunath RETURN_IF_IERROR(
517b8ca265aSkasunath bejDictGetProperty(dictionary, prop->childPointerOffset,
518b8ca265aSkasunath enumValueSequenceN, &enumValueProp));
519b8ca265aSkasunath const char* enumValueName = bejDictGetPropertyName(
520b8ca265aSkasunath dictionary, enumValueProp->nameOffset, enumValueProp->nameLength);
521b8ca265aSkasunath
522b8ca265aSkasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackEnum,
523b8ca265aSkasunath propName, enumValueName,
524b8ca265aSkasunath params->callbacksDataPtr);
525b8ca265aSkasunath }
526b8ca265aSkasunath // Update the offset to point to the next possible SFLV tuple.
527b8ca265aSkasunath params->state.encodedStreamOffset = params->sflv.valueEndOffset;
528b8ca265aSkasunath return bejProcessEnding(params, /*canBeEmpty=*/false);
529b8ca265aSkasunath }
530b8ca265aSkasunath
531b8ca265aSkasunath /**
532e2260cd6Skasunath * @brief Decodes a BejString type SFLV BEJ tuple.
533e2260cd6Skasunath *
534b8ca265aSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
535e2260cd6Skasunath * @return 0 if successful.
536e2260cd6Skasunath */
bejHandleBejString(struct BejHandleTypeFuncParam * params)537e2260cd6Skasunath static int bejHandleBejString(struct BejHandleTypeFuncParam* params)
538e2260cd6Skasunath {
539e2260cd6Skasunath // TODO: Handle deferred bindings.
540e2260cd6Skasunath const char* propName = bejGetPropName(params);
541e2260cd6Skasunath
542e2260cd6Skasunath if (params->sflv.valueLength == 0)
543e2260cd6Skasunath {
544e2260cd6Skasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackNull,
545e2260cd6Skasunath propName, params->callbacksDataPtr);
546e2260cd6Skasunath }
547e2260cd6Skasunath else
548e2260cd6Skasunath {
549e2260cd6Skasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackString,
550e2260cd6Skasunath propName, (const char*)(params->sflv.value),
551e2260cd6Skasunath params->callbacksDataPtr);
552e2260cd6Skasunath }
553e2260cd6Skasunath params->state.encodedStreamOffset = params->sflv.valueEndOffset;
554e2260cd6Skasunath return bejProcessEnding(params, /*canBeEmpty=*/false);
555e2260cd6Skasunath }
556e2260cd6Skasunath
557e2260cd6Skasunath /**
558b8ca265aSkasunath * @brief Decodes a BejReal type SFLV BEJ tuple.
559b8ca265aSkasunath *
560b8ca265aSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
561b8ca265aSkasunath * @return 0 if successful.
562b8ca265aSkasunath */
bejHandleBejReal(struct BejHandleTypeFuncParam * params)563b8ca265aSkasunath static int bejHandleBejReal(struct BejHandleTypeFuncParam* params)
564b8ca265aSkasunath {
565b8ca265aSkasunath const char* propName = bejGetPropName(params);
566b8ca265aSkasunath
567b8ca265aSkasunath if (params->sflv.valueLength == 0)
568b8ca265aSkasunath {
569b8ca265aSkasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackNull,
570b8ca265aSkasunath propName, params->callbacksDataPtr);
571b8ca265aSkasunath }
572b8ca265aSkasunath else
573b8ca265aSkasunath {
574b8ca265aSkasunath // Real value has the following format.
575b8ca265aSkasunath // nnint - Length of whole
576b8ca265aSkasunath // bejInteger - whole (includes sign for the overall real number)
577b8ca265aSkasunath // nnint - Leading zero count for fract
578b8ca265aSkasunath // nnint - fract
579b8ca265aSkasunath // nnint - Length of exp
580b8ca265aSkasunath // bejInteger - exp (includes sign for the exponent)
5810aa36d82Skasunath uint8_t wholeByteLen = (uint8_t)bejGetNnint(params->sflv.value);
582be27f2e9SPatrick Williams const uint8_t* wholeBejInt =
583be27f2e9SPatrick Williams params->sflv.value + bejGetNnintSize(params->sflv.value);
584b8ca265aSkasunath const uint8_t* fractZeroCountNnint = wholeBejInt + wholeByteLen;
585be27f2e9SPatrick Williams const uint8_t* fractNnint =
586be27f2e9SPatrick Williams fractZeroCountNnint + bejGetNnintSize(fractZeroCountNnint);
5870aa36d82Skasunath const uint8_t* lenExpNnint = fractNnint + bejGetNnintSize(fractNnint);
5880aa36d82Skasunath const uint8_t* expBejInt = lenExpNnint + bejGetNnintSize(lenExpNnint);
589b8ca265aSkasunath
590b8ca265aSkasunath struct BejReal realValue;
591b8ca265aSkasunath realValue.whole = bejGetIntegerValue(wholeBejInt, wholeByteLen);
5920aa36d82Skasunath realValue.zeroCount = bejGetNnint(fractZeroCountNnint);
5930aa36d82Skasunath realValue.fract = bejGetNnint(fractNnint);
5940aa36d82Skasunath realValue.expLen = (uint8_t)bejGetNnint(lenExpNnint);
595b8ca265aSkasunath if (realValue.expLen != 0)
596b8ca265aSkasunath {
597b8ca265aSkasunath realValue.exp = bejGetIntegerValue(
5980aa36d82Skasunath expBejInt, (uint8_t)bejGetNnint(lenExpNnint));
599b8ca265aSkasunath }
600b8ca265aSkasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackReal,
601b8ca265aSkasunath propName, &realValue,
602b8ca265aSkasunath params->callbacksDataPtr);
603b8ca265aSkasunath }
604b8ca265aSkasunath params->state.encodedStreamOffset = params->sflv.valueEndOffset;
605b8ca265aSkasunath return bejProcessEnding(params, /*canBeEmpty=*/false);
606b8ca265aSkasunath }
607b8ca265aSkasunath
608b8ca265aSkasunath /**
609e2260cd6Skasunath * @brief Decodes a BejBoolean type SFLV BEJ tuple.
610e2260cd6Skasunath *
611b8ca265aSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
612e2260cd6Skasunath * @return 0 if successful.
613e2260cd6Skasunath */
bejHandleBejBoolean(struct BejHandleTypeFuncParam * params)614e2260cd6Skasunath static int bejHandleBejBoolean(struct BejHandleTypeFuncParam* params)
615e2260cd6Skasunath {
616e2260cd6Skasunath const char* propName = bejGetPropName(params);
617e2260cd6Skasunath
618e2260cd6Skasunath if (params->sflv.valueLength == 0)
619e2260cd6Skasunath {
620e2260cd6Skasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackNull,
621e2260cd6Skasunath propName, params->callbacksDataPtr);
622e2260cd6Skasunath }
623e2260cd6Skasunath else
624e2260cd6Skasunath {
625e2260cd6Skasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackBool,
626e2260cd6Skasunath propName, *(params->sflv.value) > 0,
627e2260cd6Skasunath params->callbacksDataPtr);
628e2260cd6Skasunath }
629e2260cd6Skasunath params->state.encodedStreamOffset = params->sflv.valueEndOffset;
630e2260cd6Skasunath return bejProcessEnding(params, /*canBeEmpty=*/false);
631e2260cd6Skasunath }
632e2260cd6Skasunath
633e2260cd6Skasunath /**
634b8ca265aSkasunath * @brief Decodes a BejPropertyAnnotation type SFLV BEJ tuple.
635b8ca265aSkasunath *
636b8ca265aSkasunath * @param[in] params - a valid BejHandleTypeFuncParam struct.
637b8ca265aSkasunath * @return 0 if successful.
638b8ca265aSkasunath */
bejHandleBejPropertyAnnotation(struct BejHandleTypeFuncParam * params)639b8ca265aSkasunath static int bejHandleBejPropertyAnnotation(struct BejHandleTypeFuncParam* params)
640b8ca265aSkasunath {
641b8ca265aSkasunath // TODO: Handle colon-delimited string values.
642b8ca265aSkasunath
643b8ca265aSkasunath // Property annotation has the form OuterProperty@Annotation. First
644b8ca265aSkasunath // processing the outer property name.
645b8ca265aSkasunath const uint8_t* outerDictionary;
646b8ca265aSkasunath const struct BejDictionaryProperty* outerProp;
647b8ca265aSkasunath RETURN_IF_IERROR(bejGetDictionaryAndProperty(
648b8ca265aSkasunath params, params->sflv.tupleS.schema, params->sflv.tupleS.sequenceNumber,
649b8ca265aSkasunath &outerDictionary, &outerProp));
650b8ca265aSkasunath
651b8ca265aSkasunath const char* propName = bejDictGetPropertyName(
652b8ca265aSkasunath outerDictionary, outerProp->nameOffset, outerProp->nameLength);
653b8ca265aSkasunath RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackAnnotation,
654b8ca265aSkasunath propName, params->callbacksDataPtr);
655b8ca265aSkasunath
656b8ca265aSkasunath // Mark the ending of the property annotation.
657b8ca265aSkasunath struct BejStackProperty newEnding = {
658b8ca265aSkasunath .sectionType = bejSectionNoType,
659b8ca265aSkasunath .addPropertyName = params->state.addPropertyName,
660b8ca265aSkasunath .mainDictPropOffset = params->state.mainDictPropOffset,
661b8ca265aSkasunath .annoDictPropOffset = params->state.annoDictPropOffset,
662b8ca265aSkasunath .streamEndOffset = params->sflv.valueEndOffset,
663b8ca265aSkasunath };
664b8ca265aSkasunath // Update the states for the next encoding segment.
665b8ca265aSkasunath RETURN_IF_IERROR(
666b8ca265aSkasunath params->stackCallback->stackPush(&newEnding, params->stackDataPtr));
667b8ca265aSkasunath params->state.addPropertyName = true;
668b8ca265aSkasunath // We might have to change this for nested annotations.
669b8ca265aSkasunath params->state.mainDictPropOffset = outerProp->childPointerOffset;
670b8ca265aSkasunath // Point to the start of the value for next decoding.
671be27f2e9SPatrick Williams params->state.encodedStreamOffset =
672be27f2e9SPatrick Williams params->sflv.valueEndOffset - params->sflv.valueLength;
673b8ca265aSkasunath return 0;
674b8ca265aSkasunath }
675b8ca265aSkasunath
676b8ca265aSkasunath /**
67764cb1973Skasunath * @brief Decodes an encoded bej stream.
67864cb1973Skasunath *
67964cb1973Skasunath * @param[in] schemaDictionary - main schema dictionary to use.
68064cb1973Skasunath * @param[in] annotationDictionary - annotation dictionary
68164cb1973Skasunath * @param[in] enStream - encoded stream without the PLDM header.
68264cb1973Skasunath * @param[in] streamLen - length of the enStream.
68364cb1973Skasunath * @param[in] stackCallback - callbacks for stack handlers.
68464cb1973Skasunath * @param[in] decodedCallback - callbacks for extracting decoded properties.
68564cb1973Skasunath * @param[in] callbacksDataPtr - data pointer to pass to decoded callbacks. This
68664cb1973Skasunath * can be used pass additional data.
68764cb1973Skasunath * @param[in] stackDataPtr - data pointer to pass to stack callbacks. This can
68864cb1973Skasunath * be used pass additional data.
68964cb1973Skasunath *
69064cb1973Skasunath * @return 0 if successful.
69164cb1973Skasunath */
bejDecode(const uint8_t * schemaDictionary,const uint8_t * annotationDictionary,const uint8_t * enStream,uint32_t streamLen,const struct BejStackCallback * stackCallback,const struct BejDecodedCallback * decodedCallback,void * callbacksDataPtr,void * stackDataPtr)69264cb1973Skasunath static int bejDecode(const uint8_t* schemaDictionary,
69364cb1973Skasunath const uint8_t* annotationDictionary,
69464cb1973Skasunath const uint8_t* enStream, uint32_t streamLen,
69564cb1973Skasunath const struct BejStackCallback* stackCallback,
69664cb1973Skasunath const struct BejDecodedCallback* decodedCallback,
69764cb1973Skasunath void* callbacksDataPtr, void* stackDataPtr)
69864cb1973Skasunath {
69964cb1973Skasunath struct BejHandleTypeFuncParam params = {
70064cb1973Skasunath .state =
70164cb1973Skasunath {
70264cb1973Skasunath // We only add names of set properties. We don't use names for
70364cb1973Skasunath // array
70464cb1973Skasunath // properties. Here we are omitting the name of the root set.
70564cb1973Skasunath .addPropertyName = false,
70664cb1973Skasunath // At start, parent property from the main dictionary is the
70764cb1973Skasunath // first property.
70864cb1973Skasunath .mainDictPropOffset = bejDictGetPropertyHeadOffset(),
70964cb1973Skasunath .annoDictPropOffset = bejDictGetFirstAnnotatedPropertyOffset(),
71064cb1973Skasunath // Current location of the encoded segment we are processing.
71164cb1973Skasunath .encodedStreamOffset = 0,
71264cb1973Skasunath .encodedSubStream = enStream,
71364cb1973Skasunath },
71464cb1973Skasunath .mainDictionary = schemaDictionary,
71564cb1973Skasunath .annotDictionary = annotationDictionary,
71664cb1973Skasunath .decodedCallback = decodedCallback,
71764cb1973Skasunath .stackCallback = stackCallback,
71864cb1973Skasunath .callbacksDataPtr = callbacksDataPtr,
71964cb1973Skasunath .stackDataPtr = stackDataPtr,
72064cb1973Skasunath };
72164cb1973Skasunath
72264cb1973Skasunath while (params.state.encodedStreamOffset < streamLen)
72364cb1973Skasunath {
72464cb1973Skasunath // Go to the next encoded segment in the encoded stream.
725be27f2e9SPatrick Williams params.state.encodedSubStream =
726be27f2e9SPatrick Williams enStream + params.state.encodedStreamOffset;
72764cb1973Skasunath bejInitSFLVStruct(¶ms);
72864cb1973Skasunath
72964cb1973Skasunath if (params.sflv.format.readOnlyProperty)
73064cb1973Skasunath {
73164cb1973Skasunath RETURN_IF_CALLBACK_IERROR(
73264cb1973Skasunath params.decodedCallback->callbackReadonlyProperty,
73364cb1973Skasunath params.sflv.tupleS.sequenceNumber, params.callbacksDataPtr);
73464cb1973Skasunath }
73564cb1973Skasunath
73664cb1973Skasunath // TODO: Handle nullable property types. These are indicated by
73764cb1973Skasunath // params.sflv.format.nullableProperty
73864cb1973Skasunath switch (params.sflv.format.principalDataType)
73964cb1973Skasunath {
74064cb1973Skasunath case bejSet:
74134a096dbSkasunath RETURN_IF_IERROR(bejHandleBejSet(¶ms));
74264cb1973Skasunath break;
74364cb1973Skasunath case bejArray:
744e2260cd6Skasunath RETURN_IF_IERROR(bejHandleBejArray(¶ms));
74564cb1973Skasunath break;
74664cb1973Skasunath case bejNull:
747e2260cd6Skasunath RETURN_IF_IERROR(bejHandleBejNull(¶ms));
74864cb1973Skasunath break;
74964cb1973Skasunath case bejInteger:
75034a096dbSkasunath RETURN_IF_IERROR(bejHandleBejInteger(¶ms));
75164cb1973Skasunath break;
75264cb1973Skasunath case bejEnum:
753b8ca265aSkasunath RETURN_IF_IERROR(bejHandleBejEnum(¶ms));
75464cb1973Skasunath break;
75564cb1973Skasunath case bejString:
756e2260cd6Skasunath RETURN_IF_IERROR(bejHandleBejString(¶ms));
75764cb1973Skasunath break;
75864cb1973Skasunath case bejReal:
759b8ca265aSkasunath RETURN_IF_IERROR(bejHandleBejReal(¶ms));
76064cb1973Skasunath break;
76164cb1973Skasunath case bejBoolean:
762e2260cd6Skasunath RETURN_IF_IERROR(bejHandleBejBoolean(¶ms));
76364cb1973Skasunath break;
76464cb1973Skasunath case bejBytestring:
76564cb1973Skasunath // TODO: Add support for BejBytestring decoding.
76664cb1973Skasunath fprintf(stderr, "No BejBytestring support\n");
76764cb1973Skasunath params.state.encodedStreamOffset = params.sflv.valueEndOffset;
76864cb1973Skasunath break;
76964cb1973Skasunath case bejChoice:
77064cb1973Skasunath // TODO: Add support for BejChoice decoding.
77164cb1973Skasunath fprintf(stderr, "No BejChoice support\n");
77264cb1973Skasunath params.state.encodedStreamOffset = params.sflv.valueEndOffset;
77364cb1973Skasunath break;
77464cb1973Skasunath case bejPropertyAnnotation:
775b8ca265aSkasunath RETURN_IF_IERROR(bejHandleBejPropertyAnnotation(¶ms));
77664cb1973Skasunath break;
77764cb1973Skasunath case bejResourceLink:
77864cb1973Skasunath // TODO: Add support for BejResourceLink decoding.
77964cb1973Skasunath fprintf(stderr, "No BejResourceLink support\n");
78064cb1973Skasunath params.state.encodedStreamOffset = params.sflv.valueEndOffset;
78164cb1973Skasunath break;
78264cb1973Skasunath case bejResourceLinkExpansion:
78364cb1973Skasunath // TODO: Add support for BejResourceLinkExpansion decoding.
78464cb1973Skasunath fprintf(stderr, "No BejResourceLinkExpansion support\n");
78564cb1973Skasunath params.state.encodedStreamOffset = params.sflv.valueEndOffset;
78664cb1973Skasunath break;
78764cb1973Skasunath default:
78864cb1973Skasunath break;
78964cb1973Skasunath }
79064cb1973Skasunath }
79134a096dbSkasunath RETURN_IF_IERROR(bejProcessEnding(¶ms, /*canBeEmpty=*/true));
79264cb1973Skasunath if (!params.stackCallback->stackEmpty(params.stackDataPtr))
79364cb1973Skasunath {
79464cb1973Skasunath fprintf(stderr, "Ending stack should be empty but its not. Something "
79564cb1973Skasunath "must have gone wrong with the encoding\n");
79664cb1973Skasunath return bejErrorUnknown;
79764cb1973Skasunath }
79864cb1973Skasunath return 0;
79964cb1973Skasunath }
80064cb1973Skasunath
80164cb1973Skasunath /**
80264cb1973Skasunath * @brief Check if a bej version is supported by this decoder
80364cb1973Skasunath *
804b8ca265aSkasunath * @param[in] bejVersion - the bej version in the received encoded stream
80564cb1973Skasunath * @return true if supported.
80664cb1973Skasunath */
bejIsSupported(uint32_t bejVersion)80764cb1973Skasunath static bool bejIsSupported(uint32_t bejVersion)
80864cb1973Skasunath {
80964cb1973Skasunath for (uint32_t i = 0; i < sizeof(supportedBejVersions) / sizeof(uint32_t);
81064cb1973Skasunath ++i)
81164cb1973Skasunath {
81264cb1973Skasunath if (bejVersion == supportedBejVersions[i])
81364cb1973Skasunath {
81464cb1973Skasunath return true;
81564cb1973Skasunath }
81664cb1973Skasunath }
81764cb1973Skasunath return false;
81864cb1973Skasunath }
81964cb1973Skasunath
bejDecodePldmBlock(const struct BejDictionaries * dictionaries,const uint8_t * encodedPldmBlock,uint32_t blockLength,const struct BejStackCallback * stackCallback,const struct BejDecodedCallback * decodedCallback,void * callbacksDataPtr,void * stackDataPtr)82064cb1973Skasunath int bejDecodePldmBlock(const struct BejDictionaries* dictionaries,
82164cb1973Skasunath const uint8_t* encodedPldmBlock, uint32_t blockLength,
82264cb1973Skasunath const struct BejStackCallback* stackCallback,
82364cb1973Skasunath const struct BejDecodedCallback* decodedCallback,
82464cb1973Skasunath void* callbacksDataPtr, void* stackDataPtr)
82564cb1973Skasunath {
82634a096dbSkasunath NULL_CHECK(dictionaries, "dictionaries");
82734a096dbSkasunath NULL_CHECK(dictionaries->schemaDictionary, "schemaDictionary");
82834a096dbSkasunath NULL_CHECK(dictionaries->annotationDictionary, "annotationDictionary");
82934a096dbSkasunath
83034a096dbSkasunath NULL_CHECK(encodedPldmBlock, "encodedPldmBlock");
83134a096dbSkasunath
83234a096dbSkasunath NULL_CHECK(stackCallback, "stackCallback");
83334a096dbSkasunath NULL_CHECK(stackCallback->stackEmpty, "stackEmpty");
83434a096dbSkasunath NULL_CHECK(stackCallback->stackPeek, "stackPeek");
83534a096dbSkasunath NULL_CHECK(stackCallback->stackPop, "stackPop");
83634a096dbSkasunath NULL_CHECK(stackCallback->stackPush, "stackPush");
83734a096dbSkasunath
83834a096dbSkasunath NULL_CHECK(decodedCallback, "decodedCallback");
83934a096dbSkasunath
84064cb1973Skasunath uint32_t pldmHeaderSize = sizeof(struct BejPldmBlockHeader);
84164cb1973Skasunath if (blockLength < pldmHeaderSize)
84264cb1973Skasunath {
84364cb1973Skasunath fprintf(stderr, "Invalid pldm block size: %u\n", blockLength);
84464cb1973Skasunath return bejErrorInvalidSize;
84564cb1973Skasunath }
84664cb1973Skasunath
84764cb1973Skasunath const struct BejPldmBlockHeader* pldmHeader =
84864cb1973Skasunath (const struct BejPldmBlockHeader*)encodedPldmBlock;
84964cb1973Skasunath
85064cb1973Skasunath if (!bejIsSupported(pldmHeader->bejVersion))
85164cb1973Skasunath {
85264cb1973Skasunath fprintf(stderr, "Bej decoder doesn't support the bej version: %u\n",
85364cb1973Skasunath pldmHeader->bejVersion);
85464cb1973Skasunath return bejErrorNotSuppoted;
85564cb1973Skasunath }
85664cb1973Skasunath
85764cb1973Skasunath if (pldmHeader->schemaClass == bejAnnotationSchemaClass)
85864cb1973Skasunath {
85964cb1973Skasunath fprintf(stderr,
86064cb1973Skasunath "Encoder schema class cannot be BejAnnotationSchemaClass\n");
86164cb1973Skasunath return bejErrorNotSuppoted;
86264cb1973Skasunath }
86364cb1973Skasunath // TODO: Add support for CollectionMemberType schema class.
86464cb1973Skasunath if (pldmHeader->schemaClass == bejCollectionMemberTypeSchemaClass)
86564cb1973Skasunath {
86664cb1973Skasunath fprintf(stderr, "Decoder doesn't support "
86734a096dbSkasunath "bejCollectionMemberTypeSchemaClass yet.\n");
86864cb1973Skasunath return bejErrorNotSuppoted;
86964cb1973Skasunath }
87064cb1973Skasunath // TODO: Add support for Error schema class.
87164cb1973Skasunath if (pldmHeader->schemaClass == bejErrorSchemaClass)
87264cb1973Skasunath {
87364cb1973Skasunath fprintf(stderr, "Decoder doesn't support BejErrorSchemaClass yet.\n");
87464cb1973Skasunath return bejErrorNotSuppoted;
87564cb1973Skasunath }
87664cb1973Skasunath
87764cb1973Skasunath // Skip the PLDM header.
87864cb1973Skasunath const uint8_t* enStream = encodedPldmBlock + pldmHeaderSize;
87964cb1973Skasunath uint32_t streamLen = blockLength - pldmHeaderSize;
88064cb1973Skasunath return bejDecode(dictionaries->schemaDictionary,
88164cb1973Skasunath dictionaries->annotationDictionary, enStream, streamLen,
88264cb1973Skasunath stackCallback, decodedCallback, callbacksDataPtr,
88364cb1973Skasunath stackDataPtr);
88464cb1973Skasunath }
885