blob: c226a5212a3502970916f0a2fd860767dfd4a3b4 [file] [log] [blame]
kasunath64cb1972022-05-13 12:54:23 -07001#include "bej_decoder_core.h"
2
3#include "bej_dictionary.h"
4#include "stdio.h"
5
6#include <inttypes.h>
7#include <stdbool.h>
8#include <stdlib.h>
9#include <string.h>
10
11// TODO: Support nested annotations for version 0xF1F1F000
12const uint32_t supportedBejVersions[] = {0xF1F0F000};
13
14/**
15 * @brief Call a callback function. If the callback function is NULL, this will
16 * not do anything. If the callback function returns a non-zero value, this will
17 * cause the caller to return with the non-zero status.
18 */
19#define RETURN_IF_CALLBACK_IERROR(function, ...) \
20 do \
21 { \
22 if ((function) != NULL) \
23 { \
24 int __status = ((function)(__VA_ARGS__)); \
25 if (__status != 0) \
26 { \
27 return __status; \
28 } \
29 } \
30 } while (0)
31
32/**
kasunath34a096d2022-05-17 11:36:14 -070033 * @brief Check a given varable is NULL. If it is NULL, this will return with
34 * bejErrorNullParameter. If the variable is not NULL, this will will not
35 * return.
36 */
37#define NULL_CHECK(param, structStr) \
38 do \
39 { \
40 if ((param) == NULL) \
41 { \
42 fprintf(stderr, "nullCheck: %s cannot be null\n", structStr); \
43 return bejErrorNullParameter; \
44 } \
45 } while (0)
46
47/**
48 * @brief Get the integer value from BEJ byte stream.
49 *
50 * @param[in] bytes - valid pointer to a byte stream in little-endian format.
51 * @param[in] numOfBytes - number of bytes belongs to the value. Maximum value
52 * supported is 8 bytes.
53 * @return signed 64bit representation of the value.
54 */
55static int64_t bejGetIntegerValue(const uint8_t* bytes, uint8_t numOfBytes)
56{
57 if (numOfBytes == 0)
58 {
59 return 0;
60 }
61 uint64_t value = rdeGetUnsignedInteger(bytes, numOfBytes);
62 uint8_t bitsInVal = numOfBytes * 8;
63 // Since numOfBytes > 0, bitsInVal is non negative.
64 uint64_t mask = (uint64_t)1 << (uint8_t)(bitsInVal - 1);
65 return (value ^ mask) - mask;
66}
67
68/**
kasunath64cb1972022-05-13 12:54:23 -070069 * @brief Get offsets of SFLV fields with respect to the enSegment start.
70 *
71 * @param[in] enSegment - a valid pointer to a start of a SFLV bejTuple.
72 * @param[out] offsets - this will hold the local offsets.
73 */
74static void bejGetLocalBejSFLVOffsets(const uint8_t* enSegment,
75 struct BejSFLVOffset* offsets)
76{
77 // Structure of the SFLV.
78 // [Number of bytes need to represent the sequence number] - uint8_t
79 // [SequenceNumber] - multi byte
80 // [Format] - uint8_t
81 // [Number of bytes need to represent the value length] - uint8_t
82 // [Value length] - multi byte
83
84 // Number of bytes need to represent the sequence number.
85 const uint8_t seqSize = *enSegment;
86 // Start of format.
87 const uint32_t formatOffset = sizeof(uint8_t) + seqSize;
88 // Start of length of the value-length bytes.
89 const uint32_t valueLenNnintOffset = formatOffset + sizeof(uint8_t);
90 // Number of bytes need to represent the value length.
91 const uint8_t valueLengthSize = *(enSegment + valueLenNnintOffset);
92 // Start of the Value.
93 const uint32_t valueOffset =
94 valueLenNnintOffset + sizeof(uint8_t) + valueLengthSize;
95
96 offsets->formatOffset = formatOffset;
97 offsets->valueLenNnintOffset = valueLenNnintOffset;
98 offsets->valueOffset = valueOffset;
99}
100
101/**
102 * @brief Initialize sflv struct in params struct.
103 *
104 * @param[inout] params - a valid BejHandleTypeFuncParam struct with
105 * params->state.encodedSubStream pointing to the start of the encoded stream
106 * and params->state.encodedStreamOffset pointing to the current bejTuple.
107 */
108static void bejInitSFLVStruct(struct BejHandleTypeFuncParam* params)
109{
110 struct BejSFLVOffset localOffset;
111 // Get offsets of different SFLV fields with respect to start of the encoded
112 // segment.
113 bejGetLocalBejSFLVOffsets(params->state.encodedSubStream, &localOffset);
114 struct BejSFLV* sflv = &params->sflv;
115 const uint32_t valueLength = (uint32_t)(rdeGetNnint(
116 params->state.encodedSubStream + localOffset.valueLenNnintOffset));
117 // Sequence number itself should be 16bits. Using 32bits for
118 // [sequence_number + schema_type].
119 uint32_t tupleS = (uint32_t)(rdeGetNnint(params->state.encodedSubStream));
120 sflv->tupleS.schema = (uint8_t)(tupleS & DICTIONARY_TYPE_MASK);
121 sflv->tupleS.sequenceNumber =
122 (uint16_t)((tupleS & (~DICTIONARY_TYPE_MASK)) >>
123 DICTIONARY_SEQ_NUM_SHIFT);
124 sflv->format = *(struct BejTupleF*)(params->state.encodedSubStream +
125 localOffset.formatOffset);
126 sflv->valueLength = valueLength;
127 sflv->valueEndOffset = params->state.encodedStreamOffset +
128 localOffset.valueOffset + valueLength;
129 sflv->value = params->state.encodedSubStream + localOffset.valueOffset;
130}
131
132/**
kasunath34a096d2022-05-17 11:36:14 -0700133 * @brief Get the offset to the first tuple of a bejArray or bejSet.
134 *
135 * The first part of the value of a bejArray or a bejSet contains an nnint
136 * providing the number of elements/tuples. Offset is with respect to the start
137 * of the encoded stream.
138 *
139 * @param[in] params - a valid BejHandleTypeFuncParam struct.
140 * @return offset with respect to the start of the encoded stream.
141 */
142static uint32_t
143 bejGetFirstTupleOffset(const struct BejHandleTypeFuncParam* params)
144{
145 struct BejSFLVOffset localOffset;
146 // Get the offset of the value with respect to the current encoded segment
147 // being decoded.
148 bejGetLocalBejSFLVOffsets(params->state.encodedSubStream, &localOffset);
149 return params->state.encodedStreamOffset + localOffset.valueOffset +
150 rdeGetNnintSize(params->sflv.value);
151}
152
153/**
154 * @brief Get the correct property and the dictionary it belongs to.
155 *
156 * @param[in] params - a BejHandleTypeFuncParam struct pointing to valid
157 * dictionaries.
158 * @param[in] schemaType - indicate whether to use the annotation dictionary or
159 * the main schema dictionary.
160 * @param[in] sequenceNumber - sequence number to use for property search. Not
161 * using the params->sflv.tupleS.sequenceNumber from the provided params struct.
162 * @param[out] dictionary - if the function is successful, this will point to a
163 * valid dictionary to be used.
164 * @param[out] prop - if the function is successful, this will point to a valid
165 * property in a dictionary.
166 * @return 0 if successful.
167 */
168static int
169 bejGetDictionaryAndProperty(const struct BejHandleTypeFuncParam* params,
170 uint8_t schemaType, uint32_t sequenceNumber,
171 const uint8_t** dictionary,
172 const struct BejDictionaryProperty** prop)
173{
174 uint16_t dictPropOffset;
175 // We need to pick the correct dictionary.
176 if (schemaType == bejPrimary)
177 {
178 *dictionary = params->mainDictionary;
179 dictPropOffset = params->state.mainDictPropOffset;
180 }
181 else if (schemaType == bejAnnotation)
182 {
183 *dictionary = params->annotDictionary;
184 dictPropOffset = params->state.annoDictPropOffset;
185 }
186 else
187 {
188 fprintf(stderr, "Failed to select a dictionary. schema type: %u\n",
189 schemaType);
190 return bejErrorInvalidSchemaType;
191 }
192
193 int ret =
194 bejDictGetProperty(*dictionary, dictPropOffset, sequenceNumber, prop);
195 if (ret != 0)
196 {
197 fprintf(stderr, "Failed to get dictionary property for offset: %u\n",
198 dictPropOffset);
199 return ret;
200 }
201 return 0;
202}
203
204/**
205 * @brief Find and return the property name of the current encoded segment.
206 *
207 * @param[in] params - a valid populated BejHandleTypeFuncParam.
208 * @return 0 if successful.
209 */
210static const char* bejFindPropName(struct BejHandleTypeFuncParam* params)
211{
212 const uint8_t* dictionary;
213 const struct BejDictionaryProperty* prop;
214 if (bejGetDictionaryAndProperty(params, params->sflv.tupleS.schema,
215 params->sflv.tupleS.sequenceNumber,
216 &dictionary, &prop) != 0)
217 {
218 return "";
219 }
220 return bejDictGetPropertyName(dictionary, prop->nameOffset,
221 prop->nameLength);
222}
223
224/**
225 * @brief Look for section endings.
226 *
227 * This figures out whether the current encoded segment marks a section
228 * ending. If so, this function will update the decoder state and pop the stack
229 * used to memorize endings. This function should be called after updating the
230 * encodedStreamOffset to the end of decoded SFLV tuple.
231 *
232 * @param[in] params - a valid BejHandleTypeFuncParam which contains the decoder
233 * state.
234 * @param[in] canBeEmpty - if true, the stack being empty is not an error. If
235 * false, stack cannot be empty.
236 * @return 0 if successful.
237 */
238static int bejProcessEnding(struct BejHandleTypeFuncParam* params,
239 bool canBeEmpty)
240{
241 if (params->stackCallback->stackEmpty(params->stackDataPtr) && !canBeEmpty)
242 {
243 // If bejProcessEnding has been called after adding an appropriate JSON
244 // property, then stack cannot be empty.
245 fprintf(stderr, "Ending stack cannot be empty.\n");
246 return bejErrorUnknown;
247 }
248
249 while (!params->stackCallback->stackEmpty(params->stackDataPtr))
250 {
251 const struct BejStackProperty* const ending =
252 params->stackCallback->stackPeek(params->stackDataPtr);
253 // Check whether the current offset location matches the expected ending
254 // offset. If so, we are done with that section.
255 if (params->state.encodedStreamOffset == ending->streamEndOffset)
256 {
257 // Since we are going out of a section, we need to reset the
258 // dictionary property offsets to this section's parent property
259 // start.
260 params->state.mainDictPropOffset = ending->mainDictPropOffset;
261 params->state.annoDictPropOffset = ending->annoDictPropOffset;
262 params->state.addPropertyName = ending->addPropertyName;
263
264 if (ending->sectionType == bejSectionSet)
265 {
266 RETURN_IF_CALLBACK_IERROR(
267 params->decodedCallback->callbackSetEnd,
268 params->callbacksDataPtr);
269 }
270 else if (ending->sectionType == bejSectionArray)
271 {
272 RETURN_IF_CALLBACK_IERROR(
273 params->decodedCallback->callbackArrayEnd,
274 params->callbacksDataPtr);
275 }
276 params->stackCallback->stackPop(params->stackDataPtr);
277 }
278 else
279 {
280 RETURN_IF_CALLBACK_IERROR(
281 params->decodedCallback->callbackPropertyEnd,
282 params->callbacksDataPtr);
283 // Do not change the parent dictionary property offset since we are
284 // still inside the same section.
285 return 0;
286 }
287 }
288 return 0;
289}
290
291/**
292 * @brief Check whether the current encoded segment being decoded is an array
293 * element.
294 *
295 * @param[in] params - a valid BejHandleTypeFuncParam struct.
296 * @return true if the encoded segment is an array element. Else false.
297 */
298static bool bejIsArrayElement(const struct BejHandleTypeFuncParam* params)
299{
300 // If the encoded segment enters an array section, we are adding a
301 // BejSectionArray to the stack. Therefore if the stack is empty, encoded
302 // segment cannot be an array element.
303 if (params->stackCallback->stackEmpty(params->stackDataPtr))
304 {
305 return false;
306 }
307 const struct BejStackProperty* const ending =
308 params->stackCallback->stackPeek(params->stackDataPtr);
309 // If the stack top element holds a BejSectionArray, encoded segment is
310 // an array element.
311 return ending->sectionType == bejSectionArray;
312}
313
314/**
315 * @brief Decodes a BejSet type SFLV BEJ tuple.
316 *
317 * @param params - a valid BejHandleTypeFuncParam struct.
318 * @return 0 if successful.
319 */
320static int bejHandleBejSet(struct BejHandleTypeFuncParam* params)
321{
322 uint16_t sequenceNumber = params->sflv.tupleS.sequenceNumber;
323 // Check whether this BejSet is an array element or not.
324 if (bejIsArrayElement(params))
325 {
326 // Dictionary only contains an entry for element 0.
327 sequenceNumber = 0;
328 }
329 const uint8_t* dictionary;
330 const struct BejDictionaryProperty* prop;
331 RETURN_IF_IERROR(
332 bejGetDictionaryAndProperty(params, params->sflv.tupleS.schema,
333 sequenceNumber, &dictionary, &prop));
334
335 const char* propName = "";
336 if (params->state.addPropertyName)
337 {
338 propName = bejDictGetPropertyName(dictionary, prop->nameOffset,
339 prop->nameLength);
340 }
341
342 RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackSetStart,
343 propName, params->callbacksDataPtr);
344
345 uint64_t elements = rdeGetNnint(params->sflv.value);
346 // If its an empty set, we are done here.
347 if (elements == 0)
348 {
349 RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackSetEnd,
350 params->callbacksDataPtr);
351 }
352 else
353 {
354 // Update the states for the next encoding segment.
355 struct BejStackProperty newEnding = {
356 .sectionType = bejSectionSet,
357 .addPropertyName = params->state.addPropertyName,
358 .mainDictPropOffset = params->state.mainDictPropOffset,
359 .annoDictPropOffset = params->state.annoDictPropOffset,
360 .streamEndOffset = params->sflv.valueEndOffset,
361 };
362 RETURN_IF_IERROR(
363 params->stackCallback->stackPush(&newEnding, params->stackDataPtr));
364 params->state.addPropertyName = true;
365 if (params->sflv.tupleS.schema == bejAnnotation)
366 {
367 // Since this set is an annotated type, we need to advance the
368 // annotation dictionary for decoding the next segment.
369 params->state.annoDictPropOffset = prop->childPointerOffset;
370 }
371 else
372 {
373 params->state.mainDictPropOffset = prop->childPointerOffset;
374 }
375 }
376 params->state.encodedStreamOffset = bejGetFirstTupleOffset(params);
377 return 0;
378}
379
380/**
381 * @brief Decodes a BejInteger type SFLV BEJ tuple.
382 *
383 * @param params - a valid BejHandleTypeFuncParam struct.
384 * @return 0 if successful.
385 */
386static int bejHandleBejInteger(struct BejHandleTypeFuncParam* params)
387{
388 const char* propName = "";
389 if (params->state.addPropertyName)
390 {
391 propName = bejFindPropName(params);
392 }
393
394 if (params->sflv.valueLength == 0)
395 {
396 RETURN_IF_CALLBACK_IERROR(params->decodedCallback->callbackNull,
397 propName, params->callbacksDataPtr);
398 }
399 else
400 {
401 RETURN_IF_CALLBACK_IERROR(
402 params->decodedCallback->callbackInteger, propName,
403 bejGetIntegerValue(params->sflv.value, params->sflv.valueLength),
404 params->callbacksDataPtr);
405 }
406 params->state.encodedStreamOffset = params->sflv.valueEndOffset;
407 return bejProcessEnding(params, /*canBeEmpty=*/false);
408}
409
410/**
kasunath64cb1972022-05-13 12:54:23 -0700411 * @brief Decodes an encoded bej stream.
412 *
413 * @param[in] schemaDictionary - main schema dictionary to use.
414 * @param[in] annotationDictionary - annotation dictionary
415 * @param[in] enStream - encoded stream without the PLDM header.
416 * @param[in] streamLen - length of the enStream.
417 * @param[in] stackCallback - callbacks for stack handlers.
418 * @param[in] decodedCallback - callbacks for extracting decoded properties.
419 * @param[in] callbacksDataPtr - data pointer to pass to decoded callbacks. This
420 * can be used pass additional data.
421 * @param[in] stackDataPtr - data pointer to pass to stack callbacks. This can
422 * be used pass additional data.
423 *
424 * @return 0 if successful.
425 */
426static int bejDecode(const uint8_t* schemaDictionary,
427 const uint8_t* annotationDictionary,
428 const uint8_t* enStream, uint32_t streamLen,
429 const struct BejStackCallback* stackCallback,
430 const struct BejDecodedCallback* decodedCallback,
431 void* callbacksDataPtr, void* stackDataPtr)
432{
433 struct BejHandleTypeFuncParam params = {
434 .state =
435 {
436 // We only add names of set properties. We don't use names for
437 // array
438 // properties. Here we are omitting the name of the root set.
439 .addPropertyName = false,
440 // At start, parent property from the main dictionary is the
441 // first property.
442 .mainDictPropOffset = bejDictGetPropertyHeadOffset(),
443 .annoDictPropOffset = bejDictGetFirstAnnotatedPropertyOffset(),
444 // Current location of the encoded segment we are processing.
445 .encodedStreamOffset = 0,
446 .encodedSubStream = enStream,
447 },
448 .mainDictionary = schemaDictionary,
449 .annotDictionary = annotationDictionary,
450 .decodedCallback = decodedCallback,
451 .stackCallback = stackCallback,
452 .callbacksDataPtr = callbacksDataPtr,
453 .stackDataPtr = stackDataPtr,
454 };
455
456 while (params.state.encodedStreamOffset < streamLen)
457 {
458 // Go to the next encoded segment in the encoded stream.
459 params.state.encodedSubStream =
460 enStream + params.state.encodedStreamOffset;
461 bejInitSFLVStruct(&params);
462
463 if (params.sflv.format.readOnlyProperty)
464 {
465 RETURN_IF_CALLBACK_IERROR(
466 params.decodedCallback->callbackReadonlyProperty,
467 params.sflv.tupleS.sequenceNumber, params.callbacksDataPtr);
468 }
469
470 // TODO: Handle nullable property types. These are indicated by
471 // params.sflv.format.nullableProperty
472 switch (params.sflv.format.principalDataType)
473 {
474 case bejSet:
kasunath34a096d2022-05-17 11:36:14 -0700475 RETURN_IF_IERROR(bejHandleBejSet(&params));
kasunath64cb1972022-05-13 12:54:23 -0700476 break;
477 case bejArray:
478 // TODO: Add support for BejArray decoding.
479 fprintf(stderr, "No BejArray support\n");
480 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
481 break;
482 case bejNull:
483 // TODO: Add support for BejNull decoding.
484 fprintf(stderr, "No BejNull support\n");
485 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
486 break;
487 case bejInteger:
kasunath34a096d2022-05-17 11:36:14 -0700488 RETURN_IF_IERROR(bejHandleBejInteger(&params));
kasunath64cb1972022-05-13 12:54:23 -0700489 break;
490 case bejEnum:
491 // TODO: Add support for BejEnum decoding.
492 fprintf(stderr, "No BejEnum support\n");
493 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
494 break;
495 case bejString:
496 // TODO: Add support for BejString decoding.
497 fprintf(stderr, "No BejString support\n");
498 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
499 break;
500 case bejReal:
501 // TODO: Add support for BejReal decoding.
502 fprintf(stderr, "No BejReal support\n");
503 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
504 break;
505 case bejBoolean:
506 // TODO: Add support for BejBoolean decoding.
507 fprintf(stderr, "No BejBoolean support\n");
508 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
509 break;
510 case bejBytestring:
511 // TODO: Add support for BejBytestring decoding.
512 fprintf(stderr, "No BejBytestring support\n");
513 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
514 break;
515 case bejChoice:
516 // TODO: Add support for BejChoice decoding.
517 fprintf(stderr, "No BejChoice support\n");
518 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
519 break;
520 case bejPropertyAnnotation:
521 // TODO: Add support for BejPropertyAnnotation decoding.
522 fprintf(stderr, "No BejPropertyAnnotation support\n");
523 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
524 break;
525 case bejResourceLink:
526 // TODO: Add support for BejResourceLink decoding.
527 fprintf(stderr, "No BejResourceLink support\n");
528 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
529 break;
530 case bejResourceLinkExpansion:
531 // TODO: Add support for BejResourceLinkExpansion decoding.
532 fprintf(stderr, "No BejResourceLinkExpansion support\n");
533 params.state.encodedStreamOffset = params.sflv.valueEndOffset;
534 break;
535 default:
536 break;
537 }
538 }
kasunath34a096d2022-05-17 11:36:14 -0700539 RETURN_IF_IERROR(bejProcessEnding(&params, /*canBeEmpty=*/true));
kasunath64cb1972022-05-13 12:54:23 -0700540 if (!params.stackCallback->stackEmpty(params.stackDataPtr))
541 {
542 fprintf(stderr, "Ending stack should be empty but its not. Something "
543 "must have gone wrong with the encoding\n");
544 return bejErrorUnknown;
545 }
546 return 0;
547}
548
549/**
550 * @brief Check if a bej version is supported by this decoder
551 *
552 * @param bejVersion[in] - the bej version in the received encoded stream
553 * @return true if supported.
554 */
555static bool bejIsSupported(uint32_t bejVersion)
556{
557 for (uint32_t i = 0; i < sizeof(supportedBejVersions) / sizeof(uint32_t);
558 ++i)
559 {
560 if (bejVersion == supportedBejVersions[i])
561 {
562 return true;
563 }
564 }
565 return false;
566}
567
568int bejDecodePldmBlock(const struct BejDictionaries* dictionaries,
569 const uint8_t* encodedPldmBlock, uint32_t blockLength,
570 const struct BejStackCallback* stackCallback,
571 const struct BejDecodedCallback* decodedCallback,
572 void* callbacksDataPtr, void* stackDataPtr)
573{
kasunath34a096d2022-05-17 11:36:14 -0700574 NULL_CHECK(dictionaries, "dictionaries");
575 NULL_CHECK(dictionaries->schemaDictionary, "schemaDictionary");
576 NULL_CHECK(dictionaries->annotationDictionary, "annotationDictionary");
577
578 NULL_CHECK(encodedPldmBlock, "encodedPldmBlock");
579
580 NULL_CHECK(stackCallback, "stackCallback");
581 NULL_CHECK(stackCallback->stackEmpty, "stackEmpty");
582 NULL_CHECK(stackCallback->stackPeek, "stackPeek");
583 NULL_CHECK(stackCallback->stackPop, "stackPop");
584 NULL_CHECK(stackCallback->stackPush, "stackPush");
585
586 NULL_CHECK(decodedCallback, "decodedCallback");
587
kasunath64cb1972022-05-13 12:54:23 -0700588 uint32_t pldmHeaderSize = sizeof(struct BejPldmBlockHeader);
589 if (blockLength < pldmHeaderSize)
590 {
591 fprintf(stderr, "Invalid pldm block size: %u\n", blockLength);
592 return bejErrorInvalidSize;
593 }
594
595 const struct BejPldmBlockHeader* pldmHeader =
596 (const struct BejPldmBlockHeader*)encodedPldmBlock;
597
598 if (!bejIsSupported(pldmHeader->bejVersion))
599 {
600 fprintf(stderr, "Bej decoder doesn't support the bej version: %u\n",
601 pldmHeader->bejVersion);
602 return bejErrorNotSuppoted;
603 }
604
605 if (pldmHeader->schemaClass == bejAnnotationSchemaClass)
606 {
607 fprintf(stderr,
608 "Encoder schema class cannot be BejAnnotationSchemaClass\n");
609 return bejErrorNotSuppoted;
610 }
611 // TODO: Add support for CollectionMemberType schema class.
612 if (pldmHeader->schemaClass == bejCollectionMemberTypeSchemaClass)
613 {
614 fprintf(stderr, "Decoder doesn't support "
kasunath34a096d2022-05-17 11:36:14 -0700615 "bejCollectionMemberTypeSchemaClass yet.\n");
kasunath64cb1972022-05-13 12:54:23 -0700616 return bejErrorNotSuppoted;
617 }
618 // TODO: Add support for Error schema class.
619 if (pldmHeader->schemaClass == bejErrorSchemaClass)
620 {
621 fprintf(stderr, "Decoder doesn't support BejErrorSchemaClass yet.\n");
622 return bejErrorNotSuppoted;
623 }
624
625 // Skip the PLDM header.
626 const uint8_t* enStream = encodedPldmBlock + pldmHeaderSize;
627 uint32_t streamLen = blockLength - pldmHeaderSize;
628 return bejDecode(dictionaries->schemaDictionary,
629 dictionaries->annotationDictionary, enStream, streamLen,
630 stackCallback, decodedCallback, callbacksDataPtr,
631 stackDataPtr);
632}