From dec9eecd1a84c14a99dde6ac712fa210046d65c1 Mon Sep 17 00:00:00 2001 From: Laurence Lundblade Date: Wed, 4 May 2022 21:37:25 -0600 Subject: [PATCH] Prototype simple map decoder --- inc/qcbor/qcbor_decode.h | 13 +++++++ src/qcbor_decode.c | 68 ++++++++++++++++++++++++++++++++ test/qcbor_decode_tests.c | 81 ++++++++++++++++++++++++++++++++++++++- test/qcbor_decode_tests.h | 5 +++ test/run_tests.c | 1 + 5 files changed, 167 insertions(+), 1 deletion(-) diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h index 4c641aeb..44e11fdf 100644 --- a/inc/qcbor/qcbor_decode.h +++ b/inc/qcbor/qcbor_decode.h @@ -923,6 +923,19 @@ void QCBORDecode_VGetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); QCBORError QCBORDecode_GetNext(QCBORDecodeContext *pCtx, QCBORItem *pDecodedItem); + +typedef QCBORError (*MapCB)(void *pCBCtx, QCBORDecodeContext *pDecodeCtx, QCBORItem *pDecodedItem); + +typedef struct { + int64_t nLabel; + uint8_t uType; + MapCB pCB; +} MCB; + + +QCBORError QCBORDecode_Mappie(QCBORDecodeContext *pCtx, uint16_t uMapSize, const MCB *pCBList, void *pCBCtx, UsefulBuf DupDetectionBuffer); + + /** * @brief Get the next item, fully consuming it if it is a map or array. * diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c index 82170732..4b6fbd2b 100644 --- a/src/qcbor_decode.c +++ b/src/qcbor_decode.c @@ -2811,6 +2811,74 @@ void QCBORDecode_VGetNextConsume(QCBORDecodeContext *pMe, QCBORItem *pDecodedIte } +QCBORError +QCBORDecode_Mappie(QCBORDecodeContext *pMe, + const uint16_t uMapSize, + const MCB *pCBList, + void *pCBCtx, + const UsefulBuf DupDetection) +{ + QCBORItem Item; + QCBORError uErr; + + if(!UsefulBuf_IsNULL(DupDetection)) { + if(DupDetection.len < uMapSize * sizeof(int64_t)) { + /* Dup detection buffer too small*/ + return 888; + } + } + + /* Loop over items */ + for(int xx = 0; xx< uMapSize; xx++) { + uErr = QCBORDecode_GetNext(pMe, &Item); + if(uErr) { + goto Done; + } + + if(Item.uLabelType != QCBOR_TYPE_INT64) { + /* Only works on integer labels */ + // TODO: proper error code + return 99; + } + + /* Duplicate detection if caller supplied a buffer */ + if(!UsefulBuf_IsNULL(DupDetection)) { + for(int j = 0; j < xx; j++) { + if(((int64_t *)DupDetection.ptr)[xx] == Item.label.int64) { + /* Found a duplicate */ + return 777; + } + } + + ((int64_t *)DupDetection.ptr)[xx] = Item.label.int64; + } + + /* Loop over CB's looking for label */ + for(int i = 0 ; pCBList[i].pCB != NULL; i++) { + + if(pCBList[i].nLabel == Item.label.int64) { + if(pCBList[i].uType != Item.uDataType && + pCBList[i].uType != QCBOR_TYPE_ANY) { + uErr = QCBOR_ERR_UNEXPECTED_TYPE; + goto Done; + } + + /* Matched label, make call back */ + uErr = (*pCBList[i].pCB)(pCBCtx, pMe, &Item); + if(uErr) { + goto Done; + } + break; /* First callback for label wins */ + } + } + } + uErr = QCBOR_SUCCESS; + +Done: + return uErr; +} + + /* Call only on maps and arrays. Rewinds the cursor * to the start as if it was just entered. diff --git a/test/qcbor_decode_tests.c b/test/qcbor_decode_tests.c index edb08613..8e4212fb 100644 --- a/test/qcbor_decode_tests.c +++ b/test/qcbor_decode_tests.c @@ -6070,7 +6070,7 @@ int32_t CBORTestIssue134() uCBORError = QCBORDecode_Finish(&DCtx); - return uCBORError; + return (int32_t)uCBORError; } int32_t CBORSequenceDecodeTests(void) @@ -7901,3 +7901,82 @@ int32_t BoolTest(void) return 0; } + + + +/* + {1: "hi", 2: 42, 3: 3.14} + */ + +static const uint8_t spMappieT[] = {0xA3, 0x01, 0x62, 0x68, 0x69, 0x02, 0x18, 0x2A, 0x03, 0xFB, 0x40, 0x09, 0x1E, 0xB8, 0x51, 0xEB, 0x85, 0x1F}; + +struct MappieTest { + UsefulBufC Text; + int64_t Int; + double Float; +}; + + + +static QCBORError +DecodeOne(void *pCBCtx, QCBORDecodeContext *pDCtx, QCBORItem *Item) +{ + struct MappieTest *pMt = (struct MappieTest *)pCBCtx; + + pMt->Text = Item->val.string; + + return 0; +} + +static QCBORError +DecodeTwo(void *pCBCtx, QCBORDecodeContext *pDCtx, QCBORItem *Item) +{ + struct MappieTest *pMt = (struct MappieTest *)pCBCtx; + + pMt->Int = Item->val.int64; + + return 0; +} + +static QCBORError +DecodeThree(void *pCBCtx, QCBORDecodeContext *pDCtx, QCBORItem *Item) +{ + struct MappieTest *pMt = (struct MappieTest *)pCBCtx; + + pMt->Float = Item->val.dfnum; + + return 0; +} + + +int32_t MappieTest(void) +{ + QCBORDecodeContext DC; + QCBORItem Item; + QCBORError uErr; + MakeUsefulBufOnStack(DupDetect, (sizeof(int64_t) * 4)); + + struct MappieTest MT; + + MCB MM[] = { + {1, QCBOR_TYPE_TEXT_STRING, &DecodeOne}, + {2, QCBOR_TYPE_INT64, &DecodeTwo}, + {3, QCBOR_TYPE_DOUBLE, &DecodeThree}, + {0, QCBOR_TYPE_NONE, NULL} + }; + + + QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spMappieT), 0); + + QCBORDecode_GetNext(&DC, &Item); + + uErr = QCBORDecode_Mappie(&DC, Item.val.uCount, MM, &MT, DupDetect); + + uErr = QCBORDecode_Finish(&DC); + + if(MT.Int != 42) { + return 99; + } + + return 0; +} diff --git a/test/qcbor_decode_tests.h b/test/qcbor_decode_tests.h index 11fdc94b..847039c2 100644 --- a/test/qcbor_decode_tests.h +++ b/test/qcbor_decode_tests.h @@ -318,4 +318,9 @@ Test GitHub issue #134: decode an indefinite-length string with a zero-length fi */ int32_t CBORTestIssue134(void); + + +int32_t MappieTest(void); + + #endif /* defined(__QCBOR__qcbort_decode_tests__) */ diff --git a/test/run_tests.c b/test/run_tests.c index 54cd8832..b4717318 100644 --- a/test/run_tests.c +++ b/test/run_tests.c @@ -66,6 +66,7 @@ static test_entry2 s_tests2[] = { static test_entry s_tests[] = { + TEST_ENTRY(MappieTest), TEST_ENTRY(OpenCloseBytesTest), TEST_ENTRY(EnterBstrTest), TEST_ENTRY(IntegerConvertTest),