| /*============================================================================== |
| Copyright (c) 2016-2018, The Linux Foundation. |
| Copyright (c) 2018-2020, Laurence Lundblade. |
| All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are |
| met: |
| * Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| * Redistributions in binary form must reproduce the above |
| copyright notice, this list of conditions and the following |
| disclaimer in the documentation and/or other materials provided |
| with the distribution. |
| * Neither the name of The Linux Foundation nor the names of its |
| contributors, nor the name "Laurence Lundblade" may be used to |
| endorse or promote products derived from this software without |
| specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| =============================================================================*/ |
| |
| #include "qcbor_decode_tests.h" |
| #include "qcbor/qcbor_encode.h" |
| #include "qcbor/qcbor_decode.h" |
| #include <string.h> |
| #include <math.h> // for fabs() |
| #include "not_well_formed_cbor.h" |
| |
| |
| #ifdef PRINT_FUNCTIONS_FOR_DEBUGGING |
| #include <stdio.h> |
| |
| static void PrintUsefulBufC(const char *szLabel, UsefulBufC Buf) |
| { |
| if(szLabel) { |
| printf("%s ", szLabel); |
| } |
| |
| size_t i; |
| for(i = 0; i < Buf.len; i++) { |
| uint8_t Z = ((uint8_t *)Buf.ptr)[i]; |
| printf("%02x ", Z); |
| } |
| printf("\n"); |
| |
| fflush(stdout); |
| } |
| #endif |
| |
| |
| static const uint8_t spExpectedEncodedInts[] = { |
| 0x98, 0x2f, 0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, |
| 0xff, 0xff, 0xff, 0x3b, 0x00, 0x00, 0x00, 0x01, |
| 0x00, 0x00, 0x00, 0x00, 0x3a, 0xff, 0xff, 0xff, |
| 0xff, 0x3a, 0xff, 0xff, 0xff, 0xfe, 0x3a, 0xff, |
| 0xff, 0xff, 0xfd, 0x3a, 0x7f, 0xff, 0xff, 0xff, |
| 0x3a, 0x7f, 0xff, 0xff, 0xfe, 0x3a, 0x00, 0x01, |
| 0x00, 0x01, 0x3a, 0x00, 0x01, 0x00, 0x00, 0x39, |
| 0xff, 0xff, 0x39, 0xff, 0xfe, 0x39, 0xff, 0xfd, |
| 0x39, 0x01, 0x00, 0x38, 0xff, 0x38, 0xfe, 0x38, |
| 0xfd, 0x38, 0x18, 0x37, 0x36, 0x20, 0x00, 0x00, |
| 0x01, 0x16, 0x17, 0x18, 0x18, 0x18, 0x19, 0x18, |
| 0x1a, 0x18, 0xfe, 0x18, 0xff, 0x19, 0x01, 0x00, |
| 0x19, 0x01, 0x01, 0x19, 0xff, 0xfe, 0x19, 0xff, |
| 0xff, 0x1a, 0x00, 0x01, 0x00, 0x00, 0x1a, 0x00, |
| 0x01, 0x00, 0x01, 0x1a, 0x00, 0x01, 0x00, 0x02, |
| 0x1a, 0x7f, 0xff, 0xff, 0xff, 0x1a, 0x7f, 0xff, |
| 0xff, 0xff, 0x1a, 0x80, 0x00, 0x00, 0x00, 0x1a, |
| 0x80, 0x00, 0x00, 0x01, 0x1a, 0xff, 0xff, 0xff, |
| 0xfe, 0x1a, 0xff, 0xff, 0xff, 0xff, 0x1b, 0x00, |
| 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x1b, |
| 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, |
| 0x1b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
| 0xff, 0x1b, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, |
| 0xff, 0xff}; |
| |
| |
| // return CBOR error or -1 if type of value doesn't match |
| |
| static int32_t IntegerValuesParseTestInternal(QCBORDecodeContext *pDCtx) |
| { |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -9223372036854775807LL - 1) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -4294967297) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -4294967296) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -4294967295) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -4294967294) |
| return -1; |
| |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -2147483648) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -2147483647) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -65538) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -65537) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -65536) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -65535) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -65534) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -257) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -256) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -255) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -254) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -25) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -24) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -23) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -1) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 0) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 0) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 1) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 22) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 23) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 24) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 25) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 26) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 254) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 255) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 256) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 257) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 65534) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 65535) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 65536) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 65537) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 65538) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 2147483647) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 2147483647) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 2147483648) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 2147483649) |
| return -1; |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 4294967294) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 4294967295) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 4294967296) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 4294967297) |
| return -1; |
| |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 9223372036854775807LL) |
| return -1; |
| |
| |
| if(( nCBORError = QCBORDecode_GetNext(pDCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_UINT64 || |
| Item.val.uint64 != 18446744073709551615ULL) |
| return -1; |
| |
| |
| if(QCBORDecode_Finish(pDCtx) != QCBOR_SUCCESS) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| |
| // One less than the smallest negative integer allowed in C. Decoding |
| // this should fail. |
| static const uint8_t spTooSmallNegative[] = { |
| 0x3b, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| }; |
| |
| |
| /* |
| Tests the decoding of lots of different integers sizes |
| and values. |
| */ |
| int32_t IntegerValuesParseTest() |
| { |
| int nReturn; |
| QCBORDecodeContext DCtx; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedEncodedInts), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| // The really big test of all successes |
| nReturn = IntegerValuesParseTestInternal(&DCtx); |
| if(nReturn) { |
| return nReturn; |
| } |
| |
| // The one large negative integer that can be parsed |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooSmallNegative), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| QCBORItem item; |
| if(QCBORDecode_GetNext(&DCtx, &item) != QCBOR_ERR_INT_OVERFLOW) { |
| nReturn = -4000; |
| } |
| |
| return(nReturn); |
| } |
| |
| |
| /* |
| Creates a simple CBOR array and returns it in *pEncoded. The array is |
| malloced and needs to be freed. This is used by several tests. |
| |
| Two of the inputs can be set. Two other items in the array are fixed. |
| |
| */ |
| |
| static uint8_t spSimpleArrayBuffer[50]; |
| |
| static int32_t CreateSimpleArray(int nInt1, int nInt2, uint8_t **pEncoded, size_t *pEncodedLen) |
| { |
| QCBOREncodeContext ECtx; |
| int nReturn = -1; |
| |
| *pEncoded = NULL; |
| *pEncodedLen = INT32_MAX; |
| |
| // loop runs CBOR encoding twice. First with no buffer to |
| // calculate the length so buffer can be allocated correctly, |
| // and last with the buffer to do the actual encoding |
| do { |
| QCBOREncode_Init(&ECtx, (UsefulBuf){*pEncoded, *pEncodedLen}); |
| QCBOREncode_OpenArray(&ECtx); |
| QCBOREncode_AddInt64(&ECtx, nInt1); |
| QCBOREncode_AddInt64(&ECtx, nInt2); |
| QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"galactic", 8})); |
| QCBOREncode_AddBytes(&ECtx, ((UsefulBufC) {"haven token", 11})); |
| QCBOREncode_CloseArray(&ECtx); |
| |
| if(QCBOREncode_FinishGetSize(&ECtx, pEncodedLen)) |
| goto Done; |
| |
| if(*pEncoded != NULL) { |
| nReturn = 0; |
| goto Done; |
| } |
| |
| // Use static buffer to avoid dependency on malloc() |
| if(*pEncodedLen > sizeof(spSimpleArrayBuffer)) { |
| goto Done; |
| } |
| *pEncoded = spSimpleArrayBuffer; |
| |
| } while(1); |
| |
| Done: |
| return nReturn; |
| } |
| |
| |
| /* |
| Some basic CBOR with map and array used in a lot of tests. |
| The map labels are all strings |
| |
| {"first integer": 42, |
| "an array of two strings": [ |
| "string1", "string2" |
| ], |
| "map in a map": { |
| "bytes 1": h'78787878', |
| "bytes 2": h'79797979', |
| "another int": 98, |
| "text 2": "lies, damn lies and statistics" |
| } |
| } |
| */ |
| static const uint8_t pValidMapEncoded[] = { |
| 0xa3, 0x6d, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x69, 0x6e, |
| 0x74, 0x65, 0x67, 0x65, 0x72, 0x18, 0x2a, 0x77, 0x61, 0x6e, |
| 0x20, 0x61, 0x72, 0x72, 0x61, 0x79, 0x20, 0x6f, 0x66, 0x20, |
| 0x74, 0x77, 0x6f, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, |
| 0x73, 0x82, 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x31, |
| 0x67, 0x73, 0x74, 0x72, 0x69, 0x6e, 0x67, 0x32, 0x6c, 0x6d, |
| 0x61, 0x70, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x6d, 0x61, |
| 0x70, 0xa4, 0x67, 0x62, 0x79, 0x74, 0x65, 0x73, 0x20, 0x31, |
| 0x44, 0x78, 0x78, 0x78, 0x78, 0x67, 0x62, 0x79, 0x74, 0x65, |
| 0x73, 0x20, 0x32, 0x44, 0x79, 0x79, 0x79, 0x79, 0x6b, 0x61, |
| 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x74, |
| 0x18, 0x62, 0x66, 0x74, 0x65, 0x78, 0x74, 0x20, 0x32, 0x78, |
| 0x1e, 0x6c, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x64, 0x61, 0x6d, |
| 0x6e, 0x20, 0x6c, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, |
| 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x73, 0x74, 0x69, 0x63, |
| 0x73 } ; |
| |
| static int32_t ParseOrderedArray(const uint8_t *pEncoded, |
| size_t nLen, |
| int64_t *pInt1, |
| int64_t *pInt2, |
| const uint8_t **pBuf3, |
| size_t *pBuf3Len, |
| const uint8_t **pBuf4, |
| size_t *pBuf4Len) |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| int nReturn = -1; // assume error until success |
| |
| QCBORDecode_Init(&DCtx, |
| (UsefulBufC){pEncoded, nLen}, |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| // Make sure the first thing is a map |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_ARRAY) |
| goto Done; |
| |
| // First integer |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64) |
| goto Done; |
| *pInt1 = Item.val.int64; |
| |
| // Second integer |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_INT64) |
| goto Done; |
| *pInt2 = Item.val.int64; |
| |
| // First string |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING) |
| goto Done; |
| *pBuf3 = Item.val.string.ptr; |
| *pBuf3Len = Item.val.string.len; |
| |
| // Second string |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || Item.uDataType != QCBOR_TYPE_BYTE_STRING) |
| goto Done; |
| *pBuf4 = Item.val.string.ptr; |
| *pBuf4Len = Item.val.string.len; |
| |
| nReturn = 0; |
| |
| Done: |
| return(nReturn); |
| } |
| |
| |
| |
| |
| int32_t SimpleArrayTest() |
| { |
| uint8_t *pEncoded; |
| size_t nEncodedLen; |
| |
| int64_t i1=0, i2=0; |
| size_t i3=0, i4=0; |
| const uint8_t *s3= (uint8_t *)""; |
| const uint8_t *s4= (uint8_t *)""; |
| |
| |
| if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) { |
| return(-1); |
| } |
| |
| ParseOrderedArray(pEncoded, nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4); |
| |
| if(i1 != 23 || |
| i2 != 6000 || |
| i3 != 8 || |
| i4 != 11 || |
| memcmp("galactic", s3, 8) !=0 || |
| memcmp("haven token", s4, 11) !=0) { |
| return(-1); |
| } |
| |
| return(0); |
| } |
| |
| |
| /* |
| [ |
| 0, |
| [], |
| [ |
| [], |
| [ |
| 0 |
| ], |
| {}, |
| { |
| 1: {}, |
| 2: {}, |
| 3: [] |
| } |
| ] |
| ] |
| */ |
| static uint8_t sEmpties[] = {0x83, 0x00, 0x80, 0x84, 0x80, 0x81, 0x00, 0xa0, |
| 0xa3, 0x01, 0xa0, 0x02, 0xa0, 0x03, 0x80}; |
| |
| int32_t EmptyMapsAndArraysTest() |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(sEmpties), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| // Array with 3 items |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != 0 || |
| Item.uNextNestLevel != 1 || |
| Item.val.uCount != 3) { |
| return -1; |
| } |
| |
| // An integer 0 |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.uNestingLevel != 1 || |
| Item.uNextNestLevel != 1 || |
| Item.val.uint64 != 0) { |
| return -2; |
| } |
| |
| // An empty array |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != 1 || |
| Item.uNextNestLevel != 1 || |
| Item.val.uCount != 0) { |
| return -3; |
| } |
| |
| // An array with 4 items |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != 1 || |
| Item.uNextNestLevel != 2 || |
| Item.val.uCount != 4) { |
| return -4; |
| } |
| |
| // An empty array |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != 2 || |
| Item.uNextNestLevel != 2 || |
| Item.val.uCount != 0) { |
| return -5; |
| } |
| |
| // An array with 1 item |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != 2 || |
| Item.uNextNestLevel != 3 || |
| Item.val.uCount != 1) { |
| return -6; |
| } |
| |
| // An integer 0 |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.uNestingLevel != 3 || |
| Item.uNextNestLevel != 2 || |
| Item.val.uint64 != 0) { |
| return -7; |
| } |
| |
| // An empty map |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_MAP || |
| Item.uNestingLevel != 2 || |
| Item.uNextNestLevel != 2 || |
| Item.val.uCount != 0) { |
| return -8; |
| } |
| |
| // An map with 3 items |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_MAP || |
| Item.uNestingLevel != 2 || |
| Item.uNextNestLevel != 3 || |
| Item.val.uCount != 3) { |
| return -9; |
| } |
| |
| // An empty map |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_MAP || |
| Item.uNestingLevel != 3 || |
| Item.uNextNestLevel != 3 || |
| Item.val.uCount != 0) { |
| return -10; |
| } |
| |
| // An empty map |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_MAP || |
| Item.uNestingLevel != 3 || |
| Item.uNextNestLevel != 3 || |
| Item.val.uCount != 0) { |
| return -11; |
| } |
| |
| // An empty array |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != 3 || |
| Item.uNextNestLevel != 0 || |
| Item.val.uCount != 0) { |
| return -12; |
| } |
| |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_SUCCESS) { |
| return -13; |
| } |
| |
| return 0; |
| } |
| |
| |
| static uint8_t spDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 0x81, 0x81, 0x81, 0x80}; |
| |
| int32_t ParseDeepArrayTest() |
| { |
| QCBORDecodeContext DCtx; |
| int nReturn = 0; |
| int i; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDeepArrays), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| for(i = 0; i < 10; i++) { |
| QCBORItem Item; |
| |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != i) { |
| nReturn = -1; |
| break; |
| } |
| } |
| |
| return(nReturn); |
| } |
| |
| // Big enough to test nesting to the depth of 24 |
| static uint8_t spTooDeepArrays[] = {0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, |
| 0x81, 0x81, 0x81, 0x80}; |
| |
| int32_t ParseTooDeepArrayTest() |
| { |
| QCBORDecodeContext DCtx; |
| int nReturn = 0; |
| int i; |
| QCBORItem Item; |
| |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spTooDeepArrays), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| for(i = 0; i < QCBOR_MAX_ARRAY_NESTING1; i++) { |
| |
| if(QCBORDecode_GetNext(&DCtx, &Item) != 0 || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != i) { |
| nReturn = -1; |
| break; |
| } |
| } |
| |
| if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) |
| nReturn = -1; |
| |
| return(nReturn); |
| } |
| |
| |
| |
| |
| int32_t ShortBufferParseTest() |
| { |
| int nResult = 0; |
| |
| for(size_t nNum = sizeof(spExpectedEncodedInts)-1; nNum; nNum--) { |
| QCBORDecodeContext DCtx; |
| |
| QCBORDecode_Init(&DCtx, |
| (UsefulBufC){spExpectedEncodedInts, nNum}, |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| const int nErr = IntegerValuesParseTestInternal(&DCtx); |
| |
| if(nErr != QCBOR_ERR_HIT_END && nErr != QCBOR_ERR_NO_MORE_ITEMS) { |
| nResult = -1; |
| goto Done; |
| } |
| } |
| Done: |
| return nResult; |
| } |
| |
| |
| |
| int32_t ShortBufferParseTest2() |
| { |
| uint8_t *pEncoded; |
| int nReturn; |
| size_t nEncodedLen; |
| |
| int64_t i1, i2; |
| size_t i3, i4; |
| const uint8_t *s3, *s4; |
| |
| nReturn = 0; |
| |
| if(CreateSimpleArray(23, 6000, &pEncoded, &nEncodedLen) < 0) { |
| return(-1); |
| } |
| |
| for(nEncodedLen--; nEncodedLen; nEncodedLen--) { |
| int nResult = ParseOrderedArray(pEncoded, (uint32_t)nEncodedLen, &i1, &i2, &s3, &i3, &s4, &i4); |
| if(nResult == 0) { |
| nReturn = -1; |
| } |
| } |
| |
| return(nReturn); |
| } |
| |
| /* |
| Decode and thoroughly check a moderately complex |
| set of maps. Can be run in QCBOR_DECODE_MODE_NORMAL or in |
| QCBOR_DECODE_MODE_MAP_STRINGS_ONLY. |
| */ |
| static int32_t ParseMapTest1(QCBORDecodeMode nMode) |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| QCBORDecode_Init(&DCtx, |
| (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, |
| nMode); |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP || |
| Item.val.uCount != 3) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 42 || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) { |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.val.uCount != 2) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) { |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) { |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) || |
| Item.uDataType != QCBOR_TYPE_MAP || |
| Item.val.uCount != 4) { |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1"))|| |
| Item.uDataType != QCBOR_TYPE_BYTE_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) { |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) || |
| Item.uDataType != QCBOR_TYPE_BYTE_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) { |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) || |
| Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 98) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| |
| Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| |
| /* |
| Decode and thoroughly check a moderately complex |
| set of maps |
| */ |
| int32_t ParseMapAsArrayTest() |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), |
| QCBOR_DECODE_MODE_MAP_AS_ARRAY); |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || |
| Item.val.uCount != 6) { |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| Item.uLabelType != QCBOR_TYPE_NONE || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("first integer"))) { |
| return -2; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 42 || |
| Item.uDataAlloc || |
| Item.uLabelAlloc) { |
| return -3; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("an array of two strings")) || |
| Item.uDataType != QCBOR_TYPE_TEXT_STRING) { |
| return -4; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.val.uCount != 2) { |
| return -5; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.val.string.len != 7 || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) { |
| return -6; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) { |
| return -7; |
| } |
| |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("map in a map"))) { |
| return -8; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| Item.uDataType != QCBOR_TYPE_MAP_AS_ARRAY || |
| Item.val.uCount != 8) { |
| return -9; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 1"))|| |
| Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc) { |
| return -10; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataType != QCBOR_TYPE_BYTE_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) { |
| return -11; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("bytes 2")) || |
| Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc) { |
| return -12; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataType != QCBOR_TYPE_BYTE_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) { |
| return -13; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("another int")) || |
| Item.uDataType != QCBOR_TYPE_TEXT_STRING) { |
| return -14; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 98) { |
| return -15; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("text 2"))|| |
| Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc) { |
| return -16; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_NONE || |
| Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataAlloc || |
| Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) { |
| return -17; |
| } |
| |
| |
| /* |
| Test with map that nearly QCBOR_MAX_ITEMS_IN_ARRAY items in a |
| map that when interpreted as an array will be too many. Test |
| data just has the start of the map, not all the items in the map. |
| */ |
| static const uint8_t pTooLargeMap[] = {0xb9, 0xff, 0xfd}; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pTooLargeMap), |
| QCBOR_DECODE_MODE_MAP_AS_ARRAY); |
| |
| if((QCBOR_ERR_ARRAY_TOO_LONG != QCBORDecode_GetNext(&DCtx, &Item))) { |
| return -50; |
| } |
| |
| return 0; |
| } |
| |
| |
| /* |
| Fully or partially decode pValidMapEncoded. When |
| partially decoding check for the right error code. |
| How much partial decoding depends on nLevel. |
| |
| The partial decodes test error conditions of |
| incomplete encoded input. |
| |
| This could be combined with the above test |
| and made prettier and maybe a little more |
| thorough. |
| */ |
| static int32_t ExtraBytesTest(int nLevel) |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| QCBORDecode_Init(&DCtx, |
| (UsefulBufC){pValidMapEncoded, sizeof(pValidMapEncoded)}, |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| if(nLevel < 1) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_EXTRA_BYTES) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP || |
| Item.val.uCount != 3) |
| return -1; |
| |
| if(nLevel < 2) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.uCount != 42 || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("first integer"))) { |
| return -1; |
| } |
| |
| if(nLevel < 3) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("an array of two strings")) || |
| Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.val.uCount != 2) { |
| return -1; |
| } |
| |
| |
| if(nLevel < 4) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string1"))) { |
| return -1; |
| } |
| |
| if(nLevel < 5) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("string2"))) { |
| return -1; |
| } |
| |
| if(nLevel < 6) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("map in a map")) || |
| Item.uDataType != QCBOR_TYPE_MAP || |
| Item.val.uCount != 4) |
| return -1; |
| |
| if(nLevel < 7) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 1")) || |
| Item.uDataType != QCBOR_TYPE_BYTE_STRING || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("xxxx"))) { |
| return -1; |
| } |
| |
| if(nLevel < 8) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("bytes 2")) || |
| Item.uDataType != QCBOR_TYPE_BYTE_STRING || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("yyyy"))) { |
| return -1; |
| } |
| |
| if(nLevel < 9) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("another int")) || |
| Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != 98) |
| return -1; |
| |
| if(nLevel < 10) { |
| if(QCBORDecode_Finish(&DCtx) != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -1; |
| } else { |
| return 0; |
| } |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) { |
| return (int32_t)nCBORError; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("text 2"))|| |
| Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.val.string, UsefulBuf_FromSZ("lies, damn lies and statistics"))) { |
| return -1; |
| } |
| |
| if(QCBORDecode_Finish(&DCtx)) { |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| |
| int32_t ParseMapTest() |
| { |
| // Parse a moderatly complex map structure very thoroughly |
| int32_t nResult = ParseMapTest1(QCBOR_DECODE_MODE_NORMAL); |
| if(nResult) { |
| return nResult; |
| } |
| |
| // Again, but in strings-only mode. It should succeed since the input |
| // map has only string labels. |
| nResult = ParseMapTest1(QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); |
| if(nResult) { |
| return nResult; |
| } |
| |
| // Again, but try to finish the decoding before the end of the |
| // input at 10 different place and see that the right error code |
| // is returned. |
| for(int i = 0; i < 10; i++) { |
| nResult = ExtraBytesTest(i); |
| if(nResult) { |
| break; |
| } |
| } |
| |
| return nResult; |
| } |
| |
| |
| static uint8_t spSimpleValues[] = {0x8a, 0xf4, 0xf5, 0xf6, 0xf7, 0xff, |
| 0xe0, 0xf3, 0xf8, 0x00, 0xf8, 0x13, |
| 0xf8, 0x1f, 0xf8, 0x20, 0xf8, 0xff}; |
| |
| int32_t ParseSimpleTest() |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.val.uCount != 10) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_FALSE) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_TRUE) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_NULL) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_UNDEF) |
| return -1; |
| |
| // A break |
| if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_BREAK) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 0) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 19) |
| return -1; |
| |
| if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) |
| return -1; |
| |
| if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) |
| return -1; |
| |
| if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_BAD_TYPE_7) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 32) |
| return -1; |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_UKNOWN_SIMPLE || Item.val.uSimple != 255) |
| return -1; |
| |
| return 0; |
| |
| } |
| |
| |
| static int IsNotWellFormedError(QCBORError nErr) |
| { |
| switch(nErr){ |
| case QCBOR_ERR_INDEFINITE_STRING_CHUNK: |
| case QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN: |
| case QCBOR_ERR_UNSUPPORTED: |
| case QCBOR_ERR_HIT_END: |
| case QCBOR_ERR_BAD_TYPE_7: |
| case QCBOR_ERR_BAD_BREAK: |
| case QCBOR_ERR_EXTRA_BYTES: |
| case QCBOR_ERR_BAD_INT: |
| return 1; |
| default: |
| return 0; |
| } |
| } |
| |
| |
| int32_t NotWellFormedTests() |
| { |
| // Loop over all the not-well-formed instance of CBOR |
| // that are test vectors in not_well_formed_cbor.h |
| const uint16_t nArraySize = sizeof(paNotWellFormedCBOR)/sizeof(struct someBinaryBytes); |
| for(uint16_t nIterate = 0; nIterate < nArraySize; nIterate++) { |
| const struct someBinaryBytes *pBytes = &paNotWellFormedCBOR[nIterate]; |
| const UsefulBufC Input = (UsefulBufC){pBytes->p, pBytes->n}; |
| |
| // Set up decoder context. String allocator needed for indefinite |
| // string test cases |
| QCBORDecodeContext DCtx; |
| QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); |
| UsefulBuf_MAKE_STACK_UB(Pool, 100); |
| QCBORDecode_SetMemPool(&DCtx, Pool, 0); |
| |
| // Loop getting items until no more to get |
| QCBORError nCBORError; |
| do { |
| QCBORItem Item; |
| |
| nCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| } while(nCBORError == QCBOR_SUCCESS); |
| |
| // Every test vector must fail with |
| // a not-well-formed error. If not |
| // this test fails. |
| if(!IsNotWellFormedError(nCBORError)) { |
| // Return index of failure in the error code |
| return 2000 + nIterate; |
| } |
| } |
| return 0; |
| } |
| |
| |
| struct FailInput { |
| UsefulBufC Input; |
| QCBORError nError; |
| }; |
| |
| |
| static int32_t ProcessFailures(struct FailInput *pFailInputs, size_t nNumFails) |
| { |
| for(struct FailInput *pF = pFailInputs; pF < pFailInputs + nNumFails; pF++) { |
| // Set up the decoding context including a memory pool so that |
| // indefinite length items can be checked |
| QCBORDecodeContext DCtx; |
| QCBORDecode_Init(&DCtx, pF->Input, QCBOR_DECODE_MODE_NORMAL); |
| UsefulBuf_MAKE_STACK_UB(Pool, 100); |
| QCBORError nCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0); |
| if(nCBORError) { |
| return -9; |
| } |
| |
| // Iterate until there is an error of some sort error |
| QCBORItem Item; |
| do { |
| // Set to something none-zero other than QCBOR_TYPE_NONE |
| memset(&Item, 0x33, sizeof(Item)); |
| |
| nCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| } while(nCBORError == QCBOR_SUCCESS); |
| |
| // Must get the expected error or the this test fails |
| // The data and label type must also be QCBOR_TYPE_NONE |
| if(nCBORError != pF->nError || |
| Item.uDataType != QCBOR_TYPE_NONE || |
| Item.uLabelType != QCBOR_TYPE_NONE) { |
| // return index of CBOR + 100 |
| const size_t nIndex = (size_t)(pF - pFailInputs)/sizeof(struct FailInput); |
| return (int32_t)(nIndex * 100 + nCBORError); |
| } |
| } |
| |
| return 0; |
| } |
| |
| |
| struct FailInput Failures[] = { |
| // Most of this is copied from not_well_formed.h. Here the error code |
| // returned is also checked. |
| |
| // Indefinite length strings must be closed off |
| // An indefinite length byte string not closed off |
| { {(uint8_t[]){0x5f, 0x41, 0x00}, 3}, QCBOR_ERR_HIT_END }, |
| // An indefinite length text string not closed off |
| { {(uint8_t[]){0x7f, 0x61, 0x00}, 3}, QCBOR_ERR_HIT_END }, |
| |
| |
| // All the chunks in an indefinite length string must be of the type of indefinite length string |
| // indefinite length byte string with text string chunk |
| { {(uint8_t[]){0x5f, 0x61, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, |
| // indefinite length text string with a byte string chunk |
| { {(uint8_t[]){0x7f, 0x41, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, |
| // indefinite length byte string with an positive integer chunk |
| { {(uint8_t[]){0x5f, 0x00, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, |
| // indefinite length byte string with an negative integer chunk |
| { {(uint8_t[]){0x5f, 0x21, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, |
| // indefinite length byte string with an array chunk |
| { {(uint8_t[]){0x5f, 0x80, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, |
| // indefinite length byte string with an map chunk |
| { {(uint8_t[]){0x5f, 0xa0, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, |
| // indefinite length byte string with tagged integer chunk |
| { {(uint8_t[]){0x5f, 0xc0, 0x00, 0xff}, 4}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, |
| // indefinite length byte string with an simple type chunk |
| { {(uint8_t[]){0x5f, 0xe0, 0xff}, 3}, QCBOR_ERR_INDEFINITE_STRING_CHUNK }, |
| { {(uint8_t[]){0x5f, 0x5f, 0x41, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEFINITE_STRING_CHUNK}, |
| // indefinite length text string with indefinite string inside |
| { {(uint8_t[]){0x7f, 0x7f, 0x61, 0x00, 0xff, 0xff}, 6}, QCBOR_ERR_INDEFINITE_STRING_CHUNK}, |
| |
| |
| // Definte length maps and arrays must be closed by having the right number of items |
| // A definte length array that is supposed to have 1 item, but has none |
| { {(uint8_t[]){0x81}, 1}, QCBOR_ERR_HIT_END }, |
| // A definte length array that is supposed to have 2 items, but has only 1 |
| { {(uint8_t[]){0x82, 0x00}, 2}, QCBOR_ERR_HIT_END }, |
| // A definte length array that is supposed to have 511 items, but has only 1 |
| { {(uint8_t[]){0x9a, 0x01, 0xff, 0x00}, 4}, QCBOR_ERR_HIT_END }, |
| // A definte length map that is supposed to have 1 item, but has none |
| { {(uint8_t[]){0xa1}, 1}, QCBOR_ERR_HIT_END }, |
| // A definte length map that is supposed to have s item, but has only 1 |
| { {(uint8_t[]){0xa2, 0x01, 0x02}, 3}, QCBOR_ERR_HIT_END }, |
| |
| |
| // Indefinte length maps and arrays must be ended by a break |
| // Indefinite length array with zero items and no break |
| { {(uint8_t[]){0x9f}, 1}, QCBOR_ERR_HIT_END }, |
| // Indefinite length array with two items and no break |
| { {(uint8_t[]){0x9f, 0x01, 0x02}, 3}, QCBOR_ERR_HIT_END }, |
| // Indefinite length map with zero items and no break |
| { {(uint8_t[]){0xbf}, 1}, QCBOR_ERR_HIT_END }, |
| // Indefinite length map with two items and no break |
| { {(uint8_t[]){0xbf, 0x01, 0x02, 0x01, 0x02}, 5}, QCBOR_ERR_HIT_END }, |
| |
| |
| // Nested maps and arrays must be closed off (some extra nested test vectors) |
| // Unclosed indefinite array containing a close definite array |
| { {(uint8_t[]){0x9f, 0x80, 0x00}, 3}, QCBOR_ERR_HIT_END }, |
| // Definite length array containing an unclosed indefinite array |
| { {(uint8_t[]){0x81, 0x9f}, 2}, QCBOR_ERR_HIT_END }, |
| // Deeply nested definite length arrays with deepest one unclosed |
| { {(uint8_t[]){0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81, 0x81}, 9}, QCBOR_ERR_HIT_END }, |
| // Deeply nested indefinite length arrays with deepest one unclosed |
| { {(uint8_t[]){0x9f, 0x9f, 0x9f, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_HIT_END }, |
| // Mixed nesting with indefinite unclosed |
| // TODO: think through this one |
| { {(uint8_t[]){0x9f, 0x81, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff}, 9}, QCBOR_ERR_BAD_BREAK }, |
| // Mixed nesting with definite unclosed |
| // TODO: think through this one |
| { {(uint8_t[]){0x9f, 0x82, 0x9f, 0x81, 0x9f, 0x9f, 0xff, 0xff, 0xff, 0xff}, 10}, QCBOR_ERR_BAD_BREAK }, |
| |
| |
| // The "argument" for the data item is incomplete |
| // Positive integer missing 1 byte argument |
| { {(uint8_t[]){0x18}, 1}, QCBOR_ERR_HIT_END }, |
| // Positive integer missing 2 byte argument |
| { {(uint8_t[]){0x19}, 1}, QCBOR_ERR_HIT_END }, |
| // Positive integer missing 4 byte argument |
| { {(uint8_t[]){0x1a}, 1}, QCBOR_ERR_HIT_END }, |
| // Positive integer missing 8 byte argument |
| { {(uint8_t[]){0x1b}, 1}, QCBOR_ERR_HIT_END }, |
| // Positive integer missing 1 byte of 2 byte argument |
| { {(uint8_t[]){0x19, 0x01}, 2}, QCBOR_ERR_HIT_END }, |
| // Positive integer missing 2 bytes of 4 byte argument |
| { {(uint8_t[]){0x1a, 0x01, 0x02}, 3}, QCBOR_ERR_HIT_END }, |
| // Positive integer missing 1 bytes of 7 byte argument |
| { {(uint8_t[]){0x1b, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07}, 8}, QCBOR_ERR_HIT_END }, |
| // Negative integer missing 1 byte argument |
| { {(uint8_t[]){0x38}, 1}, QCBOR_ERR_HIT_END }, |
| // Binary string missing 1 byte argument |
| { {(uint8_t[]){0x58}, 1}, QCBOR_ERR_HIT_END }, |
| // Text string missing 1 byte argument |
| { {(uint8_t[]){0x78}, 1}, QCBOR_ERR_HIT_END }, |
| // Array missing 1 byte argument |
| { {(uint8_t[]){0x98}, 1}, QCBOR_ERR_HIT_END }, |
| // Map missing 1 byte argument |
| { {(uint8_t[]){0xb8}, 1}, QCBOR_ERR_HIT_END }, |
| // Tag missing 1 byte argument |
| { {(uint8_t[]){0xd8}, 1}, QCBOR_ERR_HIT_END }, |
| // Simple missing 1 byte argument |
| { {(uint8_t[]){0xf8}, 1}, QCBOR_ERR_HIT_END }, |
| |
| |
| // Breaks must not occur in definite length arrays and maps |
| // Array of length 1 with sole member replaced by a break |
| { {(uint8_t[]){0x81, 0xff}, 2}, QCBOR_ERR_BAD_BREAK }, |
| // Array of length 2 with 2nd member replaced by a break |
| { {(uint8_t[]){0x82, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, |
| // Map of length 1 with sole member label replaced by a break |
| { {(uint8_t[]){0xa1, 0xff}, 2}, QCBOR_ERR_BAD_BREAK }, |
| // Map of length 1 with sole member label replaced by break |
| // Alternate representation that some decoders handle difference |
| { {(uint8_t[]){0xa1, 0xff, 0x00}, 3}, QCBOR_ERR_BAD_BREAK }, |
| // Array of length 1 with 2nd member value replaced by a break |
| { {(uint8_t[]){0xa1, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, |
| // Map of length 2 with 2nd member replaced by a break |
| { {(uint8_t[]){0xa2, 0x00, 0x00, 0xff}, 4}, QCBOR_ERR_BAD_BREAK }, |
| |
| |
| // Breaks must not occur on their own out of an indefinite length data item |
| // A bare break is not well formed |
| { {(uint8_t[]){0xff}, 1}, QCBOR_ERR_BAD_BREAK }, |
| // A bare break after a zero length definite length array |
| { {(uint8_t[]){0x80, 0xff}, 2}, QCBOR_ERR_BAD_BREAK }, |
| // A bare break after a zero length indefinite length map |
| { {(uint8_t[]){0x9f, 0xff, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, |
| |
| |
| // Forbidden two byte encodings of simple types |
| // Must use 0xe0 instead |
| { {(uint8_t[]){0xf8, 0x00}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xe1 instead |
| { {(uint8_t[]){0xf8, 0x01}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xe2 instead |
| { {(uint8_t[]){0xf8, 0x02}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xe3 instead |
| { {(uint8_t[]){0xf8, 0x03}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xe4 instead |
| { {(uint8_t[]){0xf8, 0x04}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xe5 instead |
| { {(uint8_t[]){0xf8, 0x05}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xe6 instead |
| { {(uint8_t[]){0xf8, 0x06}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xe7 instead |
| { {(uint8_t[]){0xf8, 0x07}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xe8 instead |
| { {(uint8_t[]){0xf8, 0x08}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xe9 instead |
| { {(uint8_t[]){0xf8, 0x09}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xea instead |
| { {(uint8_t[]){0xf8, 0x0a}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xeb instead |
| { {(uint8_t[]){0xf8, 0x0b}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xec instead |
| { {(uint8_t[]){0xf8, 0x0c}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xed instead |
| { {(uint8_t[]){0xf8, 0x0d}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xee instead |
| { {(uint8_t[]){0xf8, 0x0e}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xef instead |
| { {(uint8_t[]){0xf8, 0x0f}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xf0 instead |
| { {(uint8_t[]){0xf8, 0x10}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xf1 instead |
| { {(uint8_t[]){0xf8, 0x11}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Should use 0xf2 instead |
| { {(uint8_t[]){0xf8, 0x12}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Must use 0xf3 instead |
| { {(uint8_t[]){0xf8, 0x13}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Must use 0xf4 instead |
| { {(uint8_t[]){0xf8, 0x14}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Must use 0xf5 instead |
| { {(uint8_t[]){0xf8, 0x15}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Must use 0xf6 instead |
| { {(uint8_t[]){0xf8, 0x16}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Must use 0xf7 instead |
| { {(uint8_t[]){0xf8, 0x17}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| // Must use 0xf8 instead |
| { {(uint8_t[]){0xf8, 0x18}, 2}, QCBOR_ERR_BAD_TYPE_7 }, |
| |
| |
| // Integers with additional info indefinite length |
| // Positive integer with additional info indefinite length |
| { {(uint8_t[]){0x1f}, 1}, QCBOR_ERR_BAD_INT }, |
| // Negative integer with additional info indefinite length |
| { {(uint8_t[]){0x3f}, 1}, QCBOR_ERR_BAD_INT }, |
| // CBOR tag with "argument" an indefinite length |
| { {(uint8_t[]){0xdf, 0x00}, 2}, QCBOR_ERR_BAD_INT }, |
| // CBOR tag with "argument" an indefinite length alternate vector |
| { {(uint8_t[]){0xdf}, 1}, QCBOR_ERR_BAD_INT }, |
| |
| |
| // Missing bytes from a deterministic length string |
| // A byte string is of length 1 without the 1 byte |
| { {(uint8_t[]){0x41}, 1}, QCBOR_ERR_HIT_END }, |
| // A text string is of length 1 without the 1 byte |
| { {(uint8_t[]){0x61}, 1}, QCBOR_ERR_HIT_END }, |
| // Byte string should have 2^32-15 bytes, but has one |
| { {(uint8_t[]){0x5a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, |
| // Byte string should have 2^32-15 bytes, but has one |
| { {(uint8_t[]){0x7a, 0xff, 0xff, 0xff, 0xf0, 0x00}, 6}, QCBOR_ERR_HIT_END }, |
| |
| |
| // Use of unassigned additional information values |
| // Major type positive integer with reserved value 28 |
| { {(uint8_t[]){0x1c}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type positive integer with reserved value 29 |
| { {(uint8_t[]){0x1d}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type positive integer with reserved value 30 |
| { {(uint8_t[]){0x1e}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type negative integer with reserved value 28 |
| { {(uint8_t[]){0x3c}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type negative integer with reserved value 29 |
| { {(uint8_t[]){0x3d}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type negative integer with reserved value 30 |
| { {(uint8_t[]){0x3e}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type byte string with reserved value 28 length |
| { {(uint8_t[]){0x5c}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type byte string with reserved value 29 length |
| { {(uint8_t[]){0x5d}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type byte string with reserved value 30 length |
| { {(uint8_t[]){0x5e}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type text string with reserved value 28 length |
| { {(uint8_t[]){0x7c}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type text string with reserved value 29 length |
| { {(uint8_t[]){0x7d}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type text string with reserved value 30 length |
| { {(uint8_t[]){0x7e}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type array with reserved value 28 length |
| { {(uint8_t[]){0x9c}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type array with reserved value 29 length |
| { {(uint8_t[]){0x9d}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type array with reserved value 30 length |
| { {(uint8_t[]){0x9e}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type map with reserved value 28 length |
| { {(uint8_t[]){0xbc}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type map with reserved value 29 length |
| { {(uint8_t[]){0xbd}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type map with reserved value 30 length |
| { {(uint8_t[]){0xbe}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type tag with reserved value 28 length |
| { {(uint8_t[]){0xdc}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type tag with reserved value 29 length |
| { {(uint8_t[]){0xdd}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type tag with reserved value 30 length |
| { {(uint8_t[]){0xde}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type simple with reserved value 28 length |
| { {(uint8_t[]){0xfc}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type simple with reserved value 29 length |
| { {(uint8_t[]){0xfd}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| // Major type simple with reserved value 30 length |
| { {(uint8_t[]){0xfe}, 1}, QCBOR_ERR_UNSUPPORTED }, |
| |
| |
| // Maps must have an even number of data items (key & value) |
| // Map with 1 item when it should have 2 |
| { {(uint8_t[]){0xa1, 0x00}, 2}, QCBOR_ERR_HIT_END }, |
| // Map with 3 item when it should have 4 |
| { {(uint8_t[]){0xa2, 0x00, 0x00, 0x00}, 2}, QCBOR_ERR_HIT_END }, |
| // Map with 1 item when it should have 2 |
| { {(uint8_t[]){0xbf, 0x00, 0xff}, 3}, QCBOR_ERR_BAD_BREAK }, |
| // Map with 3 item when it should have 4 |
| { {(uint8_t[]){0xbf, 0x00, 0x00, 0x00, 0xff}, 5}, QCBOR_ERR_BAD_BREAK }, |
| |
| |
| // In addition to not-well-formed, some invalid CBOR |
| // Text-based date, with an integer |
| { {(uint8_t[]){0xc0, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, |
| // Epoch date, with an byte string |
| { {(uint8_t[]){0xc1, 0x41, 0x33}, 3}, QCBOR_ERR_BAD_OPT_TAG }, |
| // tagged as both epoch and string dates |
| { {(uint8_t[]){0xc1, 0xc0, 0x00}, 3}, QCBOR_ERR_BAD_OPT_TAG }, |
| // big num tagged an int, not a byte string |
| { {(uint8_t[]){0xc2, 0x00}, 2}, QCBOR_ERR_BAD_OPT_TAG }, |
| }; |
| |
| int32_t DecodeFailureTests() |
| { |
| int32_t nResult; |
| |
| nResult = ProcessFailures(Failures, sizeof(Failures)/sizeof(struct FailInput)); |
| if(nResult) { |
| return nResult; |
| } |
| |
| // Corrupt the UsefulInputBuf and see that |
| // it reflected correctly for CBOR decoding |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spSimpleValues), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return (int32_t)nCBORError; |
| if(Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.val.uCount != 10) { |
| // This wasn't supposed to happen |
| return -1; |
| } |
| |
| DCtx.InBuf.magic = 0; // Reach in and corrupt the UsefulInputBuf |
| |
| nCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(nCBORError != QCBOR_ERR_HIT_END) { |
| // Did not get back the error expected |
| return -2; |
| } |
| } |
| |
| /* |
| This test is disabled until QCBOREncode_EncodeHead() is brought in so |
| the size encoded can be tied to SIZE_MAX and work for all size CPUs. |
| |
| This relies on the largest string allowed being SIZE_MAX -4 rather than |
| SIZE_MAX. That way the test can be performed. |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| |
| static uint8_t foo[] = {0x5b, 0xff, 0xff, 0xff, 0xff, |
| 0xff, 0xff, 0xff, 0xff}; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(foo), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| if(QCBOR_ERR_STRING_TOO_LONG != QCBORDecode_GetNext(&DCtx, &Item)) { |
| return -4; |
| } |
| } |
| */ |
| |
| return 0; |
| } |
| |
| |
| /* Try all 256 values of the byte at nLen including recursing for |
| each of the values to try values at nLen+1 ... up to nLenMax |
| */ |
| static void ComprehensiveInputRecurser(uint8_t *pBuf, size_t nLen, size_t nLenMax) |
| { |
| if(nLen >= nLenMax) { |
| return; |
| } |
| |
| for(int inputByte = 0; inputByte < 256; inputByte++) { |
| // Set up the input |
| pBuf[nLen] = (uint8_t)inputByte; |
| const UsefulBufC Input = {pBuf, nLen+1}; |
| |
| // Get ready to parse |
| QCBORDecodeContext DCtx; |
| QCBORDecode_Init(&DCtx, Input, QCBOR_DECODE_MODE_NORMAL); |
| |
| // Parse by getting the next item until an error occurs |
| // Just about every possible decoder error can occur here |
| // The goal of this test is not to check for the correct |
| // error since that is not really possible. It is to |
| // see that there is no crash on hostile input. |
| while(1) { |
| QCBORItem Item; |
| QCBORError nCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| break; |
| } |
| } |
| |
| ComprehensiveInputRecurser(pBuf, nLen+1, nLenMax); |
| } |
| } |
| |
| |
| int32_t ComprehensiveInputTest() |
| { |
| // Size 2 tests 64K inputs and runs quickly |
| uint8_t pBuf[2]; |
| |
| ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); |
| |
| return 0; |
| } |
| |
| |
| int32_t BigComprehensiveInputTest() |
| { |
| // size 3 tests 16 million inputs and runs OK |
| // in seconds on fast machines. Size 4 takes |
| // 10+ minutes and 5 half a day on fast |
| // machines. This test is kept separate from |
| // the others so as to no slow down the use |
| // of them as a very frequent regression. |
| uint8_t pBuf[3]; // |
| |
| ComprehensiveInputRecurser(pBuf, 0, sizeof(pBuf)); |
| |
| return 0; |
| } |
| |
| |
| static uint8_t spDateTestInput[] = { |
| 0xc0, // tag for string date |
| 0x6a, '1','9','8','5','-','0','4','-','1','2', // Date string |
| |
| 0xc1, // tag for epoch date |
| 0x1a, 0x53, 0x72, 0x4E, 0x00, // Epoch date 1400000000; Tue, 13 May 2014 16:53:20 GMT |
| |
| // CBOR_TAG_B64 |
| 0xc1, 0xcf, 0xd8, 0x22, // 0xee, // Epoch date with extra tags TODO: fix this test |
| 0x1a, 0x53, 0x72, 0x4E, 0x01, |
| |
| 0xc1, // tag for epoch date |
| 0x1b, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, // Too large integer |
| |
| 0xc1, // tag for epoch date |
| 0xfa, 0x3f, 0x8c, 0xcc, 0xcd, // double with value 1.1 |
| |
| 0xc1, // tag for epoch date |
| 0xfa, 0x7f, 0x7f, 0xff, 0xff, // 3.4028234663852886e+38 too large |
| |
| 0xc1, // tag for epoch date |
| 0xfb, 0x43, 0xe0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, // 9223372036854775808.000000 just barely too large |
| //0xfa, 0x7f, 0x7f, 0xff, 0xff // 3.4028234663852886e+38 too large |
| |
| 0xc1, // tag for epoch date |
| 0xfb, 0x43, 0xdf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe // 9223372036854773760 largest supported |
| }; |
| |
| |
| // have to check float expected only to within an epsilon |
| int CHECK_EXPECTED_DOUBLE(double val, double expected) { |
| |
| double diff = val - expected; |
| |
| diff = fabs(diff); |
| |
| return diff > 0.0000001; |
| } |
| |
| |
| int32_t DateParseTest() |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| const uint64_t uTags[] = {15}; |
| QCBORTagListIn TagList = {1, uTags}; |
| |
| QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); |
| |
| // String date |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -1; |
| if(Item.uDataType != QCBOR_TYPE_DATE_STRING || |
| UsefulBuf_Compare(Item.val.dateString, UsefulBuf_FromSZ("1985-04-12"))){ |
| return -2; |
| } |
| |
| // Epoch date |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -3; |
| if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || |
| Item.val.epochDate.nSeconds != 1400000000 || |
| Item.val.epochDate.fSecondsFraction != 0 ) { |
| return -4; |
| } |
| |
| // Epoch date with extra CBOR_TAG_B64 tag that doesn't really mean anything |
| // but want to be sure extra tag doesn't cause a problem |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -5; |
| if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || |
| Item.val.epochDate.nSeconds != 1400000001 || |
| Item.val.epochDate.fSecondsFraction != 0 || |
| !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_B64)) { |
| return -6; |
| } |
| |
| // Epoch date that is too large for our representation |
| if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { |
| return -7; |
| } |
| |
| // Epoch date in float format with fractional seconds |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -8; |
| if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH || |
| Item.val.epochDate.nSeconds != 1 || |
| CHECK_EXPECTED_DOUBLE(Item.val.epochDate.fSecondsFraction, 0.1 )) { |
| return -9; |
| } |
| |
| // Epoch date float that is too large for our representation |
| if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { |
| return -10; |
| } |
| |
| // Epoch date double that is just slightly too large |
| if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_ERR_DATE_OVERFLOW) { |
| return -11; |
| } |
| |
| // Largest double epoch date supported |
| if(QCBORDecode_GetNext(&DCtx, &Item) != QCBOR_SUCCESS || |
| Item.uDataType != QCBOR_TYPE_DATE_EPOCH || |
| Item.val.epochDate.nSeconds != 9223372036854773760 || |
| Item.val.epochDate.nSeconds == 0) { |
| return -12; |
| } |
| // TODO: could use a few more tests with float, double, and half precsion |
| // and negative (but coverage is still pretty good) |
| |
| return 0; |
| } |
| |
| // Really simple basic input for tagging test |
| static uint8_t spOptTestInput[] = { |
| 0xd9, 0xd9, 0xf7, // CBOR magic number |
| 0x81, // Array of one |
| 0xd8, 0x04, // non-preferred serialization of tag 4 |
| 0x82, 0x01, 0x03}; // fraction 1/3 |
| |
| /* |
| DB 9192939495969798 # tag(10489608748473423768) |
| 80 # array(0) |
| */ |
| static uint8_t spEncodedLargeTag[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, |
| 0x96, 0x97, 0x98, 0x80}; |
| |
| /* |
| DB 9192939495969798 # tag(10489608748473423768) |
| D8 88 # tag(136) |
| C6 # tag(6) |
| C7 # tag(7) |
| 80 # array(0) |
| */ |
| static uint8_t spLotsOfTags[] = {0xdb, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, |
| 0x97, 0x98, 0xd8, 0x88, 0xc6, 0xc7, 0x80}; |
| |
| /* |
| The cbor.me parse of this. |
| 55799(55799(55799({6(7(-23)): 5859837686836516696(7({7(-20): 11({17(-18): 17(17(17("Organization"))), |
| 9(-17): 773("SSG"), -15: 16(17(6(7(8(9(10(11(12(13(14(15("Confusion")))))))))))), 17(-16): 17("San Diego"), |
| 17(-14): 17("US")}), 23(-19): 19({-11: 9({-9: -7}), |
| 90599561(90599561(90599561(-10))): 12(h'0102030405060708090A')})})), |
| 16(-22): 23({11(8(7(-5))): 8(-3)})}))) |
| */ |
| static uint8_t spCSRWithTags[] = { |
| 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xd9, 0xd9, 0xf7, 0xa2, |
| 0xc6, 0xc7, 0x36, |
| 0xdb, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0xc7, 0xa2, |
| 0xda, 0x00, 0x00, 0x00, 0x07, 0x33, |
| 0xcb, 0xa5, |
| 0xd1, 0x31, |
| 0xd1, 0xd1, 0xd1, 0x6c, |
| 0x4f, 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, 0x69, 0x6f, 0x6e, |
| 0xc9, 0x30, |
| 0xd9, 0x03, 0x05, 0x63, |
| 0x53, 0x53, 0x47, |
| 0x2e, |
| 0xd0, 0xd1, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0x69, |
| 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, 0x69, 0x6f, 0x6e, |
| 0xd1, 0x2f, |
| 0xd1, 0x69, |
| 0x53, 0x61, 0x6e, 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, |
| 0xd1, 0x2d, |
| 0xd1, 0x62, |
| 0x55, 0x53, |
| 0xd7, 0x32, |
| 0xd3, 0xa2, |
| 0x2a, |
| 0xc9, 0xa1, |
| 0x28, |
| 0x26, |
| 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0xda, 0x05, 0x66, 0x70, 0x89, 0x29, |
| 0xcc, 0x4a, |
| 0x01, 0x02, 0x03, 0x04, 0x05, 0x06,0x07, 0x08, 0x09, 0x0a, |
| 0xd0, 0x35, |
| 0xd7, 0xa1, |
| 0xcb, 0xc8, 0xc7, 0x24, |
| 0xc8, 0x22}; |
| |
| static int32_t CheckCSRMaps(QCBORDecodeContext *pDC); |
| |
| |
| int32_t OptTagParseTest() |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spOptTestInput), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| //------------------------- |
| // This text matches the magic number tag and the fraction tag |
| if(QCBORDecode_GetNext(&DCtx, &Item)) { |
| return -2; |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY || |
| !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC)) { |
| return -3; |
| } |
| |
| if(QCBORDecode_GetNext(&DCtx, &Item)) { |
| return -4; |
| } |
| |
| #ifdef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA |
| if(Item.uDataType != QCBOR_TYPE_ARRAY || |
| !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DECIMAL_FRACTION) || |
| Item.val.uCount != 2) { |
| return -5; |
| } |
| #else |
| if(Item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION) { |
| return -6; |
| } |
| #endif |
| |
| // -------------------------------- |
| // This test decodes the very large tag, but it is not in |
| // any list so it is ignored. |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), |
| QCBOR_DECODE_MODE_NORMAL); |
| if(QCBORDecode_GetNext(&DCtx, &Item)) { |
| return -6; |
| } |
| if(Item.uTagBits) { |
| return -7; |
| } |
| |
| // ---------------------------------- |
| // This test sets up a caller-config list that includes the very large |
| // tage and then matches it. |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), |
| QCBOR_DECODE_MODE_NORMAL); |
| const uint64_t puList[] = {0x9192939495969798, 257}; |
| const QCBORTagListIn TL = {2, puList}; |
| QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TL); |
| |
| if(QCBORDecode_GetNext(&DCtx, &Item)) { |
| return -8; |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY || |
| !QCBORDecode_IsTagged(&DCtx, &Item, 0x9192939495969798) || |
| QCBORDecode_IsTagged(&DCtx, &Item, 257) || |
| QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_BIGFLOAT) || |
| Item.val.uCount != 0) { |
| return -9; |
| } |
| |
| //------------------------ |
| // Sets up a caller-configured list and look up something not in it |
| const uint64_t puLongList[17] = {1,2,1}; |
| const QCBORTagListIn TLLong = {17, puLongList}; |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spEncodedLargeTag), |
| QCBOR_DECODE_MODE_NORMAL); |
| QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TLLong); |
| if(QCBORDecode_GetNext(&DCtx, &Item)) { |
| return -11; |
| } |
| |
| // ----------------------- |
| // This tests retrievel of the full tag list |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), |
| QCBOR_DECODE_MODE_NORMAL); |
| uint64_t puTags[16]; |
| QCBORTagListOut Out = {0, 4, puTags}; |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -12; |
| } |
| if(puTags[0] != 0x9192939495969798 || |
| puTags[1] != 0x88 || |
| puTags[2] != 0x06 || |
| puTags[3] != 0x07) { |
| return -13; |
| } |
| |
| // ---------------------- |
| // This text if too small of an out list |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spLotsOfTags), |
| QCBOR_DECODE_MODE_NORMAL); |
| QCBORTagListOut OutSmall = {0, 3, puTags}; |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &OutSmall) != QCBOR_ERR_TOO_MANY_TAGS) { |
| return -14; |
| } |
| |
| // --------------- |
| // Parse a version of the "CSR" that has had a ton of tags randomly inserted |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), |
| QCBOR_DECODE_MODE_NORMAL); |
| int n = CheckCSRMaps(&DCtx); |
| if(n) { |
| return n-2000; |
| } |
| |
| Out = (QCBORTagListOut){0, 16, puTags}; |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRWithTags), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| const uint64_t puTagList[] = {773, 1, 90599561}; |
| const QCBORTagListIn TagList = {3, puTagList}; |
| QCBORDecode_SetCallerConfiguredTagList(&DCtx, &TagList); |
| |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -100; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP || |
| !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || |
| QCBORDecode_IsTagged(&DCtx, &Item, 90599561) || |
| QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_DATE_EPOCH) || |
| Item.val.uCount != 2 || |
| puTags[0] != CBOR_TAG_CBOR_MAGIC || |
| puTags[1] != CBOR_TAG_CBOR_MAGIC || |
| puTags[2] != CBOR_TAG_CBOR_MAGIC || |
| Out.uNumUsed != 3) { |
| return -101; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -102; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP || |
| QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_CBOR_MAGIC) || |
| QCBORDecode_IsTagged(&DCtx, &Item, 6) || |
| QCBORDecode_IsTagged(&DCtx, &Item, 7) || // item is tagged 7, but 7 is not configured to be recognized |
| Item.val.uCount != 2 || |
| puTags[0] != 5859837686836516696 || |
| puTags[1] != 7 || |
| Out.uNumUsed != 2) { |
| return -103; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -104; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP || |
| Item.uTagBits || |
| Item.val.uCount != 5 || |
| puTags[0] != 0x0b || |
| Out.uNumUsed != 1) { |
| return -105; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -106; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_COSE_MAC0) || |
| Item.val.string.len != 12 || |
| puTags[0] != CBOR_TAG_COSE_MAC0 || |
| puTags[1] != CBOR_TAG_COSE_MAC0 || |
| puTags[2] != CBOR_TAG_COSE_MAC0 || |
| Out.uNumUsed != 3) { |
| return -105; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -107; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| !QCBORDecode_IsTagged(&DCtx, &Item, 773) || |
| Item.val.string.len != 3 || |
| puTags[0] != 773 || |
| Out.uNumUsed != 1) { |
| return -108; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -109; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| !QCBORDecode_IsTagged(&DCtx, &Item, 16) || |
| Item.val.string.len != 9 || |
| puTags[0] != 16 || |
| puTags[11] != 0x0f || |
| Out.uNumUsed != 12) { |
| return -110; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -111; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| !QCBORDecode_IsTagged(&DCtx, &Item, 17) || |
| Item.val.string.len != 9 || |
| puTags[0] != 17 || |
| Out.uNumUsed != 1) { |
| return -112; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -111; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| !QCBORDecode_IsTagged(&DCtx, &Item, 17) || |
| Item.val.string.len != 2 || |
| puTags[0] != 17 || |
| Out.uNumUsed != 1) { |
| return -112; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -113; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP || |
| QCBORDecode_IsTagged(&DCtx, &Item, 19) || |
| Item.val.uCount != 2 || |
| puTags[0] != 19 || |
| Out.uNumUsed != 1) { |
| return -114; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -115; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP || |
| QCBORDecode_IsTagged(&DCtx, &Item, 9) || |
| Item.uTagBits || |
| Item.val.uCount != 1 || |
| puTags[0] != 9 || |
| Out.uNumUsed != 1) { |
| return -116; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -116; |
| } |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.val.int64 != -7 || |
| Item.uTagBits || |
| Out.uNumUsed != 0) { |
| return -117; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -118; |
| } |
| if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || |
| Item.val.string.len != 10 || |
| Item.uTagBits || |
| puTags[0] != 12 || |
| Out.uNumUsed != 1) { |
| return -119; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -120; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP || |
| !QCBORDecode_IsTagged(&DCtx, &Item, CBOR_TAG_ENC_AS_B16) || |
| Item.val.uCount != 1 || |
| puTags[0] != 0x17 || |
| Out.uNumUsed != 1) { |
| return -121; |
| } |
| |
| if(QCBORDecode_GetNextWithTags(&DCtx, &Item, &Out)) { |
| return -122; |
| } |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| QCBORDecode_IsTagged(&DCtx, &Item, 8) || |
| Item.val.int64 != -3 || |
| puTags[0] != 8 || |
| Out.uNumUsed != 1) { |
| return -123; |
| } |
| |
| if(QCBORDecode_Finish(&DCtx)) { |
| return -124; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| |
| static uint8_t spBigNumInput[] = { |
| 0x83, |
| 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0xA4, |
| 0x63, 0x42, 0x4E, 0x2B, |
| 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x18, 0x40, |
| 0xC2, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x63, 0x42, 0x4E, 0x2D, |
| 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, |
| 0x38, 0x3F, |
| 0xC3, 0x49, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| |
| |
| static uint8_t spBigNum[] = {0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}; |
| |
| |
| int32_t BignumParseTest() |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumInput), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| |
| // |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -1; |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -1; |
| } |
| |
| // |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -1; |
| if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || |
| UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ |
| return -1; |
| } |
| |
| // |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -1; |
| if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || |
| UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ |
| return -1; |
| } |
| |
| // |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -1; |
| if(Item.uDataType != QCBOR_TYPE_MAP) { |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -1; |
| if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || |
| Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -1; |
| if(Item.uDataType != QCBOR_TYPE_POSBIGNUM || |
| Item.uLabelType != QCBOR_TYPE_INT64 || |
| Item.label.int64 != 64 || |
| UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -1; |
| if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || |
| Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ |
| return -1; |
| } |
| |
| if((nCBORError = QCBORDecode_GetNext(&DCtx, &Item))) |
| return -1; |
| if(Item.uDataType != QCBOR_TYPE_NEGBIGNUM || |
| Item.uLabelType != QCBOR_TYPE_INT64 || |
| Item.label.int64 != -64 || |
| UsefulBuf_Compare(Item.val.bigNum, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNum))){ |
| return -1; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| static int32_t CheckItemWithIntLabel(QCBORDecodeContext *pCtx, |
| uint8_t uDataType, |
| uint8_t uNestingLevel, |
| uint8_t uNextNest, |
| int64_t nLabel, |
| QCBORItem *pItem) |
| { |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| if((nCBORError = QCBORDecode_GetNext(pCtx, &Item))) return -1; |
| if(Item.uDataType != uDataType) return -1; |
| if(uNestingLevel > 0) { |
| if(Item.uLabelType != QCBOR_TYPE_INT64 && |
| Item.uLabelType != QCBOR_TYPE_UINT64) { |
| return -1; |
| } |
| if(Item.uLabelType == QCBOR_TYPE_INT64) { |
| if(Item.label.int64 != nLabel) return -1; |
| } else { |
| if(Item.label.uint64 != (uint64_t)nLabel) return -1; |
| } |
| } |
| if(Item.uNestingLevel != uNestingLevel) return -1; |
| if(Item.uNextNestLevel != uNextNest) return -1; |
| |
| if(pItem) { |
| *pItem = Item; |
| } |
| return 0; |
| } |
| |
| |
| // Same code checks definite and indefinite length versions of the map |
| static int32_t CheckCSRMaps(QCBORDecodeContext *pDC) |
| { |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 0, 1, 0, NULL)) return -1; |
| |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -23, NULL)) return -1; |
| |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -20, NULL)) return -1; |
| |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -18, NULL)) return -1; |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -17, NULL)) return -1; |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -15, NULL)) return -1; |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 3, -16, NULL)) return -1; |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_TEXT_STRING, 3, 2, -14, NULL)) return -1; |
| |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 2, 3, -19, NULL)) return -1; |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 3, 4, -11, NULL)) return -1; |
| |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 4, 3, -9, NULL)) return -1; |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_BYTE_STRING, 3, 1, -10, NULL)) return -1; |
| |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_MAP, 1, 2, -22, NULL)) return -1; |
| if(CheckItemWithIntLabel(pDC, QCBOR_TYPE_INT64, 2, 0, -5, NULL)) return -1; |
| |
| if(QCBORDecode_Finish(pDC)) return -2; |
| |
| return 0; |
| } |
| |
| |
| /* |
| // cbor.me decoded output |
| { |
| -23: { |
| -20: { |
| -18: "Organization", |
| -17: "SSG", |
| -15: "Confusion", |
| -16: "San Diego", |
| -14: "US" |
| }, |
| -19: { |
| -11: { |
| -9: -7 |
| }, |
| -10: '\u0001\u0002\u0003\u0004\u0005\u0006\a\b\t\n' |
| } |
| }, |
| -22: { |
| -5: -3 |
| } |
| } |
| */ |
| |
| |
| static uint8_t spCSRInput[] = { |
| 0xa2, 0x36, 0xa2, 0x33, 0xa5, 0x31, 0x6c, 0x4f, |
| 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, |
| 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, |
| 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, |
| 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, |
| 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, |
| 0x55, 0x53, 0x32, 0xa2, 0x2a, 0xa1, 0x28, 0x26, |
| 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, |
| 0x07, 0x08, 0x09, 0x0a, 0x35, 0xa1, 0x24, 0x22}; |
| |
| int32_t NestedMapTest() |
| { |
| QCBORDecodeContext DCtx; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| return CheckCSRMaps(&DCtx); |
| } |
| |
| |
| |
| int32_t StringDecoderModeFailTest() |
| { |
| QCBORDecodeContext DCtx; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), |
| QCBOR_DECODE_MODE_MAP_STRINGS_ONLY); |
| |
| QCBORItem Item; |
| QCBORError nCBORError; |
| |
| if(QCBORDecode_GetNext(&DCtx, &Item)) { |
| return -1; |
| } |
| if(Item.uDataType != QCBOR_TYPE_MAP) { |
| return -2; |
| } |
| |
| nCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(nCBORError != QCBOR_ERR_MAP_LABEL_TYPE) { |
| return -3; |
| } |
| |
| return 0; |
| } |
| |
| |
| // Same map as above, but using indefinite lengths |
| static uint8_t spCSRInputIndefLen[] = { |
| 0xbf, 0x36, 0xbf, 0x33, 0xbf, 0x31, 0x6c, 0x4f, |
| 0x72, 0x67, 0x61, 0x6e, 0x69, 0x7a, 0x61, 0x74, |
| 0x69, 0x6f, 0x6e, 0x30, 0x63, 0x53, 0x53, 0x47, |
| 0x2e, 0x69, 0x43, 0x6f, 0x6e, 0x66, 0x75, 0x73, |
| 0x69, 0x6f, 0x6e, 0x2f, 0x69, 0x53, 0x61, 0x6e, |
| 0x20, 0x44, 0x69, 0x65, 0x67, 0x6f, 0x2d, 0x62, |
| 0x55, 0x53, 0xff, 0x32, 0xbf, 0x2a, 0xbf, 0x28, |
| 0x26, 0xff, 0x29, 0x4a, 0x01, 0x02, 0x03, 0x04, |
| 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0xff, 0xff, |
| 0x35, 0xbf, 0x24, 0x22, 0xff, 0xff}; |
| |
| int32_t NestedMapTestIndefLen() |
| { |
| QCBORDecodeContext DCtx; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInputIndefLen), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| return CheckCSRMaps(&DCtx); |
| } |
| |
| |
| |
| static UsefulBufC make_nested_indefinite_arrays(int n, UsefulBuf Storage) |
| { |
| UsefulOutBuf UOB; |
| UsefulOutBuf_Init(&UOB, Storage); |
| |
| int i; |
| for(i = 0; i < n; i++) { |
| UsefulOutBuf_AppendByte(&UOB, 0x9f); |
| } |
| |
| for(i = 0; i < n; i++) { |
| UsefulOutBuf_AppendByte(&UOB, 0xff); |
| } |
| return UsefulOutBuf_OutUBuf(&UOB); |
| } |
| |
| |
| static int32_t parse_indeflen_nested(UsefulBufC Nested, int nNestLevel) |
| { |
| QCBORDecodeContext DC; |
| QCBORDecode_Init(&DC, Nested, 0); |
| |
| int j; |
| for(j = 0; j < nNestLevel; j++) { |
| QCBORItem Item; |
| QCBORError nReturn = QCBORDecode_GetNext(&DC, &Item); |
| if(j >= QCBOR_MAX_ARRAY_NESTING) { |
| // Should be in error |
| if(nReturn != QCBOR_ERR_ARRAY_NESTING_TOO_DEEP) { |
| return -4; |
| } else { |
| return 0; // Decoding doesn't recover after an error |
| } |
| } else { |
| // Should be no error |
| if(nReturn) { |
| return -9; // Should not have got an error |
| } |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -7; |
| } |
| } |
| QCBORError nReturn = QCBORDecode_Finish(&DC); |
| if(nReturn) { |
| return -3; |
| } |
| return 0; |
| } |
| |
| |
| int32_t IndefiniteLengthNestTest() |
| { |
| UsefulBuf_MAKE_STACK_UB(Storage, 50); |
| int i; |
| for(i=1; i < QCBOR_MAX_ARRAY_NESTING+4; i++) { |
| const UsefulBufC Nested = make_nested_indefinite_arrays(i, Storage); |
| int nReturn = parse_indeflen_nested(Nested, i); |
| if(nReturn) { |
| return nReturn; |
| } |
| } |
| return 0; |
| } |
| |
| |
| // [1, [2, 3]] |
| static const uint8_t spIndefiniteArray[] = {0x9f, 0x01, 0x82, 0x02, 0x03, 0xff}; |
| // No closing break |
| static const uint8_t spIndefiniteArrayBad1[] = {0x9f}; |
| // Not enough closing breaks |
| static const uint8_t spIndefiniteArrayBad2[] = {0x9f, 0x9f, 0x02, 0xff}; |
| // Too many closing breaks |
| static const uint8_t spIndefiniteArrayBad3[] = {0x9f, 0x02, 0xff, 0xff}; |
| // Unclosed indeflen inside def len |
| static const uint8_t spIndefiniteArrayBad4[] = {0x81, 0x9f}; |
| // confused tag |
| static const uint8_t spIndefiniteArrayBad5[] = {0x9f, 0xd1, 0xff}; |
| |
| int32_t IndefiniteLengthArrayMapTest() |
| { |
| QCBORError nResult; |
| // --- first test ----- |
| UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArray); |
| |
| // Decode it and see if it is OK |
| UsefulBuf_MAKE_STACK_UB(MemPool, 150); |
| QCBORDecodeContext DC; |
| QCBORItem Item; |
| QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); |
| |
| QCBORDecode_SetMemPool(&DC, MemPool, false); |
| |
| QCBORDecode_GetNext(&DC, &Item); |
| |
| if(Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != 0 || |
| Item.uNextNestLevel != 1) { |
| return -111; |
| } |
| |
| QCBORDecode_GetNext(&DC, &Item); |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.uNestingLevel != 1 || |
| Item.uNextNestLevel != 1) { |
| return -2; |
| } |
| |
| QCBORDecode_GetNext(&DC, &Item); |
| if(Item.uDataType != QCBOR_TYPE_ARRAY || |
| Item.uNestingLevel != 1 || |
| Item.uNextNestLevel != 2) { |
| return -3; |
| } |
| |
| QCBORDecode_GetNext(&DC, &Item); |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.uNestingLevel != 2 || |
| Item.uNextNestLevel != 2) { |
| return -4; |
| } |
| |
| QCBORDecode_GetNext(&DC, &Item); |
| if(Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.uNestingLevel != 2 || |
| Item.uNextNestLevel != 0) { |
| return -5; |
| } |
| |
| if(QCBORDecode_Finish(&DC)) { |
| return -6; |
| } |
| |
| // --- next test ----- |
| IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad1); |
| |
| QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); |
| |
| QCBORDecode_SetMemPool(&DC, MemPool, false); |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -7; |
| } |
| |
| nResult = QCBORDecode_Finish(&DC); |
| if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -8; |
| } |
| |
| |
| // --- next test ----- |
| IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad2); |
| |
| QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); |
| |
| QCBORDecode_SetMemPool(&DC, MemPool, false); |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -9; |
| } |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -10; |
| } |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult || Item.uDataType != QCBOR_TYPE_INT64) { |
| return -11; |
| } |
| |
| nResult = QCBORDecode_Finish(&DC); |
| if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -12; |
| } |
| |
| |
| // --- next test ----- |
| IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad3); |
| |
| QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); |
| |
| QCBORDecode_SetMemPool(&DC, MemPool, false); |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -13; |
| } |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult != QCBOR_ERR_BAD_BREAK) { |
| return -14; |
| } |
| |
| |
| // --- next test ----- |
| IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad4); |
| |
| QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); |
| |
| QCBORDecode_SetMemPool(&DC, MemPool, false); |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -15; |
| } |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -16; |
| } |
| |
| nResult = QCBORDecode_Finish(&DC); |
| if(nResult != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return -17; |
| } |
| |
| // --- next test ----- |
| IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteArrayBad5); |
| |
| QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); |
| |
| QCBORDecode_SetMemPool(&DC, MemPool, false); |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult || Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -18; |
| } |
| |
| nResult = QCBORDecode_GetNext(&DC, &Item); |
| if(nResult != QCBOR_ERR_BAD_BREAK) { |
| return -19; |
| } |
| |
| return 0; |
| } |
| |
| |
| static const uint8_t spIndefiniteLenString[] = { |
| 0x81, // Array of length one |
| 0x7f, // text string marked with indefinite length |
| 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment |
| 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment |
| 0xff // ending break |
| }; |
| |
| static const uint8_t spIndefiniteLenStringBad2[] = { |
| 0x81, // Array of length one |
| 0x7f, // text string marked with indefinite length |
| 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment |
| 0x44, 0x6d, 0x69, 0x6e, 0x67, // second segment of wrong type |
| 0xff // ending break |
| }; |
| |
| static const uint8_t spIndefiniteLenStringBad3[] = { |
| 0x81, // Array of length one |
| 0x7f, // text string marked with indefinite length |
| 0x01, 0x02, // Not a string |
| 0xff // ending break |
| }; |
| |
| static const uint8_t spIndefiniteLenStringBad4[] = { |
| 0x81, // Array of length one |
| 0x7f, // text string marked with indefinite length |
| 0x65, 0x73, 0x74, 0x72, 0x65, 0x61, // first segment |
| 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment |
| // missing end of string |
| }; |
| |
| static const uint8_t spIndefiniteLenStringLabel[] = { |
| 0xa1, // Array of length one |
| 0x7f, // text string marked with indefinite length |
| 0x65, 0x73, 0x74, 0x72, 0x75, 0x75, // first segment |
| 0x64, 0x6d, 0x69, 0x6e, 0x67, // second segment |
| 0xff, // ending break |
| 0x01 // integer being labeled. |
| }; |
| |
| /** |
| Make an indefinite length string |
| |
| @param Storage Storage for string, must be 144 bytes in size |
| @return The indefinite length string |
| |
| This makes an array with one indefinite length string that has 7 chunks |
| from size of 1 byte up to 64 bytes. |
| */ |
| static UsefulBufC MakeIndefiniteBigBstr(UsefulBuf Storage) |
| { |
| UsefulOutBuf UOB; |
| |
| UsefulOutBuf_Init(&UOB, Storage); |
| UsefulOutBuf_AppendByte(&UOB, 0x81); |
| UsefulOutBuf_AppendByte(&UOB, 0x5f); |
| |
| uint8_t uStringByte = 0; |
| // Use of type int is intentional |
| for(int uChunkSize = 1; uChunkSize <= 128; uChunkSize *= 2) { |
| // Not using preferred encoding here, but that is OK. |
| UsefulOutBuf_AppendByte(&UOB, 0x58); |
| UsefulOutBuf_AppendByte(&UOB, (uint8_t)uChunkSize); |
| for(int j = 0; j < uChunkSize; j++) { |
| UsefulOutBuf_AppendByte(&UOB, uStringByte); |
| uStringByte++; |
| } |
| } |
| UsefulOutBuf_AppendByte(&UOB, 0xff); |
| |
| return UsefulOutBuf_OutUBuf(&UOB); |
| } |
| |
| static int CheckBigString(UsefulBufC BigString) |
| { |
| if(BigString.len != 255) { |
| return 1; |
| } |
| |
| for(uint8_t i = 0; i < 255; i++){ |
| if(((const uint8_t *)BigString.ptr)[i] != i) { |
| return 1; |
| } |
| } |
| return 0; |
| } |
| |
| |
| int32_t IndefiniteLengthStringTest() |
| { |
| QCBORDecodeContext DC; |
| QCBORItem Item; |
| // big enough for MakeIndefiniteBigBstr() + MemPool overhead |
| UsefulBuf_MAKE_STACK_UB(MemPool, 350); |
| |
| // --- Simple normal indefinite length string ------ |
| UsefulBufC IndefLen = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenString); |
| QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); |
| |
| if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { |
| return -1; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item)) { |
| return -2; |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { |
| return -3; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item)) { |
| return -4; |
| } |
| if(Item.uDataType != QCBOR_TYPE_TEXT_STRING || !Item.uDataAlloc) { |
| return -5; |
| } |
| if(QCBORDecode_Finish(&DC)) { |
| return -6; |
| } |
| |
| // ----- types mismatch --- |
| QCBORDecode_Init(&DC, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad2), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { |
| return -7; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item)) { |
| return -8; |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -9; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { |
| return -10; |
| } |
| |
| // ----- not a string --- |
| QCBORDecode_Init(&DC, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad3), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { |
| return -11; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item)) { |
| return -12; |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -13; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_INDEFINITE_STRING_CHUNK) { |
| return -14; |
| } |
| |
| // ----- no end ----- |
| QCBORDecode_Init(&DC, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringBad4), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { |
| return -15; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item)) { |
| return -16; |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -17; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_HIT_END) { |
| return -18; |
| } |
| |
| // ------ Don't set a string allocator and see an error ----- |
| QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); |
| |
| QCBORDecode_GetNext(&DC, &Item); |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -19; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_NO_STRING_ALLOCATOR) { |
| return -20; |
| } |
| |
| // ----- Mempool is way too small ----- |
| UsefulBuf_MAKE_STACK_UB(MemPoolTooSmall, QCBOR_DECODE_MIN_MEM_POOL_SIZE-1); |
| |
| QCBORDecode_Init(&DC, IndefLen, QCBOR_DECODE_MODE_NORMAL); |
| if(!QCBORDecode_SetMemPool(&DC, MemPoolTooSmall, false)) { |
| return -21; |
| } |
| |
| // ----- Mempool is way too small ----- |
| UsefulBuf_MAKE_STACK_UB(BigIndefBStrStorage, 290); |
| const UsefulBufC BigIndefBStr = MakeIndefiniteBigBstr(BigIndefBStrStorage); |
| |
| // 80 is big enough for MemPool overhead, but not BigIndefBStr |
| UsefulBuf_MAKE_STACK_UB(MemPoolSmall, 80); |
| |
| QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); |
| if(QCBORDecode_SetMemPool(&DC, MemPoolSmall, false)) { |
| return -22; |
| } |
| |
| QCBORDecode_GetNext(&DC, &Item); |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return -23; |
| } |
| if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_ERR_STRING_ALLOCATE) { |
| return -24; |
| } |
| |
| // ---- big bstr ----- |
| QCBORDecode_Init(&DC, BigIndefBStr, QCBOR_DECODE_MODE_NORMAL); |
| |
| if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { |
| return -25; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item)) { |
| return -26; |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY || Item.uDataAlloc) { |
| return -26; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item)) { |
| return -27; |
| } |
| if(Item.uDataType != QCBOR_TYPE_BYTE_STRING || !Item.uDataAlloc || Item.uNestingLevel != 1) { |
| return -28; |
| } |
| if(CheckBigString(Item.val.string)) { |
| return -3; |
| } |
| if(QCBORDecode_Finish(&DC)) { |
| return -29; |
| } |
| |
| // --- label is an indefinite length string ------ |
| QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spIndefiniteLenStringLabel), QCBOR_DECODE_MODE_NORMAL); |
| |
| if(QCBORDecode_SetMemPool(&DC, MemPool, false)) { |
| return -30; |
| } |
| |
| QCBORDecode_GetNext(&DC, &Item); |
| if(Item.uDataType != QCBOR_TYPE_MAP) { |
| return -31; |
| } |
| |
| if(QCBORDecode_GetNext(&DC, &Item)){ |
| return -32; |
| } |
| if(Item.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| Item.uDataType != QCBOR_TYPE_INT64 || |
| Item.uDataAlloc || !Item.uLabelAlloc || |
| UsefulBuf_Compare(Item.label.string, UsefulBuf_FromSZ("struuming"))) { |
| return -33; |
| } |
| |
| if(QCBORDecode_Finish(&DC)) { |
| return -34; |
| } |
| |
| return 0; |
| } |
| |
| |
| int32_t AllocAllStringsTest() |
| { |
| QCBORDecodeContext DC; |
| QCBORError nCBORError; |
| |
| |
| // First test, use the "CSRMap" as easy input and checking |
| QCBORDecode_Init(&DC, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spCSRInput), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| UsefulBuf_MAKE_STACK_UB(Pool, sizeof(spCSRInput) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); |
| |
| nCBORError = QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. |
| if(nCBORError) { |
| return -1; |
| } |
| |
| if(CheckCSRMaps(&DC)) { |
| return -2; |
| } |
| |
| // Next parse, save pointers to a few strings, destroy original and see all is OK. |
| UsefulBuf_MAKE_STACK_UB(CopyOfStorage, sizeof(pValidMapEncoded) + QCBOR_DECODE_MIN_MEM_POOL_SIZE); |
| const UsefulBufC CopyOf = UsefulBuf_Copy(CopyOfStorage, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded)); |
| |
| QCBORDecode_Init(&DC, CopyOf, QCBOR_DECODE_MODE_NORMAL); |
| UsefulBuf_Set(Pool, '/'); |
| QCBORDecode_SetMemPool(&DC, Pool, 1); // Turn on copying. |
| |
| QCBORItem Item1, Item2, Item3, Item4; |
| if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) |
| return (int32_t)nCBORError; |
| if(Item1.uDataType != QCBOR_TYPE_MAP || |
| Item1.val.uCount != 3) |
| return -3; |
| if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) |
| return (int32_t)nCBORError; |
| if((nCBORError = QCBORDecode_GetNext(&DC, &Item2))) |
| return (int32_t)nCBORError; |
| if((nCBORError = QCBORDecode_GetNext(&DC, &Item3))) |
| return (int32_t)nCBORError; |
| if((nCBORError = QCBORDecode_GetNext(&DC, &Item4))) |
| return (int32_t)nCBORError; |
| |
| UsefulBuf_Set(CopyOfStorage, '_'); |
| |
| if(Item1.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| Item1.uDataType != QCBOR_TYPE_INT64 || |
| Item1.val.int64 != 42 || |
| Item1.uDataAlloc != 0 || |
| Item1.uLabelAlloc == 0 || |
| UsefulBuf_Compare(Item1.label.string, UsefulBuf_FromSZ("first integer"))) { |
| return -4; |
| } |
| |
| |
| if(Item2.uLabelType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item2.label.string, UsefulBuf_FromSZ("an array of two strings")) || |
| Item2.uDataType != QCBOR_TYPE_ARRAY || |
| Item2.uDataAlloc != 0 || |
| Item2.uLabelAlloc == 0 || |
| Item2.val.uCount != 2) |
| return -5; |
| |
| if(Item3.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item3.uDataAlloc == 0 || |
| Item3.uLabelAlloc != 0 || |
| UsefulBuf_Compare(Item3.val.string, UsefulBuf_FromSZ("string1"))) { |
| return -6; |
| } |
| |
| if(Item4.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item4.uDataAlloc == 0 || |
| Item4.uLabelAlloc != 0 || |
| UsefulBuf_Compare(Item4.val.string, UsefulBuf_FromSZ("string2"))) { |
| return -7; |
| } |
| |
| // Next parse with a pool that is too small |
| UsefulBuf_MAKE_STACK_UB(SmallPool, QCBOR_DECODE_MIN_MEM_POOL_SIZE + 1); |
| QCBORDecode_Init(&DC, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), |
| QCBOR_DECODE_MODE_NORMAL); |
| QCBORDecode_SetMemPool(&DC, SmallPool, 1); // Turn on copying. |
| if((nCBORError = QCBORDecode_GetNext(&DC, &Item1))) |
| return -8; |
| if(Item1.uDataType != QCBOR_TYPE_MAP || |
| Item1.val.uCount != 3) { |
| return -9; |
| } |
| if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item1))){ |
| if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item2))) { |
| if(!(nCBORError = QCBORDecode_GetNext(&DC, &Item3))) { |
| nCBORError = QCBORDecode_GetNext(&DC, &Item4); |
| } |
| } |
| } |
| if(nCBORError != QCBOR_ERR_STRING_ALLOCATE) { |
| return -10; |
| } |
| |
| return 0; |
| } |
| |
| |
| |
| int32_t MemPoolTest(void) |
| { |
| // Set up the decoder with a tiny bit of CBOR to parse because |
| // nothing can be done with it unless that is set up. |
| QCBORDecodeContext DC; |
| const uint8_t pMinimalCBOR[] = {0xa0}; // One empty map |
| QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); |
| |
| // Set up an memory pool of 100 bytes |
| // Then fish into the internals of the decode context |
| // to get the allocator function so it can be called directly. |
| // Also figure out how much pool is available for use |
| // buy subtracting out the overhead. |
| UsefulBuf_MAKE_STACK_UB(Pool, 100); |
| QCBORError nError = QCBORDecode_SetMemPool(&DC, Pool, 0); |
| if(nError) { |
| return -9; |
| } |
| QCBORStringAllocate pAlloc = DC.StringAllocator.pfAllocator; |
| void *pAllocCtx = DC.StringAllocator.pAllocateCxt; |
| size_t uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; |
| |
| // First test -- ask for one more byte than available and see failure |
| UsefulBuf Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool+1); |
| if(!UsefulBuf_IsNULL(Allocated)) { |
| return -1; |
| } |
| |
| // Re do the set up for the next test that will do a successful alloc, |
| // a fail, a free and then success |
| QCBORDecode_SetMemPool(&DC, Pool, 0); |
| pAlloc = DC.StringAllocator.pfAllocator; |
| pAllocCtx = DC.StringAllocator.pAllocateCxt; |
| uAvailPool = Pool.len - QCBOR_DECODE_MIN_MEM_POOL_SIZE; |
| |
| // Allocate one byte less than available and see success |
| Allocated = (pAlloc)(pAllocCtx, NULL, uAvailPool-1); |
| if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed |
| return -2; |
| } |
| // Ask for some more and see failure |
| UsefulBuf Allocated2 = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); |
| if(!UsefulBuf_IsNULL(Allocated2)) { // expected to fail |
| return -3; |
| } |
| // Free the first allocate, retry the second and see success |
| (*pAlloc)(pAllocCtx, Allocated.ptr, 0); // Free |
| Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); |
| if(UsefulBuf_IsNULL(Allocated)) { // succeed because of the free |
| return -4; |
| } |
| |
| // Re do set up for next test that involves a successful alloc, |
| // and a successful realloc and a failed realloc |
| QCBORDecode_SetMemPool(&DC, Pool, 0); |
| pAlloc = DC.StringAllocator.pfAllocator; |
| pAllocCtx = DC.StringAllocator.pAllocateCxt; |
| |
| // Allocate half the pool and see success |
| Allocated = (*pAlloc)(pAllocCtx, NULL, uAvailPool/2); |
| if(UsefulBuf_IsNULL(Allocated)) { // expected to succeed |
| return -5; |
| } |
| // Reallocate to take up the whole pool and see success |
| Allocated2 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool); |
| if(UsefulBuf_IsNULL(Allocated2)) { |
| return -6; |
| } |
| // Make sure its the same pointer and the size is right |
| if(Allocated2.ptr != Allocated.ptr || Allocated2.len != uAvailPool) { |
| return -7; |
| } |
| // Try to allocate more to be sure there is failure after a realloc |
| UsefulBuf Allocated3 = (*pAlloc)(pAllocCtx, Allocated.ptr, uAvailPool+1); |
| if(!UsefulBuf_IsNULL(Allocated3)) { |
| return -8; |
| } |
| |
| return 0; |
| } |
| |
| |
| /* Just enough of an allocator to test configuration of one */ |
| static UsefulBuf AllocateTestFunction(void *pCtx, void *pOldMem, size_t uNewSize) |
| { |
| (void)pOldMem; // unused variable |
| |
| if(uNewSize) { |
| // Assumes the context pointer is the buffer and |
| // nothing too big will ever be asked for. |
| // This is only good for this basic test! |
| return (UsefulBuf) {pCtx, uNewSize}; |
| } else { |
| return NULLUsefulBuf; |
| } |
| } |
| |
| |
| int32_t SetUpAllocatorTest(void) |
| { |
| // Set up the decoder with a tiny bit of CBOR to parse because |
| // nothing can be done with it unless that is set up. |
| QCBORDecodeContext DC; |
| const uint8_t pMinimalCBOR[] = {0x62, 0x48, 0x69}; // "Hi" |
| QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pMinimalCBOR),0); |
| |
| uint8_t pAllocatorBuffer[50]; |
| |
| // This is really just to test that this call works. |
| // The full functionality of string allocators is tested |
| // elsewhere with the MemPool internal allocator. |
| QCBORDecode_SetUpAllocator(&DC, AllocateTestFunction, pAllocatorBuffer, 1); |
| |
| QCBORItem Item; |
| if(QCBORDecode_GetNext(&DC, &Item) != QCBOR_SUCCESS) { |
| return -1; |
| } |
| |
| if(Item.uDataAlloc == 0 || |
| Item.uDataType != QCBOR_TYPE_TEXT_STRING || |
| Item.val.string.ptr != pAllocatorBuffer) { |
| return -2; |
| } |
| |
| if(QCBORDecode_Finish(&DC) != QCBOR_SUCCESS) { |
| return -3; |
| } |
| |
| return 0; |
| } |
| |
| |
| #ifndef QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA |
| /* exponent, mantissa |
| [ |
| 4([-1, 3]), |
| 4([-20, 4759477275222530853136]), |
| 4([9223372036854775807, -4759477275222530853137]), |
| 5([300, 100]), |
| 5([-20, 4759477275222530853136]), |
| 5([-9223372036854775807, -4759477275222530853137]) |
| 5([ 9223372036854775806, -4759477275222530853137]) |
| 5([ 9223372036854775806, 9223372036854775806])] |
| ] |
| */ |
| |
| static const uint8_t spExpectedExponentsAndMantissas[] = { |
| 0x87, |
| 0xC4, 0x82, 0x20, |
| 0x03, |
| 0xC4, 0x82, 0x33, |
| 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, |
| 0xC4, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, |
| 0xC5, 0x82, 0x19, 0x01, 0x2C, |
| 0x18, 0x64, |
| 0xC5, 0x82, 0x33, |
| 0xC2, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, |
| 0xC5, 0x82, 0x3B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, |
| 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, |
| 0xC5, 0x82, 0x1B, 0x7F, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, |
| 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x10, |
| 0xC5, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE, |
| 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE |
| }; |
| |
| int32_t ExponentAndMantissaDecodeTests(void) |
| { |
| QCBORDecodeContext DC; |
| QCBORError nCBORError; |
| QCBORItem item; |
| |
| static const uint8_t spBigNumMantissa[] = {0x01, 0x02, 0x03, 0x04, 0x05, |
| 0x06, 0x07, 0x08, 0x09, 0x010}; |
| UsefulBufC BN = UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spBigNumMantissa); |
| |
| |
| QCBORDecode_Init(&DC, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentsAndMantissas), QCBOR_DECODE_MODE_NORMAL); |
| |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 1; |
| } |
| |
| if(item.uDataType != QCBOR_TYPE_ARRAY) { |
| return 2; |
| } |
| |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 3; |
| } |
| |
| if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || |
| item.val.expAndMantissa.Mantissa.nInt != 3 || |
| item.val.expAndMantissa.nExponent != -1) { |
| return 4; |
| } |
| |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 5; |
| } |
| |
| if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM || |
| item.val.expAndMantissa.nExponent != -20 || |
| UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { |
| return 6; |
| } |
| |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 7; |
| } |
| |
| if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_NEG_BIGNUM || |
| item.val.expAndMantissa.nExponent != 9223372036854775807 || |
| UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { |
| return 8; |
| } |
| |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 9; |
| } |
| |
| if(item.uDataType != QCBOR_TYPE_BIGFLOAT || |
| item.val.expAndMantissa.Mantissa.nInt != 100 || |
| item.val.expAndMantissa.nExponent != 300) { |
| return 10; |
| } |
| |
| // 5([-20, 4759477275222530853136]), |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 11; |
| } |
| if(item.uDataType != QCBOR_TYPE_BIGFLOAT_POS_BIGNUM || |
| item.val.expAndMantissa.nExponent != -20 || |
| UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { |
| return 12; |
| } |
| |
| // 5([-9223372036854775807, -4759477275222530853137]) |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 13; |
| } |
| if(item.uDataType != QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM || |
| item.val.expAndMantissa.nExponent != -9223372036854775807 || |
| UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { |
| return 14; |
| } |
| |
| // 5([ 9223372036854775806, -4759477275222530853137]) |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 13; |
| } |
| if(item.uDataType != QCBOR_TYPE_BIGFLOAT_NEG_BIGNUM || |
| item.val.expAndMantissa.nExponent != 9223372036854775806 || |
| UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { |
| return 14; |
| } |
| |
| |
| // 5([ 9223372036854775806, 9223372036854775806])] |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 15; |
| } |
| if(item.uDataType != QCBOR_TYPE_BIGFLOAT || |
| item.val.expAndMantissa.nExponent != 9223372036854775806 || |
| item.val.expAndMantissa.Mantissa.nInt!= 9223372036854775806 ) { |
| return 16; |
| } |
| |
| /* Now encode some stuff and then decode it */ |
| uint8_t pBuf[40]; |
| QCBOREncodeContext EC; |
| UsefulBufC Encoded; |
| |
| QCBOREncode_Init(&EC, UsefulBuf_FROM_BYTE_ARRAY(pBuf)); |
| QCBOREncode_OpenArray(&EC); |
| QCBOREncode_AddDecimalFraction(&EC, 999, 1000); // 999 * (10 ^ 1000) |
| QCBOREncode_AddBigFloat(&EC, 100, INT32_MIN); |
| QCBOREncode_AddDecimalFractionBigNum(&EC, BN, false, INT32_MAX); |
| QCBOREncode_CloseArray(&EC); |
| QCBOREncode_Finish(&EC, &Encoded); |
| |
| |
| QCBORDecode_Init(&DC, Encoded, QCBOR_DECODE_MODE_NORMAL); |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 13; |
| } |
| |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 13; |
| } |
| |
| if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION || |
| item.val.expAndMantissa.nExponent != 1000 || |
| item.val.expAndMantissa.Mantissa.nInt != 999) { |
| return 15; |
| } |
| |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 13; |
| } |
| |
| if(item.uDataType != QCBOR_TYPE_BIGFLOAT || |
| item.val.expAndMantissa.nExponent != INT32_MIN || |
| item.val.expAndMantissa.Mantissa.nInt != 100) { |
| return 15; |
| } |
| |
| nCBORError = QCBORDecode_GetNext(&DC, &item); |
| if(nCBORError != QCBOR_SUCCESS) { |
| return 13; |
| } |
| |
| if(item.uDataType != QCBOR_TYPE_DECIMAL_FRACTION_POS_BIGNUM || |
| item.val.expAndMantissa.nExponent != INT32_MAX || |
| UsefulBuf_Compare(item.val.expAndMantissa.Mantissa.bigNum, BN)) { |
| return 12; |
| } |
| |
| return 0; |
| } |
| |
| |
| static struct FailInput ExponentAndMantissaFailures[] = { |
| // Exponent > INT64_MAX |
| { {(uint8_t[]){0xC4, 0x82, 0x1B, 0x7f, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0x1B, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF,}, 20}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, |
| // Mantissa > INT64_MAX |
| { {(uint8_t[]){0xC4, 0x82, 0x1B, 0x80, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, |
| 0xFF, 0xFF, 0xC3, 0x4A, 0x01, 0x02, 0x03, 0x04, 0x05, |
| 0x06, 0x07, 0x08, 0x09, 0x10}, 23}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, |
| // End of input |
| { {(uint8_t[]){0xC4, 0x82}, 2}, QCBOR_ERR_HIT_END}, |
| // End of input |
| { {(uint8_t[]){0xC4, 0x82, 0x01}, 3}, QCBOR_ERR_HIT_END}, |
| // bad content for big num |
| { {(uint8_t[]){0xC4, 0x82, 0x01, 0xc3, 0x01}, 5}, QCBOR_ERR_BAD_OPT_TAG}, |
| // bad content for big num |
| { {(uint8_t[]){0xC4, 0x82, 0xc2, 0x01, 0x1f}, 5}, QCBOR_ERR_BAD_INT}, |
| // Bad integer for exponent |
| { {(uint8_t[]){0xC4, 0x82, 0x01, 0x1f}, 4}, QCBOR_ERR_BAD_INT}, |
| // Bad integer for mantissa |
| { {(uint8_t[]){0xC4, 0x82, 0x1f, 0x01}, 4}, QCBOR_ERR_BAD_INT}, |
| // 3 items in array |
| { {(uint8_t[]){0xC4, 0x83, 0x03, 0x01, 02}, 5}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, |
| // unterminated indefinite length array |
| { {(uint8_t[]){0xC4, 0x9f, 0x03, 0x01, 0x02}, 5}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, |
| // Empty array |
| { {(uint8_t[]){0xC4, 0x80}, 2}, QCBOR_ERR_NO_MORE_ITEMS}, |
| // Second is not an integer |
| { {(uint8_t[]){0xC4, 0x82, 0x03, 0x40}, 4}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, |
| // First is not an integer |
| { {(uint8_t[]){0xC4, 0x82, 0x40}, 3}, QCBOR_ERR_BAD_EXP_AND_MANTISSA}, |
| // Not an array |
| { {(uint8_t[]){0xC4, 0xa2}, 2}, QCBOR_ERR_BAD_EXP_AND_MANTISSA} |
| }; |
| |
| |
| int32_t ExponentAndMantissaDecodeFailTests() |
| { |
| return ProcessFailures(ExponentAndMantissaFailures, |
| sizeof(ExponentAndMantissaFailures)/sizeof(struct FailInput)); |
| } |
| |
| #endif /* QCBOR_CONFIG_DISABLE_EXP_AND_MANTISSA */ |
| |
| |
| |
| /* |
| Some basic CBOR with map and array used in a lot of tests. |
| The map labels are all strings |
| |
| { |
| "first integer": 42, |
| "an array of two strings": [ |
| "string1", "string2" |
| ], |
| "map in a map": { |
| "bytes 1": h'78787878', |
| "bytes 2": h'79797979', |
| "another int": 98, |
| "text 2": "lies, damn lies and statistics" |
| } |
| } |
| */ |
| |
| #include "qcbor/qcbor_decode_map.h" |
| #include <stdio.h> |
| |
| static char strbuf[10]; |
| const char *PrintType(uint8_t type) { |
| switch(type) { |
| case QCBOR_TYPE_INT64: return "INT64"; |
| case QCBOR_TYPE_UINT64: return "UINT64"; |
| case QCBOR_TYPE_ARRAY: return "ARRAY"; |
| case QCBOR_TYPE_MAP: return "MAP"; |
| case QCBOR_TYPE_BYTE_STRING: return "BYTE_STRING"; |
| case QCBOR_TYPE_TEXT_STRING: return "TEXT_STRING"; |
| default: |
| sprintf(strbuf, "%d", type); |
| return strbuf; |
| } |
| } |
| |
| |
| void PrintItem(QCBORItem Item) |
| { |
| printf("\nData: %s nest: %d,%d %s\n", PrintType(Item.uDataType), Item.uNestingLevel, Item.uNextNestLevel, Item.uDataAlloc ? "Allocated":""); |
| if(Item.uLabelType) { |
| printf("Label: %s ", PrintType(Item.uLabelType)); |
| if(Item.uLabelType == QCBOR_TYPE_INT64) { |
| printf("%lld\n", Item.label.int64); |
| } else if(Item.uLabelType == QCBOR_TYPE_TEXT_STRING) { |
| printf("\"%4.4s\"\n", Item.label.string.ptr); |
| } |
| } |
| } |
| |
| |
| int32_t EnterMapTest() |
| { |
| QCBORItem Item1, Item2, Item3; |
| int64_t nDecodedInt1, nDecodedInt2; |
| UsefulBufC B1, B2, S1, S2, S3; |
| |
| QCBORDecodeContext DCtx; |
| QCBORError nCBORError; |
| |
| QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); |
| |
| QCBORDecode_EnterMap(&DCtx); |
| |
| QCBORDecode_GetIntInMapSZ(&DCtx, "first integer", &nDecodedInt1); |
| |
| QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); |
| QCBORDecode_GetIntInMapSZ(&DCtx, "another int", &nDecodedInt2); |
| QCBORDecode_GetBstrInMapSZ(&DCtx, "bytes 1", &B1); |
| QCBORDecode_GetBstrInMapSZ(&DCtx, "bytes 2", &B2); |
| QCBORDecode_GetTextInMapSZ(&DCtx, "text 2", &S1); |
| QCBORDecode_ExitMap(&DCtx); |
| |
| QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item2); |
| if(QCBORDecode_GetNext(&DCtx, &Item3) != QCBOR_ERR_NO_MORE_ITEMS) { |
| return -400; |
| } |
| QCBORDecode_ExitArray(&DCtx); |
| |
| // Parse the same array again using GetText() instead of GetItem() |
| QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); |
| QCBORDecode_GetText(&DCtx, &S2); |
| QCBORDecode_GetText(&DCtx, &S3); |
| // TODO, check for end of array? |
| QCBORDecode_ExitArray(&DCtx); |
| |
| QCBORDecode_ExitMap(&DCtx); |
| |
| nCBORError = QCBORDecode_Finish(&DCtx); |
| |
| if(nCBORError) { |
| return (int32_t)nCBORError; |
| } |
| |
| if(nDecodedInt1 != 42) { |
| return 1001; |
| } |
| |
| if(nDecodedInt2 != 98) { |
| return 1002; |
| } |
| |
| if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item1.val.string, UsefulBuf_FromSZ("string1"))){ |
| return 1003; |
| } |
| |
| if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING || |
| UsefulBuf_Compare(Item2.val.string, UsefulBuf_FromSZ("string2"))){ |
| return 1004; |
| } |
| |
| if(UsefulBuf_Compare(S1, UsefulBuf_FromSZ("lies, damn lies and statistics"))){ |
| return 1005; |
| } |
| |
| if(UsefulBuf_Compare(B1, UsefulBuf_FromSZ("xxxx"))){ |
| return 1006; |
| } |
| |
| if(UsefulBuf_Compare(B2, UsefulBuf_FromSZ("yyyy"))){ |
| return 1007; |
| } |
| |
| if(UsefulBuf_Compare(S2, UsefulBuf_FromSZ("string1"))){ |
| return 1008; |
| } |
| |
| if(UsefulBuf_Compare(S3, UsefulBuf_FromSZ("string2"))){ |
| return 1009; |
| } |
| |
| // These tests confirm the cursor is at the right place after entering a map or array |
| |
| // Confirm cursor is at right place |
| QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); |
| QCBORDecode_EnterMap(&DCtx); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| if(Item1.uDataType != QCBOR_TYPE_INT64) { |
| return 2001; |
| } |
| |
| |
| QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_EnterArray(&DCtx); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { |
| return 2002; |
| } |
| |
| QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); |
| QCBORDecode_EnterMap(&DCtx); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_EnterMapFromMapSZ(&DCtx, "map in a map"); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| if(Item1.uDataType != QCBOR_TYPE_BYTE_STRING) { |
| return 2003; |
| } |
| |
| QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pValidMapEncoded), 0); |
| QCBORDecode_EnterMap(&DCtx); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| QCBORDecode_EnterArrayFromMapSZ(&DCtx, "an array of two strings"); |
| QCBORDecode_GetNext(&DCtx, &Item1); |
| if(Item1.uDataType != QCBOR_TYPE_TEXT_STRING) { |
| return 2004; |
| } |
| |
| |
| return 0; |
| } |
| |
| |
| struct NumberConversion { |
| char *szDescription; |
| UsefulBufC CBOR; |
| int64_t nConvertedToInt64; |
| QCBORError uErrorInt64; |
| uint64_t uConvertToUInt64; |
| QCBORError uErrorUint64; |
| double dConvertToDouble; |
| QCBORError uErrorDouble; |
| }; |
| |
| static struct NumberConversion NumberConversions[] = { |
| { |
| "Postive integer 0", |
| {(uint8_t[]){0x0}, 1}, |
| 0LL, |
| QCBOR_SUCCESS, |
| 0ULL, |
| QCBOR_SUCCESS, |
| 0.0, |
| QCBOR_SUCCESS |
| }, |
| { |
| "-18446744073709551616", |
| {(uint8_t[]){0x3b, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }, 9}, |
| -9223372036854775807-1, // INT64_MIN |
| QCBOR_SUCCESS, |
| 0ULL, |
| QCBOR_ERR_NUMBER_SIGN_CONVERSION, |
| -9223372036854775808.0, |
| QCBOR_SUCCESS |
| }, |
| { |
| "Floating point value 100.3", |
| {(uint8_t[]){0xfb, 0x40, 0x59, 0x13, 0x33, 0x33, 0x33, 0x33, 0x33}, 9}, |
| 100L, |
| QCBOR_SUCCESS, |
| 100ULL, |
| QCBOR_SUCCESS, |
| 100.3, |
| QCBOR_SUCCESS |
| }, |
| { |
| "Floating point value NaN 0xfa7fc00000", |
| {(uint8_t[]){0xfa, 0x7f, 0xc0, 0x00, 0x00}, 5}, |
| 0, |
| QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, |
| 0, |
| QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, |
| NAN, |
| QCBOR_SUCCESS |
| }, |
| { |
| "Floating point value -4", |
| {(uint8_t[]){0xf9, 0xc4, 0x00}, 3}, |
| -4, |
| QCBOR_SUCCESS, |
| 0, |
| QCBOR_ERR_NUMBER_SIGN_CONVERSION, |
| -4.0, |
| QCBOR_SUCCESS |
| }, |
| { |
| "Decimal fraction 3/10", |
| {(uint8_t[]){0xC4, 0x82, 0x20, 0x03}, 4}, |
| 0, |
| QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, |
| 0, |
| QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW, |
| 0.30000000000000004, |
| QCBOR_SUCCESS |
| } |
| }; |
| |
| |
| |
| |
| int32_t IntegerConvertTest2() |
| { |
| const size_t nNumTests = sizeof(NumberConversions)/sizeof(struct NumberConversion); |
| |
| for(struct NumberConversion *pF = NumberConversions; pF < NumberConversions + nNumTests; pF++) { |
| // Set up the decoding context including a memory pool so that |
| // indefinite length items can be checked |
| QCBORDecodeContext DCtx; |
| QCBORDecode_Init(&DCtx, pF->CBOR, QCBOR_DECODE_MODE_NORMAL); |
| UsefulBuf_MAKE_STACK_UB(Pool, 100); |
| QCBORError nCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0); |
| if(nCBORError) { |
| return -9; |
| } |
| |
| int64_t nInt; |
| DCtx.uLastError = 0; |
| QCBORDecode_GetInt64ConvertAll(&DCtx, 0xffff, &nInt); |
| if(QCBORDecode_GetError(&DCtx) != pF->uErrorInt64) { |
| return -99; |
| } |
| if(pF->uErrorInt64 == QCBOR_SUCCESS && pF->nConvertedToInt64 != nInt) { |
| return -888; |
| } |
| |
| |
| QCBORDecode_Init(&DCtx, pF->CBOR, QCBOR_DECODE_MODE_NORMAL); |
| nCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0); |
| if(nCBORError) { |
| return -9; |
| } |
| uint64_t uInt; |
| DCtx.uLastError = 0; |
| QCBORDecode_GetUInt64ConvertAll(&DCtx, 0xffff, &uInt); |
| if(QCBORDecode_GetError(&DCtx) != pF->uErrorUint64) { |
| return -99; |
| } |
| if(pF->uErrorUint64 == QCBOR_SUCCESS && pF->uConvertToUInt64 != uInt) { |
| return -888; |
| } |
| |
| |
| QCBORDecode_Init(&DCtx, pF->CBOR, QCBOR_DECODE_MODE_NORMAL); |
| nCBORError = QCBORDecode_SetMemPool(&DCtx, Pool, 0); |
| if(nCBORError) { |
| return -9; |
| } |
| double d; |
| DCtx.uLastError = 0; |
| QCBORDecode_GetDoubleConvertAll(&DCtx, 0xffff, &d); |
| if(QCBORDecode_GetError(&DCtx) != pF->uErrorDouble) { |
| return -99; |
| } |
| if(pF->uErrorDouble == QCBOR_SUCCESS) { |
| if(isnan(pF->dConvertToDouble)) { |
| if(!isnan(d)) { |
| return -4; |
| } |
| } else { |
| // TODO: this comparison may need a margin of error |
| if(pF->dConvertToDouble != d) { |
| return -5; |
| } |
| } |
| } |
| } |
| |
| return 0; |
| } |
| |
| int32_t IntegerConvertTest() |
| { |
| (void)IntegerConvertTest2(); |
| |
| QCBORDecodeContext DCtx; |
| QCBORError nCBORError; |
| |
| /* exponent, mantissa |
| [ |
| 4([-1, 3]), |
| 4([-20, 4759477275222530853136]), |
| 4([9223372036854775807, -4759477275222530853137]), |
| 5([300, 100]), |
| 5([-20, 4759477275222530853136]), |
| 5([-9223372036854775807, -4759477275222530853137]) |
| 5([ 9223372036854775806, -4759477275222530853137]) |
| 5([ 9223372036854775806, 9223372036854775806])] |
| ] |
| */ |
| |
| QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentsAndMantissas), 0); |
| |
| QCBORItem Item; |
| nCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(nCBORError) { |
| return -1; |
| } |
| |
| int64_t integer; |
| // 4([-1, 3]), |
| QCBORDecode_GetInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION, &integer); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 4([-20, 4759477275222530853136]), |
| QCBORDecode_GetInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION, &integer); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 4([9223372036854775807, -4759477275222530853137]), |
| QCBORDecode_GetInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION, &integer); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([300, 100]), |
| QCBORDecode_GetInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &integer); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([-20, 4759477275222530853136]), |
| QCBORDecode_GetInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &integer); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([-9223372036854775807, -4759477275222530853137]) |
| QCBORDecode_GetInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &integer); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([ 9223372036854775806, -4759477275222530853137]) |
| QCBORDecode_GetInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &integer); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([ 9223372036854775806, 9223372036854775806])] |
| QCBORDecode_GetInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &integer); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| |
| |
| QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentsAndMantissas), 0); |
| |
| nCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(nCBORError) { |
| return -1; |
| } |
| |
| uint64_t uinteger; |
| // 4([-1, 3]), |
| QCBORDecode_GetUInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION, &uinteger); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 4([-20, 4759477275222530853136]), |
| QCBORDecode_GetUInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION, &uinteger); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 4([9223372036854775807, -4759477275222530853137]), |
| QCBORDecode_GetUInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION, &uinteger); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([300, 100]), |
| QCBORDecode_GetUInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &uinteger); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([-20, 4759477275222530853136]), |
| QCBORDecode_GetUInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &uinteger); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([-9223372036854775807, -4759477275222530853137]) |
| QCBORDecode_GetUInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &uinteger); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([ 9223372036854775806, -4759477275222530853137]) |
| QCBORDecode_GetUInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &uinteger); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| // 5([ 9223372036854775806, 9223372036854775806])] |
| QCBORDecode_GetUInt64ConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION|QCBOR_CONVERT_TYPE_BIGFLOAT, &uinteger); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_ERR_CONVERSION_UNDER_OVER_FLOW) { |
| return -2; |
| } |
| DCtx.uLastError = 0; // TODO: a method for this |
| |
| |
| |
| QCBORDecode_Init(&DCtx, UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spExpectedExponentsAndMantissas), 0); |
| nCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(nCBORError) { |
| return -1; |
| } |
| |
| double dResult; |
| // 4([-1, 3]), |
| QCBORDecode_GetDoubleConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION, &dResult); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS && |
| dResult != 0.3) { |
| return -2; |
| } |
| |
| // 4([-20, 4759477275222530853136]), |
| QCBORDecode_GetDoubleConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION, &dResult); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS && |
| dResult != 47.408855671161923) { |
| return -2; |
| } |
| |
| // 4([9223372036854775807, -4759477275222530853137]), |
| QCBORDecode_GetDoubleConvertAll(&DCtx, QCBOR_CONVERT_TYPE_DECIMAL_FRACTION, &dResult); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS && |
| dResult != -INFINITY) { |
| return -2; |
| } |
| |
| // 5([300, 100]), |
| QCBORDecode_GetDoubleConvertAll(&DCtx, QCBOR_CONVERT_TYPE_BIGFLOAT, &dResult); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS && |
| dResult != -INFINITY) { |
| return -2; |
| } |
| |
| // 5([-20, 4759477275222530853136]), |
| QCBORDecode_GetDoubleConvertAll(&DCtx, QCBOR_CONVERT_TYPE_BIGFLOAT, &dResult); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS && |
| dResult != 4521260802379792.0) { |
| return -2; |
| } |
| |
| // 5([-9223372036854775807, -4759477275222530853137]) |
| QCBORDecode_GetDoubleConvertAll(&DCtx, QCBOR_CONVERT_TYPE_BIGFLOAT, &dResult); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS && |
| dResult != -0.0) { |
| return -2; |
| } |
| |
| // 5([9223372036854775806, 9223372036854775806])] |
| QCBORDecode_GetDoubleConvertAll(&DCtx, QCBOR_CONVERT_TYPE_BIGFLOAT, &dResult); |
| if(QCBORDecode_GetError(&DCtx) != QCBOR_SUCCESS && |
| dResult != INFINITY) { |
| return -2; |
| } |
| |
| return 0; |
| } |
| |
| |
| int32_t CBORSequenceDecodeTests(void) |
| { |
| QCBORDecodeContext DCtx; |
| QCBORItem Item; |
| QCBORError uCBORError; |
| |
| // --- Test a sequence with extra bytes --- |
| |
| // The input for the date test happens to be a sequence so it |
| // is reused. It is a sequence because it doesn't start as |
| // an array or map. |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(spDateTestInput), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| // Get the first item |
| uCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(uCBORError != QCBOR_SUCCESS) { |
| return 1; |
| } |
| if(Item.uDataType != QCBOR_TYPE_DATE_STRING) { |
| return 2; |
| } |
| |
| // Get a second item |
| uCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(uCBORError != QCBOR_SUCCESS) { |
| return 2; |
| } |
| if(Item.uDataType != QCBOR_TYPE_DATE_EPOCH) { |
| return 3; |
| } |
| |
| // A sequence can have stuff at the end that may |
| // or may not be valid CBOR. The protocol decoder knows |
| // when to stop by definition of the protocol, not |
| // when the top-level map or array is ended. |
| // Finish still has to be called to know that |
| // maps and arrays (if there were any) were closed |
| // off correctly. When called like this it |
| // must return the error QCBOR_ERR_EXTRA_BYTES. |
| uCBORError = QCBORDecode_Finish(&DCtx); |
| if(uCBORError != QCBOR_ERR_EXTRA_BYTES) { |
| return 4; |
| } |
| |
| |
| // --- Test an empty input ---- |
| uint8_t empty[1]; |
| UsefulBufC Empty = {empty, 0}; |
| QCBORDecode_Init(&DCtx, |
| Empty, |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| uCBORError = QCBORDecode_Finish(&DCtx); |
| if(uCBORError != QCBOR_SUCCESS) { |
| return 5; |
| } |
| |
| |
| // --- Sequence with unclosed indefinite length array --- |
| static const uint8_t xx[] = {0x01, 0x9f, 0x02}; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(xx), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| // Get the first item |
| uCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(uCBORError != QCBOR_SUCCESS) { |
| return 7; |
| } |
| if(Item.uDataType != QCBOR_TYPE_INT64) { |
| return 8; |
| } |
| |
| // Get a second item |
| uCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(uCBORError != QCBOR_SUCCESS) { |
| return 9; |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return 10; |
| } |
| |
| // Try to finish before consuming all bytes to confirm |
| // that the still-open error is returned. |
| uCBORError = QCBORDecode_Finish(&DCtx); |
| if(uCBORError != QCBOR_ERR_ARRAY_OR_MAP_STILL_OPEN) { |
| return 11; |
| } |
| |
| |
| // --- Sequence with a closed indefinite length array --- |
| static const uint8_t yy[] = {0x01, 0x9f, 0xff}; |
| |
| QCBORDecode_Init(&DCtx, |
| UsefulBuf_FROM_BYTE_ARRAY_LITERAL(yy), |
| QCBOR_DECODE_MODE_NORMAL); |
| |
| // Get the first item |
| uCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(uCBORError != QCBOR_SUCCESS) { |
| return 12; |
| } |
| if(Item.uDataType != QCBOR_TYPE_INT64) { |
| return 13; |
| } |
| |
| // Get a second item |
| uCBORError = QCBORDecode_GetNext(&DCtx, &Item); |
| if(uCBORError != QCBOR_SUCCESS) { |
| return 14; |
| } |
| if(Item.uDataType != QCBOR_TYPE_ARRAY) { |
| return 15; |
| } |
| |
| // Try to finish before consuming all bytes to confirm |
| // that the still-open error is returned. |
| uCBORError = QCBORDecode_Finish(&DCtx); |
| if(uCBORError != QCBOR_SUCCESS) { |
| return 16; |
| } |
| |
| |
| return 0; |
| } |