From 9fa48d8e0f2d4e68622d2076a76716193bfc7a80 Mon Sep 17 00:00:00 2001 From: Laurence Lundblade Date: Tue, 26 Nov 2024 16:50:38 -0800 Subject: [PATCH] Move all tag-related code into qcbor_tag_decode.[ch] --- README.md | 13 + inc/qcbor/qcbor_decode.h | 170 +---- inc/qcbor/qcbor_spiffy_decode.h | 924 +------------------------ inc/qcbor/qcbor_tag_decode.h | 1112 +++++++++++++++++++++++++++++- src/decode_private.h | 165 +++-- src/qcbor_decode.c | 1113 +------------------------------ src/qcbor_tag_decode.c | 1022 +++++++++++++++++++++++++++- 7 files changed, 2277 insertions(+), 2242 deletions(-) diff --git a/README.md b/README.md index d40430d..f51bebe 100644 --- a/README.md +++ b/README.md @@ -123,6 +123,19 @@ maps and arrays without the caller having to do anything. This includes mixed definite and indefinte maps and arrays. (Some work remains to support map searching with indefinite length strings.) +## v2 + +** Tag decoding + +** Map Sorting + +** Serialization Modes + +** Files Rearrangement + +** Bignumber ?? + + ## Comparison to TinyCBOR TinyCBOR is a popular widely used implementation. Like QCBOR, diff --git a/inc/qcbor/qcbor_decode.h b/inc/qcbor/qcbor_decode.h index 0f31e26..58e8fc4 100644 --- a/inc/qcbor/qcbor_decode.h +++ b/inc/qcbor/qcbor_decode.h @@ -1214,137 +1214,6 @@ QCBORError QCBORDecode_EndCheck(QCBORDecodeContext *pCtx); -#ifndef QCBOR_DISABLE_TAGS -/** - * @brief Returns the tag numbers for an item. - * - * @param[in] pCtx The decoder context. - * @param[out] puTagNumber The returned tag number. - * - * In QCBOR v2, all tag numbers on an item MUST be fetched with this - * method. If not, @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER will - * occur. This is a major change from QCBORv1. The QCBOR v1 behavior - * is too lax for proper CBOR decoding. When a tag number occurs it - * indicates the item is a new data type (except for a few tag numbers - * that are hints). Note also that in RFC 7049, tag numbers were - * incorrectly characterized as optional implying they could be - * ignored. - * - * In typical item decoding, tag numbers are not used, not present and - * not expected. There's no need to call this. - * - * When the protocol being decoded does use a tag number then this - * must be called for the items were the tag numbers occur before the - * items themselves are decoded. Making this call prevents the - * @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER error, but the caller still has to - * check that the tag number is the right one. Probably the tag number - * will be used to switch the flow of the decoder. - * - * It's possible that an item might use the presence/absence of a tag - * number to switch the flow of decoding. If there's a possibility of - * a tag number then this must be called. - * - * If this is called and there is no tag number, then this will return - * @ref QCBOR_SUCCESS and the tag number returned will be - * @ref CBOR_TAG_INVALID64. - * - * Usually there is only one tag number per item, but CBOR allows - * more. That it allows nesting of tags where the content of one tag - * is another tag. If there are multiple tag numbers, this must be - * called multiple times. This only returns one tag number at a time, - * because tag numbers are typically processed one at a time. - * - * If there is an error decoding the tag or the item it is on, the - * error code will be set and the tag number @ref CBOR_TAG_INVALID64 - * will be returned. That is, @ref CBOR_TAG_INVALID64 will be returned if - * there is a decode error or there is no tag number. - */ -void -QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber); - - -/** - * @brief Returns the tag numbers for an item. - * - * @param[in] pCtx The decoder context. - * @param[out] puTagNumber The returned tag number. - * - * @return See error table of decoding errors set by QCBORDecode_VGetNext(). - * - * Like QCBORDecode_VGetNextTagNumber(), but returns the - * error rather than set last error. - */ -QCBORError -QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber); - - -/** - * @brief Returns the tag numbers for a decoded item. - * - * @param[in] pCtx The decoder context. - * @param[in] pItem The CBOR item to get the tag for. - * @param[in] uIndex The index of the tag to get. - * - * @returns The nth tag number or @ref CBOR_TAG_INVALID64. - * - * Typically, this is only used with @ref QCBOR_DECODE_CONFIG_UNPROCESSED_TAG_NUMBERS. - * Normally, tag numbers are processed QCBORDecode_VGetNextTagNumber() or - * QCBORTagContentCallBack. - * - * When QCBOR decodes an item that is a tag, it will fully decode tags - * it is able to. Tags that it is unable to process are put in a list - * in the QCBORItem. - * - * Tags nest. Here the tag with index 0 is the outermost, the one - * furthest form the data item that is the tag content. This is - * the opposite order of QCBORDecode_GetNthTag(), but more - * useful. - * - * Deep tag nesting is rare so this implementation imposes a limit of - * @ref QCBOR_MAX_TAGS_PER_ITEM on nesting and returns @ref - * QCBOR_ERR_TOO_MANY_TAGS if there are more. This is a limit of this - * implementation, not of CBOR. (To be able to handle deeper nesting, - * the constant can be increased and the library recompiled. It will - * use more memory). - * - * See also @ref Tag-Decoding @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. - * - * To reduce memory used by a @ref QCBORItem, tag numbers larger than - * @c UINT16_MAX are mapped so the tag numbers in @c uTags should be - * accessed with this function rather than directly. - * - * This returns @ref CBOR_TAG_INVALID64 if any error occurred when - * getting the item. This is also returned if there are no tags on the - * item or no tag at @c uIndex. - */ -uint64_t -QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint8_t uIndex); - - -/** - * @brief Returns the tag numbers for last-decoded item. - * - * @param[in] pCtx The decoder context. - * @param[in] uIndex The index of the tag to get. - * - * @returns The nth tag number or @ref CBOR_TAG_INVALID64. - * - * This returns tags of the most recently decoded item. See - * QCBORDecode_GetNthTagNumber(). This is particularly of use for spiffy - * decode functions that don't return a @ref QCBORItem. - * - * This does not work for QCBORDecode_GetNext(), - * QCBORDecode_PeekNext(), QCBORDecode_VPeekNext() or - * QCBORDecode_VGetNextConsume() but these all return a - * @ref QCBORItem, so it is not necessary. - * - * If a decoding error is set, then this returns @ref CBOR_TAG_INVALID64. - */ -uint64_t -QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pCtx, uint8_t uIndex); - -#endif /* ! QCBOR_DISABLE_TAGS */ - /** * @brief Check that a decode completed successfully. @@ -1551,12 +1420,12 @@ QCBORDecode_SetError(QCBORDecodeContext *pCtx, QCBORError uError); * which causes no error to be returned when un processed tag numbers * are encountered. * - * Second, it installs all the same tag content handlers that v1 had hardwwired. + * Second, it installs all the same tag content handlers that were hardwired in v1. * QCBORDecode_InstallTagDecoders(pMe, QCBORDecode_TagDecoderTablev1, NULL); * * This is listed as deprecated even though it is new in QCBOR v2 * because it recommended that v1 mode not be used because the tag - * number processing is too loose. + * number processing is too loose. See @ref v2-Tag-Decoding. * * This links in a fair bit of object code for all the tag content * handlers that were always present in v1. To get the v1 behavior @@ -1569,42 +1438,7 @@ QCBORDecode_CompatibilityV1(QCBORDecodeContext *pCtx); -#ifndef QCBOR_DISABLE_TAGS - -/** - * @brief Returns the tag numbers for an item. (deprecated). - * - * @param[in] pCtx The decoder context. - * @param[in] uIndex The index of the tag to get. - * - * This is the same as QCBORDecode_GetNthTagNumber() but the order is - * opposite when there are multiple tags. @c uIndex 0 is the tag - * number closest to the tag content. QCBORDecode_GetNthTagNumber() is - * more useful for checking the next tag number and switching the - * decode flow. - */ -uint64_t -QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex); - - -/** - * @brief Returns the tag numbers for last-decoded item (deprecated). - * - * @param[in] pCtx The decoder context. - * @param[in] uIndex The index of the tag to get. - * - * @returns The nth tag number or CBOR_TAG_INVALID64. - * - * This is the same as QCBORDecode_GetNthTagNumberOfLast() but the - * order is opposite when there are multiple tags. @c uIndex 0 is the - * tag number closest to the tag content. - * QCBORDecode_GetNthTagNumber() is more useful for checking - * the next tag number and switching the decode flow. - */ -uint64_t -QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex); -#endif /* ! QCBOR_DISABLE_TAGS */ /* ========================================================================= * * END OF DEPRECATED FUNCTIONS * * ========================================================================= */ diff --git a/inc/qcbor/qcbor_spiffy_decode.h b/inc/qcbor/qcbor_spiffy_decode.h index 155df7c..26902d7 100644 --- a/inc/qcbor/qcbor_spiffy_decode.h +++ b/inc/qcbor/qcbor_spiffy_decode.h @@ -34,7 +34,9 @@ extern "C" { * * This section discusses spiffy decoding assuming familiarity with * the general description of decoding in the - * @ref BasicDecode section. + * @ref BasicDecode section. See also qcbor_tag_decode.h + * and qcbor_number_decode.h for more spiffy decode + * functions. * * Spiffy decode is extra decode features over and above the @ref * BasicDecode features that generally are easier to use, mirror the @@ -106,88 +108,11 @@ extern "C" { * quantified). One way ease this is to use * QCBORDecode_GetItemsInMap() which allows decoding of a list of * items expected in an map in one traveral. - * - * @anchor Tag-Usage - * ## Tag Usage - * - * Data types beyond the basic CBOR types of numbers, strings, maps and - * arrays are called tags. The main registry of these new types is in - * the IANA CBOR tags registry. These new types may be simple such a - * number that is to be interpreted as a date, or of moderate complexity - * such as defining a decimal fraction that is an array containing a - * mantissa and exponent, or complex such as format for signing and - * encryption. - * - * When a tag occurs in a protocol it is encoded as an integer tag - * number plus the content of the tag. - * - * The content format of a tag may also be "borrowed". For example, a - * protocol definition may say that a particular data item is an epoch - * date just like tag 1, but not actually tag 1. In practice the - * difference is the presence or absence of the integer tag number in - * the encoded CBOR. - * - * The decoding functions for these new types takes a tag requirement - * parameter to say whether the item is a tag, is just borrowing the - * content format and is not a tag, or whether either is OK. - * - * If the parameter indicates the item must be a tag (@ref - * QCBOR_TAG_REQUIREMENT_TAG), then @ref QCBOR_ERR_UNEXPECTED_TYPE is - * set if it is not one of the expected tag types. To decode correctly - * the contents of the tag must also be of the correct type. For - * example, to decode an epoch date tag the content must be an integer - * or floating-point value. - * - * If the parameter indicates it should not be a tag - * (@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then - * @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the - * encoded CBOR is not what is expected. In the example of an epoch - * date, the data type must be an integer or floating-point value. This - * is the case where the content format of a tag is borrowed. - * - * The parameter can also indicate that either a tag or no tag is - * allowed ( @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG ). A good protocol - * design should however be clear and choose one or the other and not - * need this option. This is a way to implement "be liberal in what you - * accept", however these days that is less in favor. See - * https://tools.ietf.org/id/draft-thomson-postel-was-wrong-03.html. - * - * Map searching works with indefinite length strings. A string - * allocator must be set up the same as for any handling of indefinite - * length strings. However, It currently over-allocates memory from the - * string pool and thus requires a much larger string pool than it - * should. The over-allocation happens every time a map is searched by - * label. (This may be corrected in the future). */ -/** The data item must be a tag of the expected type. It is an error - * if it is not. For example when calling QCBORDecode_GetEpochDate(), - * the data item must be an @ref CBOR_TAG_DATE_EPOCH tag. See - * @ref Tag-Usage. */ -#define QCBOR_TAG_REQUIREMENT_TAG 0 - -/** The data item must be of the type expected for content data type - * being fetched. It is an error if it is not. For example, when - * calling QCBORDecode_GetEpochDate() and it must not be an @ref - * CBOR_TAG_DATE_EPOCH tag. See @ref Tag-Usage. */ -#define QCBOR_TAG_REQUIREMENT_NOT_A_TAG 1 - -/** Either of the above two are allowed. This allows implementation of - * being liberal in what you receive, but it is better if CBOR-based - * protocols pick one and stick to and not required the reciever to - * take either. See @ref Tag-Usage. */ -#define QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG 2 - -/** Add this into the above value if other tags not processed by QCBOR - * are to be allowed to surround the data item. See @ref Tag-Usage. */ -#define QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS 0x80 - - - - /** * @brief Decode the next item as a byte string * @@ -200,6 +125,8 @@ extern "C" { * * If the CBOR item to decode is not a byte string, the * @ref QCBOR_ERR_UNEXPECTED_TYPE error is set. + * + * See also QCBORDecode_EnterBstrWrapped(). */ static void QCBORDecode_GetByteString(QCBORDecodeContext *pCtx, @@ -746,13 +673,6 @@ QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pCtx, void *pCallbackCtx, QCBORItemCallback pfCB); - -QCBORError -QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pCtx, int64_t nLabel, uint64_t *puTagNumber); - -QCBORError -QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint64_t *puTagNumber); - /** * @brief Decode the next item as a Boolean. * @@ -856,500 +776,6 @@ QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pCtx, -/** - * @brief Decode the next item as a date string. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pDateString The decoded date. - * - * This decodes the standard CBOR date/time string tag, integer tag - * number of 0, or encoded CBOR that is not a tag, but borrows the - * date string content format. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_DATE_STRING, QCBOREncode_AddDateString() and - * @ref QCBOR_TYPE_DATE_STRING. - */ -static void -QCBORDecode_GetDateString(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void -QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void -QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - - -/** - * @brief Decode the next item as a date-only string. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pDateString The decoded date. - * - * This decodes the CBOR date-only string tag, integer tag number of - * 1004, or encoded CBOR that is not a tag, but borrows the date-only - * string content format. An example of the format is "1985-04-12". - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_DAYS_STRING, QCBOREncode_AddDaysString() and - * @ref QCBOR_TYPE_DAYS_STRING. - */ -static void -QCBORDecode_GetDaysString(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void -QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - -static void -QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pDateString); - - -/** - * @brief Decode the next item as an epoch date. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pnTime The decoded epoch date. - * - * This decodes the standard CBOR epoch date/time tag, integer tag - * number of 1. This will also decode any integer or floating-point - * number as an epoch date (a tag 1 epoch date is just an integer or - * floating-point number). - * - * This will set @ref QCBOR_ERR_DATE_OVERFLOW if the input integer - * will not fit in an @c int64_t. Note that an @c int64_t can - * represent a range of over 500 billion years with one second - * resolution. - * - * Floating-point dates are always returned as an @c int64_t. The - * fractional part is discarded. - * - * If the input is a floating-point date and the QCBOR library is - * compiled with some or all floating-point features disabled, the - * following errors will be set. If the input is half-precision and - * half-precision is disabled @ref QCBOR_ERR_HALF_PRECISION_DISABLED - * is set. This function needs hardware floating-point to convert the - * floating-point value to an integer so if HW floating point is - * disabled @ref QCBOR_ERR_HW_FLOAT_DISABLED is set. If all - * floating-point is disabled then @ref QCBOR_ERR_ALL_FLOAT_DISABLED - * is set. A previous version of this function would return - * @ref QCBOR_ERR_FLOAT_DATE_DISABLED in some, but not all, cases when - * floating-point decoding was disabled. - * - * Floating-point dates that are plus infinity, minus infinity or NaN - * (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW - * error. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_DATE_EPOCH, QCBOREncode_AddTDateEpoch() and - * @ref QCBOR_TYPE_DATE_EPOCH. -*/ -void -QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnTime); - -void -QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnTime); - -void -QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnTime); - - -/** - * @brief Decode the next item as an days-count epoch date. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pnDays The decoded epoch date. - * - * This decodes the CBOR epoch date tag, integer tag number of 100, or - * encoded CBOR that is not a tag, but borrows the content format. The - * date is the number of days (not number of seconds) before or after - * Jan 1, 1970. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_DAYS_EPOCH, QCBOREncode_AddTDaysEpoch() and - * @ref QCBOR_TYPE_DAYS_EPOCH. -*/ -void -QCBORDecode_GetEpochDays(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - int64_t *pnDays); - -void -QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnDays); - -void -QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnDays); - - - - -/** - * @brief Decode the next item as a URI. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pURI The decoded URI. - * - * This decodes a standard CBOR URI tag, integer tag number of 32, or - * encoded CBOR that is not a tag, that is a URI encoded in a text - * string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_URI, QCBOREncode_AddTURI() and - * @ref QCBOR_TYPE_URI. - */ -static void -QCBORDecode_GetURI(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pURI); - -static void -QCBORDecode_GetURIInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pURI); - -static void -QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pCtx, - const char * szLabel, - uint8_t uTagRequirement, - UsefulBufC *pURI); - - -/** - * @brief Decode the next item as base64 encoded text. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pB64Text The decoded base64 text. - * - * This decodes a standard CBOR base64 tag, integer tag number of 34, - * or encoded CBOR that is not a tag, that is base64 encoded bytes - * encoded in a text string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * Note that this does not actually remove the base64 encoding. - * - * See also @ref CBOR_TAG_B64, QCBOREncode_AddB64Text() and - * @ref QCBOR_TYPE_BASE64. - */ -static void -QCBORDecode_GetB64(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void -QCBORDecode_GetB64InMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void -QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -/** - * @brief Decode the next item as base64URL encoded text. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pB64Text The decoded base64 text. - * - * This decodes a standard CBOR base64url tag, integer tag number of - * 33, or encoded CBOR that is not a tag, that is base64url encoded - * bytes encoded in a text string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * Note that this does not actually remove the base64url encoding. - * - * See also @ref CBOR_TAG_B64URL, QCBOREncode_AddTB64URLText() and - * @ref QCBOR_TYPE_BASE64URL. - */ -static void -QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void -QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -static void -QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pB64Text); - -/** - * @brief Decode the next item as a regular expression. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pRegex The decoded regular expression. - * - * This decodes a standard CBOR regex tag, integer tag number of 35, - * or encoded CBOR that is not a tag, that is a PERL-compatible - * regular expression encoded in a text string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_REGEX, QCBOREncode_AddTRegex() and - * @ref QCBOR_TYPE_REGEX. - */ -static void -QCBORDecode_GetRegex(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - -static void -QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - -static void -QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pCtx, - const char * szLabel, - uint8_t uTagRequirement, - UsefulBufC *pRegex); - - -/** - * @brief Decode the next item as a MIME message. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pMessage The decoded regular expression. - * @param[out] pbIsTag257 @c true if tag was 257. May be @c NULL. - * - * This decodes the standard CBOR MIME and binary MIME tags, integer - * tag numbers of 36 or 257, or encoded CBOR that is not a tag, that - * is a MIME message encoded in a text or binary string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * The MIME message itself is not parsed. - * - * This decodes both tag 36 and 257. If it is tag 257, pbIsTag257 is - * @c true. The difference between the two is that tag 36 is utf8 and - * tag 257 is a byte string that can carry binary MIME. QCBOR - * processes them exactly the same. Possibly the difference can be - * ignored. NULL can be passed to have no value returned. - * - * See also @ref CBOR_TAG_MIME, @ref CBOR_TAG_BINARY_MIME, - * QCBOREncode_AddTMIMEData(), @ref QCBOR_TYPE_MIME and - * @ref QCBOR_TYPE_BINARY_MIME. - * - * This does no translation of line endings. See QCBOREncode_AddText() - * for a discussion of line endings in CBOR. - */ -void -QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - - void -QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - - -void -QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257); - -/** - * @brief Decode the next item as a UUID. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pUUID The decoded UUID - * - * This decodes a standard CBOR UUID tag, integer tag number of 37, or - * encoded CBOR that is not a tag, that is a UUID encoded in a byte - * string. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See @ref Tag-Usage for discussion on tag requirements. - * - * See also @ref CBOR_TAG_BIN_UUID, QCBOREncode_AddTBinaryUUID() and - * @ref QCBOR_TYPE_UUID. - */ -static void -QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - -static void -QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - -static void -QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pUUID); - - - -/** - * @brief Decode some byte-string wrapped CBOR. - * - * @param[in] pCtx The decode context. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. - * @param[out] pBstr Pointer and length of byte-string wrapped CBOR (optional). - * - * This is for use on some CBOR that has been wrapped in a byte - * string. There are several ways that this can occur. - * - * First is tag 24 and tag 63. Tag 24 wraps a single CBOR data item - * and 63 a CBOR sequence. This implementation doesn't distinguish - * between the two (it would be more code and doesn't seem important). - * - * The @ref Tag-Usage discussion on the tag requirement applies here - * just the same as any other tag. - * - * In other cases, CBOR is wrapped in a byte string, but it is - * identified as CBOR by other means. The contents of a COSE payload - * are one example of that. They can be identified by the COSE content - * type, or they can be identified as CBOR indirectly by the protocol - * that uses COSE. for example, if a blob of CBOR is identified as a - * CWT, then the COSE payload is CBOR. To enter into CBOR of this - * type use the @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG as the \c - * uTagRequirement argument. - * - * Note that byte string wrapped CBOR can also be decoded by getting - * the byte string with QCBORDecode_GetItem() or - * QCBORDecode_GetByteString() and feeding it into another instance of - * QCBORDecode. Doing it with this function has the advantage of using - * less memory as another instance of QCBORDecode is not necessary. - * - * When the wrapped CBOR is entered with this function, the pre-order - * traversal and such are bounded to the wrapped - * CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume - * processing CBOR outside the wrapped CBOR. - * - * This does not work on indefinite-length strings. The - * error @ref QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING will be set. - * - * If @c pBstr is not @c NULL the pointer and length of the wrapped - * CBOR will be returned. This is usually not needed, but sometimes - * useful, particularly in the case of verifying signed data like the - * COSE payload. This is usually the pointer and length of the data is - * that is hashed or MACed. - * - * Please see @ref Decode-Errors-Overview "Decode Errors Overview". - * - * See also QCBORDecode_ExitBstrWrapped(), QCBORDecode_EnterMap() and - * QCBORDecode_EnterArray(). - */ -void -QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pCtx, - uint8_t uTagRequirement, - UsefulBufC *pBstr); - -void -QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, - int64_t nLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr); - -void -QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, - const char *szLabel, - uint8_t uTagRequirement, - UsefulBufC *pBstr); - - -/** - * @brief Exit some bstr-wrapped CBOR has been enetered. - * - * @param[in] pCtx The decode context. - * - * Bstr-wrapped CBOR must have been entered for this to succeed. - * - * The items in the wrapped CBOR that was entered do not have to have - * been consumed for this to succeed. - * - * The this sets the traversal cursor to the item after the - * byte string that was exited. - */ -void -QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx); - - - /* ========================================================================= * @@ -1368,36 +794,20 @@ void QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pCtx, uint8_t uType); - /* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - uint8_t uQCBOR_Type, - uint64_t uTagNumber, - UsefulBufC *pBstr); - -void -QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const uint8_t uQCBOR_Type, - const uint64_t uTagNumber, - UsefulBufC *pString); - - - - - +QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pCtx, + uint8_t uType, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); +/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ void -QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - uint8_t uQCBOR_Type, - uint64_t uTagNumber, - UsefulBufC *pString); +QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pCtx, + QCBORItem *pTarget, + QCBORItem *pItem, + UsefulBufC *pEncodedCBOR); @@ -1425,22 +835,6 @@ QCBORDecode_ExitMap(QCBORDecodeContext *pMe) } -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_GetArrayOrMap(QCBORDecodeContext *pCtx, - uint8_t uType, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - - -/* Semi-private funcion used by public inline functions. See qcbor_decode.c */ -void -QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pCtx, - QCBORItem *pTarget, - QCBORItem *pItem, - UsefulBufC *pEncodedCBOR); - - static inline void QCBORDecode_GetArray(QCBORDecodeContext *pMe, QCBORItem *pItem, @@ -1687,296 +1081,6 @@ QCBORDecode_GetUndefinedInMapSZ(QCBORDecodeContext *pMe, } - -static inline void -QCBORDecode_GetDateString(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pValue) -{ - QCBORDecode_Private_GetTaggedString(pMe, - uTagRequirement, - QCBOR_TYPE_DATE_STRING, - CBOR_TAG_DATE_STRING, - pValue); -} - -static inline void -QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pText) -{ - QCBORDecode_Private_GetTaggedStringInMapN(pMe, - nLabel, - uTagRequirement, - QCBOR_TYPE_DATE_STRING, - CBOR_TAG_DATE_STRING, - pText); -} - -static inline void -QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pText) -{ - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, - szLabel, - uTagRequirement, - QCBOR_TYPE_DATE_STRING, - CBOR_TAG_DATE_STRING, - pText); -} - -static inline void -QCBORDecode_GetDaysString(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pValue) -{ - QCBORDecode_Private_GetTaggedString(pMe, - uTagRequirement, - QCBOR_TYPE_DATE_STRING, - CBOR_TAG_DATE_STRING, - pValue); -} - -static inline void -QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pText) -{ - QCBORDecode_Private_GetTaggedStringInMapN(pMe, - nLabel, - uTagRequirement, - QCBOR_TYPE_DAYS_STRING, - CBOR_TAG_DAYS_STRING, - pText); -} - - -static inline void -QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pText) -{ - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, - szLabel, - uTagRequirement, - QCBOR_TYPE_DAYS_STRING, - CBOR_TAG_DAYS_STRING, - pText); - -} - - - -static inline void -QCBORDecode_GetURI(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - QCBORDecode_Private_GetTaggedString(pMe, - uTagRequirement, - QCBOR_TYPE_URI, - CBOR_TAG_URI, - pUUID); -} - -static inline void -QCBORDecode_GetURIInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - QCBORDecode_Private_GetTaggedStringInMapN(pMe, - nLabel, - uTagRequirement, - QCBOR_TYPE_URI, - CBOR_TAG_URI, - pUUID); -} - -static inline void -QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, - szLabel, - uTagRequirement, - QCBOR_TYPE_URI, - CBOR_TAG_URI, - pUUID); -} - - -static inline void -QCBORDecode_GetB64(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - QCBORDecode_Private_GetTaggedString(pMe, - uTagRequirement, - QCBOR_TYPE_BASE64, - CBOR_TAG_B64, - pB64Text); -} - -static inline void -QCBORDecode_GetB64InMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - QCBORDecode_Private_GetTaggedStringInMapN(pMe, - nLabel, - uTagRequirement, - QCBOR_TYPE_BASE64, - CBOR_TAG_B64, - pB64Text); -} - -static inline void -QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, - szLabel, - uTagRequirement, - QCBOR_TYPE_BASE64, - CBOR_TAG_B64, - pB64Text); -} - - -static inline void -QCBORDecode_GetB64URL(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - QCBORDecode_Private_GetTaggedString(pMe, - uTagRequirement, - QCBOR_TYPE_BASE64URL, - CBOR_TAG_B64URL, - pB64Text); -} - -static inline void -QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - QCBORDecode_Private_GetTaggedStringInMapN(pMe, - nLabel, - uTagRequirement, - QCBOR_TYPE_BASE64URL, - CBOR_TAG_B64URL, - pB64Text); -} - -static inline void -QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pB64Text) -{ - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, - szLabel, - uTagRequirement, - QCBOR_TYPE_BASE64URL, - CBOR_TAG_B64URL, - pB64Text); -} - - -static inline void -QCBORDecode_GetRegex(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pRegex) -{ - QCBORDecode_Private_GetTaggedString(pMe, - uTagRequirement, - QCBOR_TYPE_REGEX, - CBOR_TAG_REGEX, - pRegex); -} - -static inline void -QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pRegex) -{ - QCBORDecode_Private_GetTaggedStringInMapN(pMe, - nLabel, - uTagRequirement, - QCBOR_TYPE_REGEX, - CBOR_TAG_REGEX, - pRegex); -} - - -static inline void -QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pMe, - const char * szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pRegex) -{ - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, - szLabel, - uTagRequirement, - QCBOR_TYPE_REGEX, - CBOR_TAG_REGEX, - pRegex); -} - - -static inline void -QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - QCBORDecode_Private_GetTaggedString(pMe, - uTagRequirement, - QCBOR_TYPE_UUID, - CBOR_TAG_BIN_UUID, - pUUID); -} - -static inline void -QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - QCBORDecode_Private_GetTaggedStringInMapN(pMe, - nLabel, - uTagRequirement, - QCBOR_TYPE_UUID, - CBOR_TAG_BIN_UUID, - pUUID); -} - -static inline void -QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pUUID) -{ - QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, - szLabel, - uTagRequirement, - QCBOR_TYPE_UUID, - CBOR_TAG_BIN_UUID, - pUUID); -} - /* ======================================================================== * * END OF PRIVATE INLINE IMPLEMENTATION * * ======================================================================== */ diff --git a/inc/qcbor/qcbor_tag_decode.h b/inc/qcbor/qcbor_tag_decode.h index d952387..7f92a48 100644 --- a/inc/qcbor/qcbor_tag_decode.h +++ b/inc/qcbor/qcbor_tag_decode.h @@ -1,5 +1,5 @@ /* ========================================================================== - * qcbor_tag_decode.h -- Tag content decoders + * qcbor_tag_decode.h -- Tag decoding * * Copyright (c) 2024, Laurence Lundblade. All rights reserved. * @@ -7,7 +7,7 @@ * * See BSD-3-Clause license in README.md * - * Created on 9/5/24 + * Forked from qcbor_decode.c on 9/5/24 * ========================================================================== */ #ifndef qcbor_tag_decode_h @@ -42,34 +42,742 @@ extern "C" { * ## Tags Decoding * * TODO: lots to write here + * + * * @anchor Tag-Usage + * ## Tag Usage + * + * Data types beyond the basic CBOR types of numbers, strings, maps and + * arrays are called tags. The main registry of these new types is in + * the IANA CBOR tags registry. These new types may be simple such a + * number that is to be interpreted as a date, or of moderate complexity + * such as defining a decimal fraction that is an array containing a + * mantissa and exponent, or complex such as format for signing and + * encryption. + * + * When a tag occurs in a protocol it is encoded as an integer tag + * number plus the content of the tag. + * + * The content format of a tag may also be "borrowed". For example, a + * protocol definition may say that a particular data item is an epoch + * date just like tag 1, but not actually tag 1. In practice the + * difference is the presence or absence of the integer tag number in + * the encoded CBOR. + * + * The decoding functions for these new types takes a tag requirement + * parameter to say whether the item is a tag, is just borrowing the + * content format and is not a tag, or whether either is OK. + * + * If the parameter indicates the item must be a tag (@ref + * QCBOR_TAG_REQUIREMENT_TAG), then @ref QCBOR_ERR_UNEXPECTED_TYPE is + * set if it is not one of the expected tag types. To decode correctly + * the contents of the tag must also be of the correct type. For + * example, to decode an epoch date tag the content must be an integer + * or floating-point value. + * + * If the parameter indicates it should not be a tag + * (@ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG), then + * @ref QCBOR_ERR_UNEXPECTED_TYPE set if it is a tag or the type of the + * encoded CBOR is not what is expected. In the example of an epoch + * date, the data type must be an integer or floating-point value. This + * is the case where the content format of a tag is borrowed. + * + * The parameter can also indicate that either a tag or no tag is + * allowed ( @ref QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG ). A good protocol + * design should however be clear and choose one or the other and not + * need this option. This is a way to implement "be liberal in what you + * accept", however these days that is less in favor. See + * https://tools.ietf.org/id/draft-thomson-postel-was-wrong-03.html. + * + * Map searching works with indefinite length strings. A string + * allocator must be set up the same as for any handling of indefinite + * length strings. However, It currently over-allocates memory from the + * string pool and thus requires a much larger string pool than it + * should. The over-allocation happens every time a map is searched by + * label. (This may be corrected in the future). + * + * + * TODO: this text isn't right + * In v1, some spiffy decode functions ignored tag numbers and + * some didn't. For example, GetInt64 ignored and GetString didn't. + * The "GetXxx" where Xxxx is a tag ignore conditionally based + * on an argument. + * (Would be good to verify this with tests) + * + * Do we fix the behavior of GetString in v1? Relax so it + * allows tag numbers like the rest? Probably. + * + * In v2, the whole mechanism is with GetTagNumbers. They are + * never ignored and they must always be consumed. + * + * With v2 in v1 mode, the functions that were ignoring + * tags must go back to ignoring them. + * + * How does TagRequirement work in v2? + * + * GetInt64 and GetString require all tag numbs to be processed + * to work. */ -/* - TODO: integrate this - In v1, some spiffy decode functions ignored tag numbers and - some didn't. For example, GetInt64 ignored and GetString didn't. - The "GetXxx" where Xxxx is a tag ignore conditionally based - on an argument. - (Would be good to verify this with tests) +/** The data item must be a tag of the expected type. It is an error + * if it is not. For example when calling QCBORDecode_GetEpochDate(), + * the data item must be an @ref CBOR_TAG_DATE_EPOCH tag. See + * @ref Tag-Usage. */ +#define QCBOR_TAG_REQUIREMENT_TAG 0 - Do we fix the behavior of GetString in v1? Relax so it - allows tag numbers like the rest? Probably. +/** The data item must be of the type expected for content data type + * being fetched. It is an error if it is not. For example, when + * calling QCBORDecode_GetEpochDate() and it must not be an @ref + * CBOR_TAG_DATE_EPOCH tag. See @ref Tag-Usage. */ +#define QCBOR_TAG_REQUIREMENT_NOT_A_TAG 1 - In v2, the whole mechanism is with GetTagNumbers. They are - never ignored and they must always be consumed. +/** Either of the above two are allowed. This allows implementation of + * being liberal in what you receive, but it is better if CBOR-based + * protocols pick one and stick to and not required the reciever to + * take either. See @ref Tag-Usage. */ +#define QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG 2 - With v2 in v1 mode, the functions that were ignoring - tags must go back to ignoring them. +/** Add this into the above value if other tags not processed by QCBOR + * are to be allowed to surround the data item. See @ref Tag-Usage. */ +#define QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS 0x80 - How does TagRequirement work in v2? - GetInt64 and GetString require all tag numbs to be processed - to work. +#ifndef QCBOR_DISABLE_TAGS +/** + * @brief Returns the tag numbers for an item. + * + * @param[in] pCtx The decoder context. + * @param[out] puTagNumber The returned tag number. + * + * In QCBOR v2, all tag numbers on an item MUST be fetched with this + * method. If not, @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER will + * occur. This is a major change from QCBORv1. The QCBOR v1 behavior + * is too lax for proper CBOR decoding. When a tag number occurs it + * indicates the item is a new data type (except for a few tag numbers + * that are hints). Note also that in RFC 7049, tag numbers were + * incorrectly characterized as optional implying they could be + * ignored. + * + * In typical item decoding, tag numbers are not used, not present and + * not expected. There's no need to call this. + * + * When the protocol being decoded does use a tag number then this + * must be called for the items were the tag numbers occur before the + * items themselves are decoded. Making this call prevents the + * @ref QCBOR_ERR_UNPROCESSED_TAG_NUMBER error, but the caller still has to + * check that the tag number is the right one. Probably the tag number + * will be used to switch the flow of the decoder. + * + * It's possible that an item might use the presence/absence of a tag + * number to switch the flow of decoding. If there's a possibility of + * a tag number then this must be called. + * + * If this is called and there is no tag number, then this will return + * @ref QCBOR_SUCCESS and the tag number returned will be + * @ref CBOR_TAG_INVALID64. + * + * Usually there is only one tag number per item, but CBOR allows + * more. That it allows nesting of tags where the content of one tag + * is another tag. If there are multiple tag numbers, this must be + * called multiple times. This only returns one tag number at a time, + * because tag numbers are typically processed one at a time. + * + * If there is an error decoding the tag or the item it is on, the + * error code will be set and the tag number @ref CBOR_TAG_INVALID64 + * will be returned. That is, @ref CBOR_TAG_INVALID64 will be returned if + * there is a decode error or there is no tag number. + */ +void +QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber); +/** + * @brief Returns the tag numbers for an item. + * + * @param[in] pCtx The decoder context. + * @param[out] puTagNumber The returned tag number. + * + * @return See error table of decoding errors set by QCBORDecode_VGetNext(). + * + * Like QCBORDecode_VGetNextTagNumber(), but returns the + * error rather than set last error. */ +QCBORError +QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pCtx, uint64_t *puTagNumber); + +QCBORError +QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pCtx, int64_t nLabel, uint64_t *puTagNumber); + + +QCBORError +QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pCtx, const char *szLabel, uint64_t *puTagNumber); + + + +/** + * @brief Returns the tag numbers for a decoded item. + * + * @param[in] pCtx The decoder context. + * @param[in] pItem The CBOR item to get the tag for. + * @param[in] uIndex The index of the tag to get. + * + * @returns The nth tag number or @ref CBOR_TAG_INVALID64. + * + * Typically, this is only used with @ref QCBOR_DECODE_CONFIG_UNPROCESSED_TAG_NUMBERS. + * Normally, tag numbers are processed QCBORDecode_VGetNextTagNumber() or + * QCBORTagContentCallBack. + * + * When QCBOR decodes an item that is a tag, it will fully decode tags + * it is able to. Tags that it is unable to process are put in a list + * in the QCBORItem. + * + * Tags nest. Here the tag with index 0 is the outermost, the one + * furthest form the data item that is the tag content. This is + * the opposite order of QCBORDecode_GetNthTag(), but more + * useful. + * + * Deep tag nesting is rare so this implementation imposes a limit of + * @ref QCBOR_MAX_TAGS_PER_ITEM on nesting and returns @ref + * QCBOR_ERR_TOO_MANY_TAGS if there are more. This is a limit of this + * implementation, not of CBOR. (To be able to handle deeper nesting, + * the constant can be increased and the library recompiled. It will + * use more memory). + * + * See also @ref Tag-Decoding @ref CBORTags, @ref Tag-Usage and @ref Tags-Overview. + * + * To reduce memory used by a @ref QCBORItem, tag numbers larger than + * @c UINT16_MAX are mapped so the tag numbers in @c uTags should be + * accessed with this function rather than directly. + * + * This returns @ref CBOR_TAG_INVALID64 if any error occurred when + * getting the item. This is also returned if there are no tags on the + * item or no tag at @c uIndex. + */ +uint64_t +QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint8_t uIndex); + + +/** + * @brief Returns the tag numbers for last-decoded item. + * + * @param[in] pCtx The decoder context. + * @param[in] uIndex The index of the tag to get. + * + * @returns The nth tag number or @ref CBOR_TAG_INVALID64. + * + * This returns tags of the most recently decoded item. See + * QCBORDecode_GetNthTagNumber(). This is particularly of use for spiffy + * decode functions that don't return a @ref QCBORItem. + * + * This does not work for QCBORDecode_GetNext(), + * QCBORDecode_PeekNext(), QCBORDecode_VPeekNext() or + * QCBORDecode_VGetNextConsume() but these all return a + * @ref QCBORItem, so it is not necessary. + * + * If a decoding error is set, then this returns @ref CBOR_TAG_INVALID64. + */ +uint64_t +QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pCtx, uint8_t uIndex); + +#endif /* ! QCBOR_DISABLE_TAGS */ + + + + +/** + * @brief Decode some byte-string wrapped CBOR. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pBstr Pointer and length of byte-string wrapped CBOR (optional). + * + * This is for use on some CBOR that has been wrapped in a byte + * string. There are several ways that this can occur. + * + * First is tag 24 and tag 63. Tag 24 wraps a single CBOR data item + * and 63 a CBOR sequence. This implementation doesn't distinguish + * between the two (it would be more code and doesn't seem important). + * + * The @ref Tag-Usage discussion on the tag requirement applies here + * just the same as any other tag. + * + * In other cases, CBOR is wrapped in a byte string, but it is + * identified as CBOR by other means. The contents of a COSE payload + * are one example of that. They can be identified by the COSE content + * type, or they can be identified as CBOR indirectly by the protocol + * that uses COSE. for example, if a blob of CBOR is identified as a + * CWT, then the COSE payload is CBOR. To enter into CBOR of this + * type use the @ref QCBOR_TAG_REQUIREMENT_NOT_A_TAG as the \c + * uTagRequirement argument. + * + * Note that byte string wrapped CBOR can also be decoded by getting + * the byte string with QCBORDecode_GetItem() or + * QCBORDecode_GetByteString() and feeding it into another instance of + * QCBORDecode. Doing it with this function has the advantage of using + * less memory as another instance of QCBORDecode is not necessary. + * + * When the wrapped CBOR is entered with this function, the pre-order + * traversal and such are bounded to the wrapped + * CBOR. QCBORDecode_ExitBstrWrapped() must be called to resume + * processing CBOR outside the wrapped CBOR. + * + * This does not work on indefinite-length strings. The + * error @ref QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING will be set. + * + * If @c pBstr is not @c NULL the pointer and length of the wrapped + * CBOR will be returned. This is usually not needed, but sometimes + * useful, particularly in the case of verifying signed data like the + * COSE payload. This is usually the pointer and length of the data is + * that is hashed or MACed. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See also QCBORDecode_ExitBstrWrapped(), QCBORDecode_EnterMap() and + * QCBORDecode_EnterArray(). + */ +void +QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pBstr); + +void +QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pBstr); + +void +QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pBstr); + + +/** + * @brief Exit some bstr-wrapped CBOR has been enetered. + * + * @param[in] pCtx The decode context. + * + * Bstr-wrapped CBOR must have been entered for this to succeed. + * + * The items in the wrapped CBOR that was entered do not have to have + * been consumed for this to succeed. + * + * The this sets the traversal cursor to the item after the + * byte string that was exited. + */ +void +QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pCtx); + + + + +/** + * @brief Decode the next item as a date string. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pDateString The decoded date. + * + * This decodes the standard CBOR date/time string tag, integer tag + * number of 0, or encoded CBOR that is not a tag, but borrows the + * date string content format. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DATE_STRING, QCBOREncode_AddDateString() and + * @ref QCBOR_TYPE_DATE_STRING. + */ +static void +QCBORDecode_GetDateString(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pDateString); + +static void +QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); + +static void +QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); + + +/** + * @brief Decode the next item as an epoch date. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnTime The decoded epoch date. + * + * This decodes the standard CBOR epoch date/time tag, integer tag + * number of 1. This will also decode any integer or floating-point + * number as an epoch date (a tag 1 epoch date is just an integer or + * floating-point number). + * + * This will set @ref QCBOR_ERR_DATE_OVERFLOW if the input integer + * will not fit in an @c int64_t. Note that an @c int64_t can + * represent a range of over 500 billion years with one second + * resolution. + * + * Floating-point dates are always returned as an @c int64_t. The + * fractional part is discarded. + * + * If the input is a floating-point date and the QCBOR library is + * compiled with some or all floating-point features disabled, the + * following errors will be set. If the input is half-precision and + * half-precision is disabled @ref QCBOR_ERR_HALF_PRECISION_DISABLED + * is set. This function needs hardware floating-point to convert the + * floating-point value to an integer so if HW floating point is + * disabled @ref QCBOR_ERR_HW_FLOAT_DISABLED is set. If all + * floating-point is disabled then @ref QCBOR_ERR_ALL_FLOAT_DISABLED + * is set. A previous version of this function would return + * @ref QCBOR_ERR_FLOAT_DATE_DISABLED in some, but not all, cases when + * floating-point decoding was disabled. + * + * Floating-point dates that are plus infinity, minus infinity or NaN + * (not-a-number) will result in the @ref QCBOR_ERR_DATE_OVERFLOW + * error. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DATE_EPOCH, QCBOREncode_AddTDateEpoch() and + * @ref QCBOR_TYPE_DATE_EPOCH. +*/ +void +QCBORDecode_GetEpochDate(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnTime); + +void +QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnTime); + +void +QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnTime); + + + +/** + * @brief Decode the next item as a date-only string. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pDateString The decoded date. + * + * This decodes the CBOR date-only string tag, integer tag number of + * 1004, or encoded CBOR that is not a tag, but borrows the date-only + * string content format. An example of the format is "1985-04-12". + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DAYS_STRING, QCBOREncode_AddDaysString() and + * @ref QCBOR_TYPE_DAYS_STRING. + */ +static void +QCBORDecode_GetDaysString(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pDateString); + +static void +QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); + +static void +QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pDateString); + + +/** + * @brief Decode the next item as an days-count epoch date. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pnDays The decoded epoch date. + * + * This decodes the CBOR epoch date tag, integer tag number of 100, or + * encoded CBOR that is not a tag, but borrows the content format. The + * date is the number of days (not number of seconds) before or after + * Jan 1, 1970. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_DAYS_EPOCH, QCBOREncode_AddTDaysEpoch() and + * @ref QCBOR_TYPE_DAYS_EPOCH. +*/ +void +QCBORDecode_GetEpochDays(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + int64_t *pnDays); + +void +QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnDays); + +void +QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnDays); + + +/** + * @brief Decode the next item as a URI. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pURI The decoded URI. + * + * This decodes a standard CBOR URI tag, integer tag number of 32, or + * encoded CBOR that is not a tag, that is a URI encoded in a text + * string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_URI, QCBOREncode_AddTURI() and + * @ref QCBOR_TYPE_URI. + */ +static void +QCBORDecode_GetURI(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pURI); + +static void +QCBORDecode_GetURIInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pURI); + +static void +QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pCtx, + const char * szLabel, + uint8_t uTagRequirement, + UsefulBufC *pURI); + + +/** + * @brief Decode the next item as base64 encoded text. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pB64Text The decoded base64 text. + * + * This decodes a standard CBOR base64 tag, integer tag number of 34, + * or encoded CBOR that is not a tag, that is base64 encoded bytes + * encoded in a text string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * Note that this does not actually remove the base64 encoding. + * + * See also @ref CBOR_TAG_B64, QCBOREncode_AddB64Text() and + * @ref QCBOR_TYPE_BASE64. + */ +static void +QCBORDecode_GetB64(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); + +static void +QCBORDecode_GetB64InMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); + +static void +QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); + +/** + * @brief Decode the next item as base64URL encoded text. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pB64Text The decoded base64 text. + * + * This decodes a standard CBOR base64url tag, integer tag number of + * 33, or encoded CBOR that is not a tag, that is base64url encoded + * bytes encoded in a text string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * Note that this does not actually remove the base64url encoding. + * + * See also @ref CBOR_TAG_B64URL, QCBOREncode_AddTB64URLText() and + * @ref QCBOR_TYPE_BASE64URL. + */ +static void +QCBORDecode_GetB64URL(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); + +static void +QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); + +static void +QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pB64Text); + +/** + * @brief Decode the next item as a regular expression. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pRegex The decoded regular expression. + * + * This decodes a standard CBOR regex tag, integer tag number of 35, + * or encoded CBOR that is not a tag, that is a PERL-compatible + * regular expression encoded in a text string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_REGEX, QCBOREncode_AddTRegex() and + * @ref QCBOR_TYPE_REGEX. + */ +static void +QCBORDecode_GetRegex(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pRegex); + +static void +QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pRegex); + +static void +QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pCtx, + const char * szLabel, + uint8_t uTagRequirement, + UsefulBufC *pRegex); + + +/** + * @brief Decode the next item as a MIME message. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pMessage The decoded regular expression. + * @param[out] pbIsTag257 @c true if tag was 257. May be @c NULL. + * + * This decodes the standard CBOR MIME and binary MIME tags, integer + * tag numbers of 36 or 257, or encoded CBOR that is not a tag, that + * is a MIME message encoded in a text or binary string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * The MIME message itself is not parsed. + * + * This decodes both tag 36 and 257. If it is tag 257, pbIsTag257 is + * @c true. The difference between the two is that tag 36 is utf8 and + * tag 257 is a byte string that can carry binary MIME. QCBOR + * processes them exactly the same. Possibly the difference can be + * ignored. NULL can be passed to have no value returned. + * + * See also @ref CBOR_TAG_MIME, @ref CBOR_TAG_BINARY_MIME, + * QCBOREncode_AddTMIMEData(), @ref QCBOR_TYPE_MIME and + * @ref QCBOR_TYPE_BINARY_MIME. + * + * This does no translation of line endings. See QCBOREncode_AddText() + * for a discussion of line endings in CBOR. + */ +void +QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pMessage, + bool *pbIsTag257); + + void +QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pMessage, + bool *pbIsTag257); + + +void +QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pMessage, + bool *pbIsTag257); + +/** + * @brief Decode the next item as a UUID. + * + * @param[in] pCtx The decode context. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX. + * @param[out] pUUID The decoded UUID + * + * This decodes a standard CBOR UUID tag, integer tag number of 37, or + * encoded CBOR that is not a tag, that is a UUID encoded in a byte + * string. + * + * Please see @ref Decode-Errors-Overview "Decode Errors Overview". + * + * See @ref Tag-Usage for discussion on tag requirements. + * + * See also @ref CBOR_TAG_BIN_UUID, QCBOREncode_AddTBinaryUUID() and + * @ref QCBOR_TYPE_UUID. + */ +static void +QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pCtx, + uint8_t uTagRequirement, + UsefulBufC *pUUID); + +static void +QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pCtx, + int64_t nLabel, + uint8_t uTagRequirement, + UsefulBufC *pUUID); + +static void +QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pCtx, + const char *szLabel, + uint8_t uTagRequirement, + UsefulBufC *pUUID); + + /** @@ -354,10 +1062,89 @@ QCBORDecode_ExpMantissaTagCB(QCBORDecodeContext *pDecodeCtx, +/* ========================================================================= * + * BEGINNING OF DEPRECATED FUNCTIONS * + * * + * There is no plan to remove these in future versions. * + * They just have been replaced by something better. * + * ========================================================================= */ + +#ifndef QCBOR_DISABLE_TAGS + +/** + * @brief Returns the tag numbers for an item. (deprecated). + * + * @param[in] pCtx The decoder context. + * @param[in] uIndex The index of the tag to get. + * + * This is the same as QCBORDecode_GetNthTagNumber() but the order is + * opposite when there are multiple tags. @c uIndex 0 is the tag + * number closest to the tag content. QCBORDecode_GetNthTagNumber() is + * more useful for checking the next tag number and switching the + * decode flow. + */ +uint64_t +QCBORDecode_GetNthTag(QCBORDecodeContext *pCtx, const QCBORItem *pItem, uint32_t uIndex); + + +/** + * @brief Returns the tag numbers for last-decoded item (deprecated). + * + * @param[in] pCtx The decoder context. + * @param[in] uIndex The index of the tag to get. + * + * @returns The nth tag number or CBOR_TAG_INVALID64. + * + * This is the same as QCBORDecode_GetNthTagNumberOfLast() but the + * order is opposite when there are multiple tags. @c uIndex 0 is the + * tag number closest to the tag content. + * QCBORDecode_GetNthTagNumber() is more useful for checking + * the next tag number and switching the decode flow. + */ +uint64_t +QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pCtx, uint32_t uIndex); + +#endif /* ! QCBOR_DISABLE_TAGS */ + + +/* ========================================================================= * + * END OF DEPRECATED FUNCTIONS * + * ========================================================================= */ + + + /* ========================================================================= * * BEGINNING OF PRIVATE INLINE IMPLEMENTATION * * ========================================================================= */ +/* Semi-private used by public inline functions. See qcbor_tag_decode.c */ +void +QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe, + uint8_t uTagRequirement, + uint8_t uQCBOR_Type, + uint64_t uTagNumber, + UsefulBufC *pBstr); + +/* Semi-private used by public inline functions. See qcbor_tag_decode.c */ +void +QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const uint8_t uQCBOR_Type, + const uint64_t uTagNumber, + UsefulBufC *pString); + +/* Semi-private used by public inline functions. See qcbor_tag_decode.c */ +void +QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t uTagRequirement, + uint8_t uQCBOR_Type, + uint64_t uTagNumber, + UsefulBufC *pString); + + + #ifndef QCBOR_DISABLE_TAGS static inline void @@ -372,6 +1159,295 @@ QCBORDecode_InstallTagDecoders(QCBORDecodeContext *pMe, #endif /* ! QCBOR_DISABLE_TAGS */ + + +static inline void +QCBORDecode_GetDateString(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pValue) +{ + QCBORDecode_Private_GetTaggedString(pMe, + uTagRequirement, + QCBOR_TYPE_DATE_STRING, + CBOR_TAG_DATE_STRING, + pValue); +} + +static inline void +QCBORDecode_GetDateStringInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pText) +{ + QCBORDecode_Private_GetTaggedStringInMapN(pMe, + nLabel, + uTagRequirement, + QCBOR_TYPE_DATE_STRING, + CBOR_TAG_DATE_STRING, + pText); +} + +static inline void +QCBORDecode_GetDateStringInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pText) +{ + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, + szLabel, + uTagRequirement, + QCBOR_TYPE_DATE_STRING, + CBOR_TAG_DATE_STRING, + pText); +} + +static inline void +QCBORDecode_GetDaysString(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pValue) +{ + QCBORDecode_Private_GetTaggedString(pMe, + uTagRequirement, + QCBOR_TYPE_DATE_STRING, + CBOR_TAG_DATE_STRING, + pValue); +} + +static inline void +QCBORDecode_GetDaysStringInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pText) +{ + QCBORDecode_Private_GetTaggedStringInMapN(pMe, + nLabel, + uTagRequirement, + QCBOR_TYPE_DAYS_STRING, + CBOR_TAG_DAYS_STRING, + pText); +} + +static inline void +QCBORDecode_GetDaysStringInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pText) +{ + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, + szLabel, + uTagRequirement, + QCBOR_TYPE_DAYS_STRING, + CBOR_TAG_DAYS_STRING, + pText); + +} + + +static inline void +QCBORDecode_GetURI(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pUUID) +{ + QCBORDecode_Private_GetTaggedString(pMe, + uTagRequirement, + QCBOR_TYPE_URI, + CBOR_TAG_URI, + pUUID); +} + +static inline void +QCBORDecode_GetURIInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pUUID) +{ + QCBORDecode_Private_GetTaggedStringInMapN(pMe, + nLabel, + uTagRequirement, + QCBOR_TYPE_URI, + CBOR_TAG_URI, + pUUID); +} + +static inline void +QCBORDecode_GetURIInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pUUID) +{ + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, + szLabel, + uTagRequirement, + QCBOR_TYPE_URI, + CBOR_TAG_URI, + pUUID); +} + + +static inline void +QCBORDecode_GetB64(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) +{ + QCBORDecode_Private_GetTaggedString(pMe, + uTagRequirement, + QCBOR_TYPE_BASE64, + CBOR_TAG_B64, + pB64Text); +} + +static inline void +QCBORDecode_GetB64InMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) +{ + QCBORDecode_Private_GetTaggedStringInMapN(pMe, + nLabel, + uTagRequirement, + QCBOR_TYPE_BASE64, + CBOR_TAG_B64, + pB64Text); +} + +static inline void +QCBORDecode_GetB64InMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) +{ + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, + szLabel, + uTagRequirement, + QCBOR_TYPE_BASE64, + CBOR_TAG_B64, + pB64Text); +} + + +static inline void +QCBORDecode_GetB64URL(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) +{ + QCBORDecode_Private_GetTaggedString(pMe, + uTagRequirement, + QCBOR_TYPE_BASE64URL, + CBOR_TAG_B64URL, + pB64Text); +} + +static inline void +QCBORDecode_GetB64URLInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) +{ + QCBORDecode_Private_GetTaggedStringInMapN(pMe, + nLabel, + uTagRequirement, + QCBOR_TYPE_BASE64URL, + CBOR_TAG_B64URL, + pB64Text); +} + +static inline void +QCBORDecode_GetB64URLInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pB64Text) +{ + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, + szLabel, + uTagRequirement, + QCBOR_TYPE_BASE64URL, + CBOR_TAG_B64URL, + pB64Text); +} + + +static inline void +QCBORDecode_GetRegex(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pRegex) +{ + QCBORDecode_Private_GetTaggedString(pMe, + uTagRequirement, + QCBOR_TYPE_REGEX, + CBOR_TAG_REGEX, + pRegex); +} + +static inline void +QCBORDecode_GetRegexInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pRegex) +{ + QCBORDecode_Private_GetTaggedStringInMapN(pMe, + nLabel, + uTagRequirement, + QCBOR_TYPE_REGEX, + CBOR_TAG_REGEX, + pRegex); +} + +static inline void +QCBORDecode_GetRegexInMapSZ(QCBORDecodeContext *pMe, + const char * szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pRegex) +{ + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, + szLabel, + uTagRequirement, + QCBOR_TYPE_REGEX, + CBOR_TAG_REGEX, + pRegex); +} + + +static inline void +QCBORDecode_GetBinaryUUID(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pUUID) +{ + QCBORDecode_Private_GetTaggedString(pMe, + uTagRequirement, + QCBOR_TYPE_UUID, + CBOR_TAG_BIN_UUID, + pUUID); +} + +static inline void +QCBORDecode_GetBinaryUUIDInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pUUID) +{ + QCBORDecode_Private_GetTaggedStringInMapN(pMe, + nLabel, + uTagRequirement, + QCBOR_TYPE_UUID, + CBOR_TAG_BIN_UUID, + pUUID); +} + +static inline void +QCBORDecode_GetBinaryUUIDInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pUUID) +{ + QCBORDecode_Private_GetTaggedStringInMapSZ(pMe, + szLabel, + uTagRequirement, + QCBOR_TYPE_UUID, + CBOR_TAG_BIN_UUID, + pUUID); +} + + /* ======================================================================== * * END OF PRIVATE INLINE IMPLEMENTATION * * ======================================================================== */ diff --git a/src/decode_private.h b/src/decode_private.h index 506c668..13c83bb 100644 --- a/src/decode_private.h +++ b/src/decode_private.h @@ -1,47 +1,33 @@ -/*============================================================================== - Copyright (c) 2016-2018, The Linux Foundation. - Copyright (c) 2018-2024, Laurence Lundblade. - Copyright (c) 2021, Arm Limited. - All rights reserved. - - Created on 11/14/24 from qcbor_decode.c - - -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. - =============================================================================*/ +/* ========================================================================== + * qcbor_tag_decode.c -- Tag content decoders + * + * Copyright (c) 2016-2018, The Linux Foundation. + * Copyright (c) 2018-2024, Laurence Lundblade. + * Copyright (c) 2021, Arm Limited. + * All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + * + * Forked from qcbor_decode.c on 11/14/24 + * ========================================================================== */ + #ifndef decode_private_h #define decode_private_h +#include "qcbor/qcbor_decode.h" +#include "qcbor/qcbor_spiffy_decode.h" + +/* These are decode functions used by the spiffy decode and number decode + * implementation. They are internal linkage and nothing to do with + * the public decode interface. + */ QCBORError QCBORDecode_Private_GetNextTagContent(QCBORDecodeContext *pMe, QCBORItem *pDecodedItem); + void QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe, QCBORItem *pItem, @@ -61,19 +47,22 @@ QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe, QCBORTagContentCallBack *pfCB, size_t uOffset); + void QCBORDecode_Private_GetItemInMapNoCheckSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uQcborType, - QCBORItem *pItem, - size_t *puOffset); + const char *szLabel, + const uint8_t uQcborType, + QCBORItem *pItem, + size_t *puOffset); + void QCBORDecode_Private_GetItemInMapNoCheckN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uQcborType, - QCBORItem *pItem, - size_t *puOffset); + const int64_t nLabel, + const uint8_t uQcborType, + QCBORItem *pItem, + size_t *puOffset); + static inline void QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset) @@ -92,4 +81,94 @@ QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t } +uint64_t +QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe, + const uint16_t uMappedTagNumber); + + +QCBORError +DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting, + uint32_t uEndOffset, + uint32_t uStartOffset); + + +typedef struct { + void *pCBContext; + QCBORItemCallback pfCallback; +} MapSearchCallBack; + +typedef struct { + size_t uStartOffset; + uint16_t uItemCount; +} MapSearchInfo; + +QCBORError +QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe, + QCBORItem *pItemArray, + MapSearchInfo *pInfo, + MapSearchCallBack *pCallBack); + + +QCBORError +QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe, + const uint32_t uEndOffset); + + +static inline void +DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting) +{ + /* Only call on a definite-length array / map */ + pNesting->pCurrent->u.ma.uCountCursor++; +} + + +static inline bool +DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting) +{ + if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { + /* Not a map or array */ + return false; + } + +#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS + if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) { + /* Is indefinite */ + return false; + } + +#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ + + /* All checks passed; is a definte length map or array */ + return true; +} + + +static inline bool +DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType) +{ + if(pNesting->pCurrentBounded == NULL) { + return false; + } + + uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType; +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) { + uItemDataType = QCBOR_TYPE_ARRAY; + } +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ + + if(uItemDataType != uType) { + return false; + } + + return true; +} + + +static inline uint32_t +DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe) +{ + return pMe->pCurrentBounded->u.bs.uSavedEndOffset; +} + #endif /* decode_private_h */ diff --git a/src/qcbor_decode.c b/src/qcbor_decode.c index 7e2abad..9f79652 100644 --- a/src/qcbor_decode.c +++ b/src/qcbor_decode.c @@ -36,6 +36,7 @@ IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include "qcbor/qcbor_spiffy_decode.h" #include "qcbor/qcbor_tag_decode.h" #include "ieee754.h" /* Does not use math.h */ +#include "decode_private.h" #if (defined(__GNUC__) && !defined(__clang__)) @@ -237,25 +238,7 @@ DecodeNesting_IsCurrentAtTop(const QCBORDecodeNesting *pNesting) } -static bool -DecodeNesting_IsCurrentDefiniteLength(const QCBORDecodeNesting *pNesting) -{ - if(pNesting->pCurrent->uLevelType == QCBOR_TYPE_BYTE_STRING) { - /* Not a map or array */ - return false; - } - -#ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS - if(pNesting->pCurrent->u.ma.uCountTotal == QCBOR_COUNT_INDICATES_INDEFINITE_LENGTH) { - /* Is indefinite */ - return false; - } - -#endif /* QCBOR_DISABLE_INDEFINITE_LENGTH_ARRAYS */ - /* All checks passed; is a definte length map or array */ - return true; -} static bool DecodeNesting_IsCurrentBstrWrapped(const QCBORDecodeNesting *pNesting) @@ -354,26 +337,6 @@ DecodeNesting_IsCurrentTypeMap(const QCBORDecodeNesting *pNesting) } -static bool -DecodeNesting_IsBoundedType(const QCBORDecodeNesting *pNesting, uint8_t uType) -{ - if(pNesting->pCurrentBounded == NULL) { - return false; - } - - uint8_t uItemDataType = pNesting->pCurrentBounded->uLevelType; -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - if(uItemDataType == QCBOR_TYPE_MAP_AS_ARRAY) { - uItemDataType = QCBOR_TYPE_ARRAY; - } -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ - - if(uItemDataType != uType) { - return false; - } - - return true; -} static void @@ -384,13 +347,6 @@ DecodeNesting_DecrementDefiniteLengthMapOrArrayCount(QCBORDecodeNesting *pNestin } -static void -DecodeNesting_ReverseDecrement(QCBORDecodeNesting *pNesting) -{ - /* Only call on a definite-length array / map */ - pNesting->pCurrent->u.ma.uCountCursor++; -} - static void DecodeNesting_Ascend(QCBORDecodeNesting *pNesting) @@ -503,7 +459,7 @@ DecodeNesting_SetCurrentToBoundedLevel(QCBORDecodeNesting *pNesting) } -static QCBORError +QCBORError DecodeNesting_DescendIntoBstrWrapped(QCBORDecodeNesting *pNesting, uint32_t uEndOffset, uint32_t uStartOffset) @@ -568,12 +524,6 @@ DecodeNesting_RestoreFromMapSearch(QCBORDecodeNesting *pNesting, } -static uint32_t -DecodeNesting_GetPreviousBoundedEnd(const QCBORDecodeNesting *pMe) -{ - return pMe->pCurrentBounded->u.bs.uSavedEndOffset; -} - @@ -1791,7 +1741,7 @@ QCBORDecode_Private_MapTagNumber(QCBORDecodeContext *pMe, * * This is the reverse of MapTagNumber() */ -static uint64_t +uint64_t QCBORDecode_Private_UnMapTagNumber(const QCBORDecodeContext *pMe, const uint16_t uMappedTagNumber) { @@ -2809,152 +2759,7 @@ QCBORDecode_Finish(QCBORDecodeContext *pMe) } -#ifndef QCBOR_DISABLE_TAGS -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -uint64_t -QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe, - const QCBORItem *pItem, - uint8_t uIndex) -{ - if(pItem->uDataType == QCBOR_TYPE_NONE) { - return CBOR_TAG_INVALID64; - } - if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { - return CBOR_TAG_INVALID64; - } - - return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -uint64_t -QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe, - uint8_t uIndex) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - return CBOR_TAG_INVALID64; - } - if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { - return CBOR_TAG_INVALID64; - } - - return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -static uint64_t -QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe, - const uint16_t puTagNumbers[], - const uint32_t uIndex) -{ - uint32_t uArrayIndex; - - /* Find number of tag numbers */ - for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) { - if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) { - break; - } - } - if(uIndex > uArrayIndex) { - return CBOR_TAG_INVALID64; - } - - return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -uint64_t -QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - const uint32_t uIndex) -{ - if(pItem->uDataType == QCBOR_TYPE_NONE) { - return CBOR_TAG_INVALID64; - } - - return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pItem->auTagNumbers, uIndex); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -uint64_t -QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, - uint32_t uIndex) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - return CBOR_TAG_INVALID64; - } - if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { - return CBOR_TAG_INVALID64; - } - - return QCBORDecode_Private_GetNthTagNumberReverse(pMe, pMe->auLastTags, uIndex); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber) -{ - QCBORItem Item; - size_t uOffset; - QCBORError uErr; - - const QCBORDecodeNesting SaveNesting = pMe->nesting; - const UsefulInputBuf Save = pMe->InBuf; - - uOffset = UsefulInputBuf_Tell(&(pMe->InBuf)); - if(uOffset == pMe->uTagNumberCheckOffset) { - pMe->uTagNumberIndex++; - } else { - pMe->uTagNumberIndex = 0; - } - - *puTagNumber = CBOR_TAG_INVALID64; - uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item); - if(uErr) { - return uErr; - } - - *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex); - if(*puTagNumber == CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) { - pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED; - } - pMe->uTagNumberCheckOffset = uOffset; - - pMe->nesting = SaveNesting; - pMe->InBuf = Save; - - return QCBOR_SUCCESS; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber) -{ - pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber); -} -#endif /* ! QCBOR_DISABLE_TAGS */ #ifndef QCBOR_DISABLE_INDEFINITE_LENGTH_STRINGS @@ -3245,18 +3050,6 @@ QCBORDecode_Rewind(QCBORDecodeContext *pMe) - -typedef struct { - void *pCBContext; - QCBORItemCallback pfCallback; -} MapSearchCallBack; - -typedef struct { - size_t uStartOffset; - uint16_t uItemCount; -} MapSearchInfo; - - /** * @brief Search a map for a set of items. * @@ -3288,7 +3081,7 @@ typedef struct { * * This also finds the ends of maps and arrays when they are exited. */ -static QCBORError +QCBORError QCBORDecode_Private_MapSearch(QCBORDecodeContext *pMe, QCBORItem *pItemArray, MapSearchInfo *pInfo, @@ -3843,99 +3636,6 @@ QCBORDecode_Private_SearchAndGetArrayOrMap(QCBORDecodeContext *pMe, - -static void -QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe, - QCBORItem *pItem, - const uint8_t uTagRequirement, - const uint8_t uQCBORType, - const uint64_t uTagNumber, - QCBORTagContentCallBack *pfCB, - size_t uOffset); - -/** - * @brief Semi-private to get an string by label to match a tag specification. - * - * @param[in] pMe The decode context. - * @param[in] nLabel Label to search map for. - * @param[in] uTagRequirement Whether or not tag number is required. - * See @ref QCBOR_TAG_REQUIREMENT_TAG. - * @param[in] uQCBOR_Type QCBOR type to search for. - * @param[in] uTagNumber Tag number to match. - * @param[out] pString The string found. - * - * This finds the string with the given label in currently open - * map. Then checks that its tag number and types matches the tag - * specification. If not, an error is set in the decode context. - */ -void -QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - const uint8_t uQCBOR_Type, - const uint64_t uTagNumber, - UsefulBufC *pString) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset); - QCBORDecode_Private_ProcessTagOne(pMe, - &Item, - uTagRequirement, - uQCBOR_Type, - uTagNumber, - QCBORDecode_StringsTagCB, - uOffset); - - if(pMe->uLastError == QCBOR_SUCCESS) { - *pString = Item.val.string; - } -} - - -/** - * @brief Semi-private to get an string by label to match a tag specification. - * - * @param[in] pMe The decode context. - * @param[in] szLabel Label to search map for. - * @param[in] uTagRequirement Whether or not tag number is required. - * See @ref QCBOR_TAG_REQUIREMENT_TAG. - * @param[in] uQCBOR_Type QCBOR type to search for. - * @param[in] uTagNumber Tag number to match. - * @param[out] pString The string found. - * - * This finds the string with the given label in currently open - * map. Then checks that its tag number and types matches the tag - * specification. If not, an error is set in the decode context. - */ -void -QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - uint8_t uQCBOR_Type, - uint64_t uTagNumber, - UsefulBufC *pString) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset); - QCBORDecode_Private_ProcessTagOne(pMe, - &Item, - uTagRequirement, - uQCBOR_Type, - uTagNumber, - QCBORDecode_StringsTagCB, - uOffset); - - - if(pMe->uLastError == QCBOR_SUCCESS) { - *pString = Item.val.string; - } -} - - /* * Public function, see header qcbor/qcbor_decode.h file */ @@ -3963,96 +3663,6 @@ QCBORDecode_GetItemsInMapWithCallback(QCBORDecodeContext *pMe, } -#ifndef QCBOR_DISABLE_TAGS -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber) -{ - size_t uOffset; - MapSearchInfo Info; - QCBORItem OneItemSeach[2]; - - if(pMe->uLastError != QCBOR_SUCCESS) { - return pMe->uLastError; - } - - OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; - OneItemSeach[0].label.int64 = nLabel; - OneItemSeach[0].uDataType = QCBOR_TYPE_ANY; - OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array - - QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL); - - uOffset = Info.uStartOffset; - if(uOffset == pMe->uTagNumberCheckOffset) { - pMe->uTagNumberIndex++; - } else { - pMe->uTagNumberIndex = 0; - } - - *puTagNumber = CBOR_TAG_INVALID64; - - *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex); - if(*puTagNumber == CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) { - pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED; - } - pMe->uTagNumberCheckOffset = uOffset; - - return uReturn; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -QCBORError -QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber) -{ -#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS - size_t uOffset; - MapSearchInfo Info; - QCBORItem OneItemSeach[2]; - - if(pMe->uLastError != QCBOR_SUCCESS) { - return pMe->uLastError; - } - - OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; - OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); - OneItemSeach[0].uDataType = QCBOR_TYPE_ANY; - OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array - - QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL); - - - uOffset = Info.uStartOffset; - if(uOffset == pMe->uTagNumberCheckOffset) { - pMe->uTagNumberIndex++; - } else { - pMe->uTagNumberIndex = 0; - } - - *puTagNumber = CBOR_TAG_INVALID64; - - *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex); - if(*puTagNumber == CBOR_TAG_INVALID64 || - QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) { - pMe->uTagNumberIndex = 255; /* All tags clear for this item */ - } - pMe->uTagNumberCheckOffset = uOffset; - - return uReturn; -#else - (void)pMe; - (void)szLabel; - (void)puTagNumber; - return QCBOR_ERR_LABEL_NOT_FOUND; -#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ -} -#endif /* ! QCBOR_DISABLE_TAGS */ /** @@ -4288,7 +3898,7 @@ QCBORDecode_Private_EnterBoundedMapOrArray(QCBORDecodeContext *pMe, * The other work is to level-up the bounded mode to next higest * bounded mode or the top level if there isn't one. */ -static QCBORError +QCBORError QCBORDecode_Private_ExitBoundedLevel(QCBORDecodeContext *pMe, const uint32_t uEndOffset) { @@ -4381,240 +3991,18 @@ QCBORDecode_Private_ExitBoundedMapOrArray(QCBORDecodeContext *pMe, } -// TODO: re order this file with tags stuff last. bstr is a tag thing -static QCBORError -QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - const size_t uOffset, - const uint8_t *uQCBORTypes, - const uint64_t *uTagNumbers, - const uint8_t uTagRequirement, - bool *bTypeMatched); + + /** - * @brief The main work of entering some byte-string wrapped CBOR. - * - * @param[in] pMe The decode context. - * @param[in] pItem The byte string item. - * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX - * @param[out] pBstr Pointer and length of byte string entered. + * @brief Process simple type true and false, a boolean * - * This is called once the byte string item has been decoded to do all - * the book keeping work for descending a nesting level into the - * nested CBOR. + * @param[in] pMe The decode context. + * @param[in] pItem The item with either true or false. + * @param[out] pBool The boolean value output. * - * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement. - */ -static QCBORError -QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - const uint8_t uTagRequirement, - const size_t uOffset, - UsefulBufC *pBstr) -{ - bool bTypeMatched; - QCBORError uError; - - const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR, QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, QCBOR_TYPE_NONE}; - const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR, CBOR_TAG_CBOR_SEQUENCE, CBOR_TAG_INVALID64}; - - - if(pBstr) { - *pBstr = NULLUsefulBufC; - } - - if(pMe->uLastError != QCBOR_SUCCESS) { - return pMe->uLastError; - } - - if(pItem->uDataAlloc) { - return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING; - } - - uError = QCBORDecode_Private_CheckTagNType(pMe, - pItem, - uOffset, - uTypes, // TODO: maybe this should be empty - uTagNumbers, - uTagRequirement, - &bTypeMatched); - - if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) { - uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error - } - - - if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) { - /* Reverse the decrement done by GetNext() for the bstr so the - * increment in QCBORDecode_NestLevelAscender() called by - * ExitBoundedLevel() will work right. - */ - DecodeNesting_ReverseDecrement(&(pMe->nesting)); - } - - if(pBstr) { - *pBstr = pItem->val.string; - } - - /* This saves the current length of the UsefulInputBuf and then - * narrows the UsefulInputBuf to start and length of the wrapped - * CBOR that is being entered. - * - * Most of these calls are simple inline accessors so this doesn't - * amount to much code. - */ - - const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf)); - /* This check makes the cast of uPreviousLength to uint32_t below safe. */ - if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) { - uError = QCBOR_ERR_INPUT_TOO_LARGE; - goto Done; - } - - const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf), - pItem->val.string.ptr); - /* This check makes the cast of uStartOfBstr to uint32_t below safe. */ - if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) { - /* This should never happen because pItem->val.string.ptr should - * always be valid since it was just returned. - */ - uError = QCBOR_ERR_INPUT_TOO_LARGE; - goto Done; - } - - const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len; - - UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr); - UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr); - - uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting), - (uint32_t)uPreviousLength, - (uint32_t)uStartOfBstr); -Done: - return uError; -} - - -static void -QCBORDecode_Private_GetAndTell(QCBORDecodeContext *pMe, QCBORItem *Item, size_t *uOffset) -{ -#ifndef QCBOR_DISABLE_TAGS - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - *uOffset = QCBORDecode_Tell(pMe); -#else - *uOffset = SIZE_MAX; - -#endif /* ! QCBOR_DISABLE_TAGS */ - pMe->uLastError = (uint8_t)QCBORDecode_Private_GetNextTagContent(pMe, Item); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pBstr) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); - pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, - &Item, - uTagRequirement, - uOffset, - pBstr); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pBstr) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset); - pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, - &Item, - uTagRequirement, - uOffset, - pBstr); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pBstr) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_BYTE_STRING, &Item, &uOffset); - pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, - &Item, - uTagRequirement, - uOffset, - pBstr); -} - - -/* - * Public function, see header qcbor/qcbor_decode.h file - */ -void -QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe) -{ - if(pMe->uLastError != QCBOR_SUCCESS) { - // Already in error state; do nothing. - return; - } - - if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) { - pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH; - return; - } - - const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf)); - - /* - Reset the length of the UsefulInputBuf to what it was before - the bstr wrapped CBOR was entered. - */ - UsefulInputBuf_SetBufferLength(&(pMe->InBuf), - DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting))); - - - QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr); - pMe->uLastError = (uint8_t)uErr; -} - - - -/** - * @brief Process simple type true and false, a boolean - * - * @param[in] pMe The decode context. - * @param[in] pItem The item with either true or false. - * @param[out] pBool The boolean value output. - * - * Sets the internal error if the item isn't a true or a false. Also - * records any tag numbers as the tag numbers of the last item. + * Sets the internal error if the item isn't a true or a false. Also + * records any tag numbers as the tag numbers of the last item. */ static void QCBORDecode_Private_ProcessBool(QCBORDecodeContext *pMe, @@ -4772,481 +4160,6 @@ QCBORDecode_GetSimpleInMapSZ(QCBORDecodeContext *pMe, -#ifndef QCBOR_DISABLE_TAGS -// TODO: uTagNumber might be better a list than calling this multiple times -static QCBORError -QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe, - const QCBORItem *pItem, - const uint64_t uTagNumber, - const size_t uOffset) -{ - if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) { - /* There are no tag numbers at all, so no unprocessed */ - return QCBOR_SUCCESS; - } - - /* There are some tag numbers, so keep checking. This check passes - * if there is one and only one tag number that matches uTagNumber - */ - - // TODO: behave different in v1 and v2? - - const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0); - - if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16 ) { - /* The only tag number is the one we are processing so no unprocessed */ - return QCBOR_SUCCESS; - } - - if(uOffset != pMe->uTagNumberCheckOffset) { - /* processed tag numbers are for some other item, not us */ - return QCBOR_ERR_UNPROCESSED_TAG_NUMBER; - } - - if(pMe->uTagNumberIndex != 1) { - return QCBOR_ERR_UNPROCESSED_TAG_NUMBER; - } - - return QCBOR_SUCCESS; -} -#endif - - -static QCBORError -QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe, - const QCBORItem *pItem, - const size_t uOffset, - const uint8_t *uQCBORTypes, - const uint64_t *uTagNumbers, - const uint8_t uTagRequirement, - bool *bTypeMatched) -{ - const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS; - - *bTypeMatched = false; - for(const uint8_t *pTNum = uQCBORTypes; *pTNum != QCBOR_TYPE_NONE; pTNum++) { - if(pItem->uDataType == *pTNum) { - *bTypeMatched = true; - break; - } - } - -#ifndef QCBOR_DISABLE_TAGS - bool bTagNumberMatched; - QCBORError uErr; - const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0); - - bTagNumberMatched = false; - for(const uint64_t *pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) { - if(uInnerTag == *pQType) { - bTagNumberMatched = true; - break; - } - } - - - if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) { - /* There must be a tag number */ - if(!bTagNumberMatched && !*bTypeMatched) { - return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code - } - - } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) { - if(bTagNumberMatched || *bTypeMatched) { - return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code - } - - } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) { - /* No check necessary */ - } - - /* Now check if there are extra tags and if there's an error in them */ - if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) { - /* The flag to ignore extra is not set, so keep checking */ - for(const uint64_t *pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) { - uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset); - if(uErr != QCBOR_SUCCESS) { - return uErr; - } - } - } - - return QCBOR_SUCCESS; -#else - (void)pMe; - (void)uOffset; - (void)uTagNumbers; - - if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) { - return QCBOR_SUCCESS; - } else { - return QCBOR_ERR_UNEXPECTED_TYPE; - } - -#endif - -} - - -void -QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe, - QCBORItem *pItem, - const uint8_t uTagRequirement, - const uint8_t uQCBORTypes[], - const uint64_t uTagNumbers[], - QCBORTagContentCallBack *pfCB, - size_t uOffset) -{ - QCBORError uErr; - bool bTypeMatched; - - if(pMe->uLastError != QCBOR_SUCCESS) { - return; - } - - uErr = QCBORDecode_Private_CheckTagNType(pMe, - pItem, - uOffset, - uQCBORTypes, - uTagNumbers, - uTagRequirement, - &bTypeMatched); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - - if(!bTypeMatched) { - /* Tag content wasn't previously processed, do it now */ - uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem); - if(uErr != QCBOR_SUCCESS) { - goto Done; - } - } - -Done: - pMe->uLastError = (uint8_t)uErr; -} - - -/* - **/ -void -QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe, - QCBORItem *pItem, - const uint8_t uTagRequirement, - const uint8_t uQCBORTypes[], - const uint64_t uTagNumber, - QCBORTagContentCallBack *pfCB, - size_t uOffset) -{ - uint64_t auTagNumbers[2]; - - auTagNumbers[0] = uTagNumber; - auTagNumbers[1] = CBOR_TAG_INVALID64; - - QCBORDecode_Private_ProcessTagItemMulti(pMe, - pItem, - uTagRequirement, - uQCBORTypes, - auTagNumbers, - pfCB, - uOffset); -} - - -static void -QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe, - QCBORItem *pItem, - const uint8_t uTagRequirement, - const uint8_t uQCBORType, - const uint64_t uTagNumber, - QCBORTagContentCallBack *pfCB, - const size_t uOffset) -{ - uint8_t auQCBORType[2]; - - auQCBORType[0] = uQCBORType; - auQCBORType[1] = QCBOR_TYPE_NONE; - - QCBORDecode_Private_ProcessTagItem(pMe, - pItem, - uTagRequirement, - auQCBORType, - uTagNumber, - pfCB, - uOffset); -} - - - - -/* - * Public function, see header qcbor/qcbor_spiffy_decode.h file - */ -void -QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnTime) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); - QCBORDecode_Private_ProcessTagOne(pMe, - &Item, - uTagRequirement, - QCBOR_TYPE_DATE_EPOCH, - CBOR_TAG_DATE_EPOCH, - QCBORDecode_DateEpochTagCB, - uOffset); - *pnTime = Item.val.epochDate.nSeconds; -} - - -/* - * Public function, see header qcbor/qcbor_spiffy_decode.h file - */ -void -QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnTime) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset); - QCBORDecode_Private_ProcessTagOne(pMe, - &Item, - uTagRequirement, - QCBOR_TYPE_DATE_EPOCH, - CBOR_TAG_DATE_EPOCH, - QCBORDecode_DateEpochTagCB, - uOffset); - *pnTime = Item.val.epochDate.nSeconds; -} - - -/* - * Public function, see header qcbor/qcbor_spiffy_decode.h file - */ -void -QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnTime) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset); - QCBORDecode_Private_ProcessTagOne(pMe, - &Item, - uTagRequirement, - QCBOR_TYPE_DATE_EPOCH, - CBOR_TAG_DATE_EPOCH, - QCBORDecode_DateEpochTagCB, - uOffset); - *pnTime = Item.val.epochDate.nSeconds; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h - */ -void -QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe, - uint8_t uTagRequirement, - int64_t *pnDays) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); - QCBORDecode_Private_ProcessTagOne(pMe, - &Item, - uTagRequirement, - QCBOR_TYPE_DAYS_EPOCH, - CBOR_TAG_DAYS_EPOCH, - QCBORDecode_DaysEpochTagCB, - uOffset); - *pnDays = Item.val.epochDays; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h - */ -void -QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe, - int64_t nLabel, - uint8_t uTagRequirement, - int64_t *pnDays) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset); - QCBORDecode_Private_ProcessTagOne(pMe, - &Item, - uTagRequirement, - QCBOR_TYPE_DAYS_EPOCH, - CBOR_TAG_DAYS_EPOCH, - QCBORDecode_DaysEpochTagCB, - uOffset); - *pnDays = Item.val.epochDays; -} - - -/* - * Public function, see header qcbor/qcbor_decode.h - */ -void -QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - uint8_t uTagRequirement, - int64_t *pnDays) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset); - QCBORDecode_Private_ProcessTagOne(pMe, - &Item, - uTagRequirement, - QCBOR_TYPE_DAYS_EPOCH, - CBOR_TAG_DAYS_EPOCH, - QCBORDecode_DaysEpochTagCB, - uOffset); - *pnDays = Item.val.epochDays; -} - - - - -void -QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - const uint8_t uQCBOR_Type, - const uint64_t uTagNumber, - UsefulBufC *pStr) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); - QCBORDecode_Private_ProcessTagOne(pMe, - &Item, - uTagRequirement, - uQCBOR_Type, - uTagNumber, - QCBORDecode_StringsTagCB, - uOffset); - - if(pMe->uLastError == QCBOR_SUCCESS) { - *pStr = Item.val.string; - } else { - *pStr = NULLUsefulBufC; - } -} - - - -static void -QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - QCBORItem *pItem, - UsefulBufC *pValue, - bool *pbIsTag257, - size_t uOffset) -{ - QCBORError uErr; - - const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE}; - - const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64}; - - QCBORDecode_Private_ProcessTagItemMulti(pMe, - pItem, - uTagRequirement, - puTypes, - puTNs, - QCBORDecode_MIMETagCB, - uOffset); - if(pMe->uLastError) { - return; - } - - if(pItem->uDataType == QCBOR_TYPE_MIME) { - *pbIsTag257 = false; - } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) { - *pbIsTag257 = true; - } - *pValue = pItem->val.string; - - - uErr = QCBOR_SUCCESS; - - pMe->uLastError = (uint8_t)uErr; -} - - -void -QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe, - const uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); - QCBORDecode_Private_GetMIME(pMe, - uTagRequirement, - &Item, - pMessage, - pbIsTag257, - uOffset); -} - -void -QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe, - const int64_t nLabel, - const uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckN(pMe, nLabel, QCBOR_TYPE_ANY, &Item, &uOffset); - QCBORDecode_Private_GetMIME(pMe, - uTagRequirement, - &Item, - pMessage, - pbIsTag257, - uOffset); -} - -void -QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe, - const char *szLabel, - const uint8_t uTagRequirement, - UsefulBufC *pMessage, - bool *pbIsTag257) -{ - QCBORItem Item; - size_t uOffset; - - QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, szLabel, QCBOR_TYPE_ANY, &Item, &uOffset); - QCBORDecode_Private_GetMIME(pMe, - uTagRequirement, - &Item, - pMessage, - pbIsTag257, - uOffset); -} - // Improvement: add methods for wrapped CBOR, a simple alternate diff --git a/src/qcbor_tag_decode.c b/src/qcbor_tag_decode.c index 31f9c03..bf265f8 100644 --- a/src/qcbor_tag_decode.c +++ b/src/qcbor_tag_decode.c @@ -10,13 +10,1028 @@ * Created on 9/5/24 from qcbode_decode.c * ========================================================================== */ -// TODO: qcbor_tag_decode.c or tag_decode.c - #include "qcbor/qcbor_tag_decode.h" +#include "decode_private.h" #include /* For isnan() */ + +#ifndef QCBOR_DISABLE_TAGS + +/* Public function; see qcbor_tag_decode.h */ +QCBORError +QCBORDecode_GetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber) +{ + QCBORItem Item; + size_t uOffset; + QCBORError uErr; + + const QCBORDecodeNesting SaveNesting = pMe->nesting; + const UsefulInputBuf Save = pMe->InBuf; + + uOffset = UsefulInputBuf_Tell(&(pMe->InBuf)); + if(uOffset == pMe->uTagNumberCheckOffset) { + pMe->uTagNumberIndex++; + } else { + pMe->uTagNumberIndex = 0; + } + + *puTagNumber = CBOR_TAG_INVALID64; + uErr = QCBORDecode_Private_GetNextTagContent(pMe, &Item); + if(uErr) { + return uErr; + } + + *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex); + if(*puTagNumber == CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTagNumber(pMe, &Item, pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) { + pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED; + } + pMe->uTagNumberCheckOffset = uOffset; + + pMe->nesting = SaveNesting; + pMe->InBuf = Save; + + return QCBOR_SUCCESS; +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_VGetNextTagNumber(QCBORDecodeContext *pMe, uint64_t *puTagNumber) +{ + pMe->uLastError = (uint8_t)QCBORDecode_GetNextTagNumber(pMe, puTagNumber); +} + +/* + * Public function, see header qcbor/qcbor_tag_decode.h file + */ +QCBORError +QCBORDecode_GetNextTagNumberInMapN(QCBORDecodeContext *pMe, const int64_t nLabel, uint64_t *puTagNumber) +{ + size_t uOffset; + MapSearchInfo Info; + QCBORItem OneItemSeach[2]; + QCBORError uReturn; + + if(pMe->uLastError != QCBOR_SUCCESS) { + return pMe->uLastError; + } + + OneItemSeach[0].uLabelType = QCBOR_TYPE_INT64; + OneItemSeach[0].label.int64 = nLabel; + OneItemSeach[0].uDataType = QCBOR_TYPE_ANY; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array + + uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL); + + uOffset = Info.uStartOffset; + if(uOffset == pMe->uTagNumberCheckOffset) { + pMe->uTagNumberIndex++; + } else { + pMe->uTagNumberIndex = 0; + } + + *puTagNumber = CBOR_TAG_INVALID64; + + *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, + &OneItemSeach[0], + pMe->uTagNumberIndex); + if(*puTagNumber == CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) { + pMe->uTagNumberIndex = QCBOR_ALL_TAGS_PROCESSED; + } + pMe->uTagNumberCheckOffset = uOffset; + + return uReturn; +} + + +/* Public function; see qcbor_tag_decode.h */ +QCBORError +QCBORDecode_GetNextTagNumberInMapSZ(QCBORDecodeContext *pMe, const char *szLabel, uint64_t *puTagNumber) +{ +#ifndef QCBOR_DISABLE_NON_INTEGER_LABELS + size_t uOffset; + MapSearchInfo Info; + QCBORItem OneItemSeach[2]; + + if(pMe->uLastError != QCBOR_SUCCESS) { + return pMe->uLastError; + } + + OneItemSeach[0].uLabelType = QCBOR_TYPE_TEXT_STRING; + OneItemSeach[0].label.string = UsefulBuf_FromSZ(szLabel); + OneItemSeach[0].uDataType = QCBOR_TYPE_ANY; + OneItemSeach[1].uLabelType = QCBOR_TYPE_NONE; // Indicates end of array + + QCBORError uReturn = QCBORDecode_Private_MapSearch(pMe, OneItemSeach, &Info, NULL); + + + uOffset = Info.uStartOffset; + if(uOffset == pMe->uTagNumberCheckOffset) { + pMe->uTagNumberIndex++; + } else { + pMe->uTagNumberIndex = 0; + } + + *puTagNumber = CBOR_TAG_INVALID64; + + *puTagNumber = QCBORDecode_GetNthTagNumber(pMe, + &OneItemSeach[0], + pMe->uTagNumberIndex); + if(*puTagNumber == CBOR_TAG_INVALID64 || + QCBORDecode_GetNthTagNumber(pMe, &OneItemSeach[0], pMe->uTagNumberIndex+1) == CBOR_TAG_INVALID64 ) { + pMe->uTagNumberIndex = 255; /* All tags clear for this item */ + } + pMe->uTagNumberCheckOffset = uOffset; + + return uReturn; +#else + (void)pMe; + (void)szLabel; + (void)puTagNumber; + return QCBOR_ERR_LABEL_NOT_FOUND; +#endif /* ! QCBOR_DISABLE_NON_INTEGER_LABELS */ +} + + +/* Public function; see qcbor_tag_decode.h */ +uint64_t +QCBORDecode_GetNthTagNumber(const QCBORDecodeContext *pMe, + const QCBORItem *pItem, + uint8_t uIndex) +{ + if(pItem->uDataType == QCBOR_TYPE_NONE) { + return CBOR_TAG_INVALID64; + } + if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { + return CBOR_TAG_INVALID64; + } + + return QCBORDecode_Private_UnMapTagNumber(pMe, pItem->auTagNumbers[uIndex]); +} + + +/* Public function; see qcbor_tag_decode.h */ +uint64_t +QCBORDecode_GetNthTagNumberOfLast(QCBORDecodeContext *pMe, uint8_t uIndex) +{ + if(pMe->uLastError != QCBOR_SUCCESS) { + return CBOR_TAG_INVALID64; + } + if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { + return CBOR_TAG_INVALID64; + } + + return QCBORDecode_Private_UnMapTagNumber(pMe, pMe->auLastTags[uIndex]); +} + + +static uint64_t +QCBORDecode_Private_GetNthTagNumberReverse(const QCBORDecodeContext *pMe, + const uint16_t puTagNumbers[], + const uint32_t uIndex) +{ + uint32_t uArrayIndex; + + /* Find number of tag numbers */ + for(uArrayIndex = QCBOR_MAX_TAGS_PER_ITEM-1; uArrayIndex > 0; uArrayIndex--) { + if(puTagNumbers[uArrayIndex] != CBOR_TAG_INVALID16) { + break; + } + } + if(uIndex > uArrayIndex) { + return CBOR_TAG_INVALID64; + } + + return QCBORDecode_Private_UnMapTagNumber(pMe, puTagNumbers[uArrayIndex - uIndex]); +} + + +/* Public function; see qcbor_tag_decode.h */ +uint64_t +QCBORDecode_GetNthTag(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + const uint32_t uIndex) +{ + if(pItem->uDataType == QCBOR_TYPE_NONE) { + return CBOR_TAG_INVALID64; + } + + return QCBORDecode_Private_GetNthTagNumberReverse(pMe, + pItem->auTagNumbers, + uIndex); +} + + +/* Public function; see qcbor_tag_decode.h */ +uint64_t +QCBORDecode_GetNthTagOfLast(const QCBORDecodeContext *pMe, uint32_t uIndex) +{ + if(pMe->uLastError != QCBOR_SUCCESS) { + return CBOR_TAG_INVALID64; + } + if(uIndex >= QCBOR_MAX_TAGS_PER_ITEM) { + return CBOR_TAG_INVALID64; + } + + return QCBORDecode_Private_GetNthTagNumberReverse(pMe, + pMe->auLastTags, + uIndex); +} + + + +// TODO: uTagNumber might be better a list than calling this multiple times +static QCBORError +QCBORDecode_Private_Check1TagNumber(const QCBORDecodeContext *pMe, + const QCBORItem *pItem, + const uint64_t uTagNumber, + const size_t uOffset) +{ + if(pItem->auTagNumbers[0] == CBOR_TAG_INVALID16) { + /* There are no tag numbers at all, so no unprocessed */ + return QCBOR_SUCCESS; + } + + /* There are some tag numbers, so keep checking. This check passes + * if there is one and only one tag number that matches uTagNumber + */ + + // TODO: behave different in v1 and v2? + + const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0); + + if(uInnerTag == uTagNumber && pItem->auTagNumbers[1] == CBOR_TAG_INVALID16) { + /* The only tag number is the one we are processing so no unprocessed */ + return QCBOR_SUCCESS; + } + + if(uOffset != pMe->uTagNumberCheckOffset) { + /* processed tag numbers are for some other item, not us */ + return QCBOR_ERR_UNPROCESSED_TAG_NUMBER; + } + + if(pMe->uTagNumberIndex != 1) { + return QCBOR_ERR_UNPROCESSED_TAG_NUMBER; + } + + return QCBOR_SUCCESS; +} +#endif + + +static QCBORError +QCBORDecode_Private_CheckTagNType(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + const size_t uOffset, + const uint8_t *uQCBORTypes, + const uint64_t *uTagNumbers, + const uint8_t uTagRequirement, + bool *bTypeMatched) +{ + const uint64_t *pQType; + const uint64_t *pTNum; + const uint8_t *pTypeNum; + + const int nTagReq = uTagRequirement & ~QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS; + + *bTypeMatched = false; + for(pTypeNum = uQCBORTypes; *pTypeNum != QCBOR_TYPE_NONE; pTypeNum++) { + if(pItem->uDataType == *pTypeNum) { + *bTypeMatched = true; + break; + } + } + +#ifndef QCBOR_DISABLE_TAGS + bool bTagNumberMatched; + QCBORError uErr; + const uint64_t uInnerTag = QCBORDecode_GetNthTagNumber(pMe, pItem, 0); + + bTagNumberMatched = false; + for(pQType = uTagNumbers; *pQType != CBOR_TAG_INVALID64; pQType++) { + if(uInnerTag == *pQType) { + bTagNumberMatched = true; + break; + } + } + + + if(nTagReq == QCBOR_TAG_REQUIREMENT_TAG) { + /* There must be a tag number */ + if(!bTagNumberMatched && !*bTypeMatched) { + return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code + } + + } else if(nTagReq == QCBOR_TAG_REQUIREMENT_NOT_A_TAG) { + if(bTagNumberMatched || *bTypeMatched) { + return QCBOR_ERR_UNEXPECTED_TYPE; // TODO: error code + } + + } else if(nTagReq == QCBOR_TAG_REQUIREMENT_OPTIONAL_TAG) { + /* No check necessary */ + } + + /* Now check if there are extra tags and if there's an error in them */ + if(!(uTagRequirement & QCBOR_TAG_REQUIREMENT_ALLOW_ADDITIONAL_TAGS)) { + /* The flag to ignore extra is not set, so keep checking */ + for(pTNum = uTagNumbers; *pTNum != CBOR_TAG_INVALID64; pTNum++) { + uErr = QCBORDecode_Private_Check1TagNumber(pMe, pItem, *pTNum, uOffset); + if(uErr != QCBOR_SUCCESS) { + return uErr; + } + } + } + + return QCBOR_SUCCESS; +#else /* ! QCBOR_DISABLE_TAGS */ + (void)pMe; + (void)uOffset; + (void)uTagNumbers; + + if(nTagReq != QCBOR_TAG_REQUIREMENT_TAG && bTypeMatched) { + return QCBOR_SUCCESS; + } else { + return QCBOR_ERR_UNEXPECTED_TYPE; + } + +#endif /* ! QCBOR_DISABLE_TAGS */ + +} + + +void +QCBORDecode_Private_ProcessTagItemMulti(QCBORDecodeContext *pMe, + QCBORItem *pItem, + const uint8_t uTagRequirement, + const uint8_t uQCBORTypes[], + const uint64_t uTagNumbers[], + QCBORTagContentCallBack *pfCB, + size_t uOffset) +{ + QCBORError uErr; + bool bTypeMatched; + + if(pMe->uLastError != QCBOR_SUCCESS) { + return; + } + + uErr = QCBORDecode_Private_CheckTagNType(pMe, + pItem, + uOffset, + uQCBORTypes, + uTagNumbers, + uTagRequirement, + &bTypeMatched); + if(uErr != QCBOR_SUCCESS) { + goto Done; + } + + if(!bTypeMatched) { + /* Tag content wasn't previously processed, do it now */ + uErr = (*pfCB)(pMe, NULL, uTagNumbers[0], pItem); + if(uErr != QCBOR_SUCCESS) { + goto Done; + } + } + +Done: + pMe->uLastError = (uint8_t)uErr; +} + + +/* + **/ +void +QCBORDecode_Private_ProcessTagItem(QCBORDecodeContext *pMe, + QCBORItem *pItem, + const uint8_t uTagRequirement, + const uint8_t uQCBORTypes[], + const uint64_t uTagNumber, + QCBORTagContentCallBack *pfCB, + size_t uOffset) +{ + uint64_t auTagNumbers[2]; + + auTagNumbers[0] = uTagNumber; + auTagNumbers[1] = CBOR_TAG_INVALID64; + + QCBORDecode_Private_ProcessTagItemMulti(pMe, + pItem, + uTagRequirement, + uQCBORTypes, + auTagNumbers, + pfCB, + uOffset); +} + + +static void +QCBORDecode_Private_ProcessTagOne(QCBORDecodeContext *pMe, + QCBORItem *pItem, + const uint8_t uTagRequirement, + const uint8_t uQCBORType, + const uint64_t uTagNumber, + QCBORTagContentCallBack *pfCB, + const size_t uOffset) +{ + uint8_t auQCBORType[2]; + + auQCBORType[0] = uQCBORType; + auQCBORType[1] = QCBOR_TYPE_NONE; + + QCBORDecode_Private_ProcessTagItem(pMe, + pItem, + uTagRequirement, + auQCBORType, + uTagNumber, + pfCB, + uOffset); +} + + +void +QCBORDecode_Private_GetTaggedString(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + const uint8_t uQCBOR_Type, + const uint64_t uTagNumber, + UsefulBufC *pStr) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); + QCBORDecode_Private_ProcessTagOne(pMe, + &Item, + uTagRequirement, + uQCBOR_Type, + uTagNumber, + QCBORDecode_StringsTagCB, + uOffset); + + if(pMe->uLastError == QCBOR_SUCCESS) { + *pStr = Item.val.string; + } else { + *pStr = NULLUsefulBufC; + } +} + + +/** + * @brief Semi-private to get an string by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] nLabel Label to search map for. + * @param[in] uTagRequirement Whether or not tag number is required. + * See @ref QCBOR_TAG_REQUIREMENT_TAG. + * @param[in] uQCBOR_Type QCBOR type to search for. + * @param[in] uTagNumber Tag number to match. + * @param[out] pString The string found. + * + * This finds the string with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */ +void +QCBORDecode_Private_GetTaggedStringInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + const uint8_t uQCBOR_Type, + const uint64_t uTagNumber, + UsefulBufC *pString) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckN(pMe, + nLabel, + QCBOR_TYPE_ANY, + &Item, + &uOffset); + QCBORDecode_Private_ProcessTagOne(pMe, + &Item, + uTagRequirement, + uQCBOR_Type, + uTagNumber, + QCBORDecode_StringsTagCB, + uOffset); + + if(pMe->uLastError == QCBOR_SUCCESS) { + *pString = Item.val.string; + } +} + + +/** + * @brief Semi-private to get an string by label to match a tag specification. + * + * @param[in] pMe The decode context. + * @param[in] szLabel Label to search map for. + * @param[in] uTagRequirement Whether or not tag number is required. + * See @ref QCBOR_TAG_REQUIREMENT_TAG. + * @param[in] uQCBOR_Type QCBOR type to search for. + * @param[in] uTagNumber Tag number to match. + * @param[out] pString The string found. + * + * This finds the string with the given label in currently open + * map. Then checks that its tag number and types matches the tag + * specification. If not, an error is set in the decode context. + */ +void +QCBORDecode_Private_GetTaggedStringInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t uTagRequirement, + uint8_t uQCBOR_Type, + uint64_t uTagNumber, + UsefulBufC *pString) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, + szLabel, + QCBOR_TYPE_ANY, + &Item, + &uOffset); + QCBORDecode_Private_ProcessTagOne(pMe, + &Item, + uTagRequirement, + uQCBOR_Type, + uTagNumber, + QCBORDecode_StringsTagCB, + uOffset); + + + if(pMe->uLastError == QCBOR_SUCCESS) { + *pString = Item.val.string; + } +} + + + + +/** + * @brief The main work of entering some byte-string wrapped CBOR. + * + * @param[in] pMe The decode context. + * @param[in] pItem The byte string item. + * @param[in] uTagRequirement One of @c QCBOR_TAG_REQUIREMENT_XXX + * @param[out] pBstr Pointer and length of byte string entered. + * + * This is called once the byte string item has been decoded to do all + * the book keeping work for descending a nesting level into the + * nested CBOR. + * + * See QCBORDecode_EnterBstrWrapped() for details on uTagRequirement. + */ +static QCBORError +QCBORDecode_Private_EnterBstrWrapped(QCBORDecodeContext *pMe, + const QCBORItem *pItem, + const uint8_t uTagRequirement, + const size_t uOffset, + UsefulBufC *pBstr) +{ + bool bTypeMatched; + QCBORError uError; + + const uint8_t uTypes[] = {QBCOR_TYPE_WRAPPED_CBOR, + QBCOR_TYPE_WRAPPED_CBOR_SEQUENCE, + QCBOR_TYPE_NONE}; + const uint64_t uTagNumbers[] = {CBOR_TAG_CBOR, + CBOR_TAG_CBOR_SEQUENCE, + CBOR_TAG_INVALID64}; + + + if(pBstr) { + *pBstr = NULLUsefulBufC; + } + + if(pMe->uLastError != QCBOR_SUCCESS) { + return pMe->uLastError; + } + + if(pItem->uDataAlloc) { + return QCBOR_ERR_CANNOT_ENTER_ALLOCATED_STRING; + } + + uError = QCBORDecode_Private_CheckTagNType(pMe, + pItem, + uOffset, + uTypes,//TODO: maybe empty? + uTagNumbers, + uTagRequirement, + &bTypeMatched); + + if(pItem->uDataType != QCBOR_TYPE_BYTE_STRING) { + uError = QCBOR_ERR_BAD_TAG_CONTENT; // TODO: error + } + + + if(DecodeNesting_IsCurrentDefiniteLength(&(pMe->nesting))) { + /* Reverse the decrement done by GetNext() for the bstr so the + * increment in QCBORDecode_NestLevelAscender() called by + * ExitBoundedLevel() will work right. + */ + DecodeNesting_ReverseDecrement(&(pMe->nesting)); + } + + if(pBstr) { + *pBstr = pItem->val.string; + } + + /* This saves the current length of the UsefulInputBuf and then + * narrows the UsefulInputBuf to start and length of the wrapped + * CBOR that is being entered. + * + * Most of these calls are simple inline accessors so this doesn't + * amount to much code. + */ + + const size_t uPreviousLength = UsefulInputBuf_GetBufferLength(&(pMe->InBuf)); + /* This check makes the cast of uPreviousLength to uint32_t below safe. */ + if(uPreviousLength >= QCBOR_MAX_DECODE_INPUT_SIZE) { + uError = QCBOR_ERR_INPUT_TOO_LARGE; + goto Done; + } + + const size_t uStartOfBstr = UsefulInputBuf_PointerToOffset(&(pMe->InBuf), + pItem->val.string.ptr); + /* This check makes the cast of uStartOfBstr to uint32_t below safe. */ + if(uStartOfBstr == SIZE_MAX || uStartOfBstr > QCBOR_MAX_DECODE_INPUT_SIZE) { + /* This should never happen because pItem->val.string.ptr should + * always be valid since it was just returned. + */ + uError = QCBOR_ERR_INPUT_TOO_LARGE; + goto Done; + } + + const size_t uEndOfBstr = uStartOfBstr + pItem->val.string.len; + + UsefulInputBuf_Seek(&(pMe->InBuf), uStartOfBstr); + UsefulInputBuf_SetBufferLength(&(pMe->InBuf), uEndOfBstr); + + uError = DecodeNesting_DescendIntoBstrWrapped(&(pMe->nesting), + (uint32_t)uPreviousLength, + (uint32_t)uStartOfBstr); +Done: + return uError; +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_EnterBstrWrapped(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); + pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, + &Item, + uTagRequirement, + uOffset, + pBstr); +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_EnterBstrWrappedFromMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckN(pMe, + nLabel, + QCBOR_TYPE_BYTE_STRING, + &Item, + &uOffset); + pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, + &Item, + uTagRequirement, + uOffset, + pBstr); +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_EnterBstrWrappedFromMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pBstr) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, + szLabel, + QCBOR_TYPE_BYTE_STRING, + &Item, + &uOffset); + pMe->uLastError = (uint8_t)QCBORDecode_Private_EnterBstrWrapped(pMe, + &Item, + uTagRequirement, + uOffset, + pBstr); +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_ExitBstrWrapped(QCBORDecodeContext *pMe) +{ + if(pMe->uLastError != QCBOR_SUCCESS) { + // Already in error state; do nothing. + return; + } + + if(!DecodeNesting_IsBoundedType(&(pMe->nesting), QCBOR_TYPE_BYTE_STRING)) { + pMe->uLastError = QCBOR_ERR_EXIT_MISMATCH; + return; + } + + const uint32_t uEndOfBstr = (uint32_t)UsefulInputBuf_GetBufferLength(&(pMe->InBuf)); + + /* + Reset the length of the UsefulInputBuf to what it was before + the bstr wrapped CBOR was entered. + */ + UsefulInputBuf_SetBufferLength(&(pMe->InBuf), + DecodeNesting_GetPreviousBoundedEnd(&(pMe->nesting))); + + + QCBORError uErr = QCBORDecode_Private_ExitBoundedLevel(pMe, uEndOfBstr); + pMe->uLastError = (uint8_t)uErr; +} + + + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_GetEpochDate(QCBORDecodeContext *pMe, + uint8_t uTagRequirement, + int64_t *pnTime) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); + QCBORDecode_Private_ProcessTagOne(pMe, + &Item, + uTagRequirement, + QCBOR_TYPE_DATE_EPOCH, + CBOR_TAG_DATE_EPOCH, + QCBORDecode_DateEpochTagCB, + uOffset); + *pnTime = Item.val.epochDate.nSeconds; +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_GetEpochDateInMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnTime) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckN(pMe, + nLabel, + QCBOR_TYPE_ANY, + &Item, + &uOffset); + QCBORDecode_Private_ProcessTagOne(pMe, + &Item, + uTagRequirement, + QCBOR_TYPE_DATE_EPOCH, + CBOR_TAG_DATE_EPOCH, + QCBORDecode_DateEpochTagCB, + uOffset); + *pnTime = Item.val.epochDate.nSeconds; +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_GetEpochDateInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnTime) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, + szLabel, + QCBOR_TYPE_ANY, + &Item, + &uOffset); + QCBORDecode_Private_ProcessTagOne(pMe, + &Item, + uTagRequirement, + QCBOR_TYPE_DATE_EPOCH, + CBOR_TAG_DATE_EPOCH, + QCBORDecode_DateEpochTagCB, + uOffset); + *pnTime = Item.val.epochDate.nSeconds; +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_GetEpochDays(QCBORDecodeContext *pMe, + uint8_t uTagRequirement, + int64_t *pnDays) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); + QCBORDecode_Private_ProcessTagOne(pMe, + &Item, + uTagRequirement, + QCBOR_TYPE_DAYS_EPOCH, + CBOR_TAG_DAYS_EPOCH, + QCBORDecode_DaysEpochTagCB, + uOffset); + *pnDays = Item.val.epochDays; +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_GetEpochDaysInMapN(QCBORDecodeContext *pMe, + int64_t nLabel, + uint8_t uTagRequirement, + int64_t *pnDays) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckN(pMe, + nLabel, + QCBOR_TYPE_ANY, + &Item, + &uOffset); + QCBORDecode_Private_ProcessTagOne(pMe, + &Item, + uTagRequirement, + QCBOR_TYPE_DAYS_EPOCH, + CBOR_TAG_DAYS_EPOCH, + QCBORDecode_DaysEpochTagCB, + uOffset); + *pnDays = Item.val.epochDays; +} + + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_GetEpochDaysInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + uint8_t uTagRequirement, + int64_t *pnDays) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, + szLabel, + QCBOR_TYPE_ANY, + &Item, + &uOffset); + QCBORDecode_Private_ProcessTagOne(pMe, + &Item, + uTagRequirement, + QCBOR_TYPE_DAYS_EPOCH, + CBOR_TAG_DAYS_EPOCH, + QCBORDecode_DaysEpochTagCB, + uOffset); + *pnDays = Item.val.epochDays; +} + + + + +static void +QCBORDecode_Private_GetMIME(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + QCBORItem *pItem, + UsefulBufC *pValue, + bool *pbIsTag257, + size_t uOffset) +{ + QCBORError uErr; + + const uint8_t puTypes[] = {QCBOR_TYPE_MIME, QCBOR_TYPE_BINARY_MIME, QCBOR_TYPE_NONE}; + + const uint64_t puTNs[] = {CBOR_TAG_MIME, CBOR_TAG_BINARY_MIME, CBOR_TAG_INVALID64}; + + QCBORDecode_Private_ProcessTagItemMulti(pMe, + pItem, + uTagRequirement, + puTypes, + puTNs, + QCBORDecode_MIMETagCB, + uOffset); + if(pMe->uLastError) { + return; + } + + if(pItem->uDataType == QCBOR_TYPE_MIME) { + *pbIsTag257 = false; + } else if(pItem->uDataType == QCBOR_TYPE_BINARY_MIME) { + *pbIsTag257 = true; + } + *pValue = pItem->val.string; + + + uErr = QCBOR_SUCCESS; + + pMe->uLastError = (uint8_t)uErr; +} + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_GetMIMEMessage(QCBORDecodeContext *pMe, + const uint8_t uTagRequirement, + UsefulBufC *pMessage, + bool *pbIsTag257) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetAndTell(pMe, &Item, &uOffset); + QCBORDecode_Private_GetMIME(pMe, + uTagRequirement, + &Item, + pMessage, + pbIsTag257, + uOffset); +} + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_GetMIMEMessageInMapN(QCBORDecodeContext *pMe, + const int64_t nLabel, + const uint8_t uTagRequirement, + UsefulBufC *pMessage, + bool *pbIsTag257) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckN(pMe, + nLabel, + QCBOR_TYPE_ANY, + &Item, + &uOffset); + QCBORDecode_Private_GetMIME(pMe, + uTagRequirement, + &Item, + pMessage, + pbIsTag257, + uOffset); +} + +/* Public function; see qcbor_tag_decode.h */ +void +QCBORDecode_GetMIMEMessageInMapSZ(QCBORDecodeContext *pMe, + const char *szLabel, + const uint8_t uTagRequirement, + UsefulBufC *pMessage, + bool *pbIsTag257) +{ + QCBORItem Item; + size_t uOffset; + + QCBORDecode_Private_GetItemInMapNoCheckSZ(pMe, + szLabel, + QCBOR_TYPE_ANY, + &Item, + &uOffset); + QCBORDecode_Private_GetMIME(pMe, + uTagRequirement, + &Item, + pMessage, + pbIsTag257, + uOffset); +} + + + + /* Public function; see qcbor_tag_decode.h */ QCBORError QCBORDecode_DateEpochTagCB(QCBORDecodeContext *pDecodeCtx, @@ -166,7 +1181,8 @@ QCBORDecode_DaysEpochTagCB(QCBORDecodeContext *pDecodeCtx, * @ref CBOR_TAG_BIG_FLOAT. * @param[in] pDecodedItem Item being decoded. * - * @returns One of the ten values related to @ref QCBOR_TYPE_DECIMAL_FRACTION and @ref QCBOR_TYPE_BIGFLOAT + * @returns One of the ten values related to @ref QCBOR_TYPE_DECIMAL_FRACTION + * and @ref QCBOR_TYPE_BIGFLOAT * * Does mapping between a CBOR tag number and a QCBOR type with a * little logic and arithmetic.