Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

QCBOREncode_Tell and QCBOREncode_SubString #251

Merged
merged 8 commits into from
Aug 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
53 changes: 53 additions & 0 deletions inc/qcbor/UsefulBuf.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@

when who what, where, why
-------- ---- --------------------------------------------------
08/14/2024 llundblade Add UsefulOutBuf_RetrieveOutputStorage().
08/13/2024 llundblade Add UsefulInputBuf_RetrieveUndecodedInput().
08/08/2024 llundblade Add UsefulOutBuf_SubString().
10/05/2024 llundblade Add Xxx_OffsetToPointer.
19/12/2022 llundblade Document that adding empty data is allowed.
4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf.
Expand Down Expand Up @@ -1381,6 +1384,35 @@ UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *pUOutBuf);
UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pUOutBuf, UsefulBuf Dest);


/**
* @beief Return a substring of the output data.
*
* @param[in] pUOutBuf Pointer to the @ref UsefulOutBuf.
* @param[in] uStart Offset of start of substring.
* @param[in] uLen Length of substring.
*
* This is the same as UsefulOutBuf_OutUBuf(), but returns a
* substring. @c NULLUsefulBufC is returned if the requested substring
* is off the end of the output bytes or if in error state.
*/
UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pUOutBuf,
const size_t uStart,
const size_t uLen);


/**
* @brief Retrieve the storage buffer passed in to UsefulOutBuf_Init().
*
* @param[in] pUOutBuf The encoding context.
*
* @return The output storage buffer passed to UsefulOutBuf_Init().
*
* This doesn't give any information about how much has been encoded
* or the error state. It just returns the exact @ref UsefulOutBuf given
* to UsefulOutBuf_Init().
*/
static UsefulBuf UsefulOutBuf_RetrieveOutputStorage(UsefulOutBuf *pUOutBuf);



/**
Expand Down Expand Up @@ -1724,6 +1756,16 @@ static inline size_t UsefulInputBuf_GetBufferLength(UsefulInputBuf *pUInBuf);
static void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pUInBuf, size_t uNewLen);


/**
* @brief Retrieve the undecoded input buffer.
*
* @param[in] pUInBuf Pointer to the @ref UsefulInputBuf.
*
* @return The input that was given to UsefulInputBuf_Init().
*
* A simple convenience method, should it be useful to get the original input back.
*/
static UsefulBufC UsefulInputBuf_RetrieveUndecodedInput(UsefulInputBuf *pUInBuf);


/*----------------------------------------------------------
Expand Down Expand Up @@ -2228,6 +2270,12 @@ static inline UsefulBuf UsefulOutBuf_GetOutPlace(UsefulOutBuf *pUOutBuf)
}


static inline UsefulBuf UsefulOutBuf_RetrieveOutputStorage(UsefulOutBuf *pMe)
{
return pMe->UB;
}




static inline void UsefulInputBuf_Init(UsefulInputBuf *pMe, UsefulBufC UB)
Expand Down Expand Up @@ -2496,6 +2544,11 @@ static inline void UsefulInputBuf_SetBufferLength(UsefulInputBuf *pMe, size_t uN
pMe->UB.len = uNewLen;
}

static inline UsefulBufC UsefulInputBuf_RetrieveUndecodedInput(UsefulInputBuf *pMe)
{
return pMe->UB;
}


#ifdef __cplusplus
}
Expand Down
19 changes: 19 additions & 0 deletions inc/qcbor/qcbor_decode.h
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,19 @@ QCBORError
QCBORDecode_PartialFinish(QCBORDecodeContext *pCtx, size_t *puConsumed);


/**
* @brief Retrieve the undecoded input buffer.
*
* @param[in] pCtx The decode context.
*
* @return The input that was given to QCBORDecode_Init().
*
* A simple convenience method, should it be useful to get the original input back.
*/
static UsefulBufC
QCBORDecode_RetrieveUndecodedInput(QCBORDecodeContext *pCtx);


/**
* @brief Get the decoding error.
*
Expand Down Expand Up @@ -1608,6 +1621,12 @@ QCBORDecode_Tell(QCBORDecodeContext *pMe)
return (uint32_t)UsefulInputBuf_Tell(&(pMe->InBuf));
}

static inline UsefulBufC
QCBORDecode_RetrieveUndecodedInput(QCBORDecodeContext *pMe)
{
return UsefulInputBuf_RetrieveUndecodedInput(&(pMe->InBuf));
}

static inline QCBORError
QCBORDecode_GetError(QCBORDecodeContext *pMe)
{
Expand Down
106 changes: 100 additions & 6 deletions inc/qcbor/qcbor_encode.h
Original file line number Diff line number Diff line change
Expand Up @@ -2226,7 +2226,8 @@ QCBOREncode_AddEncodedToMapN(QCBOREncodeContext *pCtx, int64_t nLabel, UsefulBuf
*
* This may be called multiple times. It will always return the
* same. It can also be interleaved with calls to
* QCBOREncode_FinishGetSize().
* QCBOREncode_FinishGetSize(). See QCBOREncode_SubString() for a
* means to get the thus-far-encoded CBOR.
*
* QCBOREncode_GetErrorState() can be called to get the current
* error state in order to abort encoding early as an optimization, but
Expand All @@ -2253,21 +2254,34 @@ QCBOREncode_FinishGetSize(QCBOREncodeContext *pCtx, size_t *uEncodedLen);


/**
* @brief Indicate whether output buffer is NULL or not.
* @brief Indicate whether the output storage buffer is NULL.
*
* @param[in] pCtx The encoding context.
*
* @return 1 if the output buffer is @c NULL.
*
* Sometimes a @c NULL input buffer is given to QCBOREncode_Init() so
* that the size of the generated CBOR can be calculated without
* allocating a buffer for it. This returns 1 when the output buffer
* is @c NULL and 0 when it is not.
* As described in QCBOREncode_Init(), @c Storage.ptr may be give as @c NULL
* for output size calculation. This returns 1 when that is the true, and 0 if not.
*/
static int
QCBOREncode_IsBufferNULL(QCBOREncodeContext *pCtx);


/**
* @brief Retrieve the storage buffer passed in to QCBOREncode_Init().
*
* @param[in] pCtx The encoding context.
*
* @return The output storage buffer passed to QCBOREncode_Init().
*
* This doesn't give any information about how much has been encoded
* or the error state. It just returns the exact @ref UsefulOutBuf given
* to QCBOREncode_Init().
*/
static UsefulBuf
QCBOREncode_RetrieveOutputStorage(QCBOREncodeContext *pCtx);


/**
* @brief Get the encoding error state.
*
Expand All @@ -2285,6 +2299,72 @@ static QCBORError
QCBOREncode_GetErrorState(QCBOREncodeContext *pCtx);


/**
* @brief Returns current end of encoded data.
*
* @param[in] pCtx The encoding context.
*
* @return Byte offset of end of encoded data.
*
* The purpose of this is to enable cryptographic hashing over a
* subpart of thus far CBOR-encoded data. Then perhaps a signature
* over the hashed CBOR is added to the encoded output. There is
* nothing specific to hashing or signing in this, so this can be used
* for other too.
*
* Call this to get the offset of the start of the encoded
* to-be-hashed CBOR items, then call QCBOREncode_SubString().
* QCBOREncode_Tell() can also be called twice, first to get the
* offset of the start and second for the offset of the end. Those
* offsets can be applied to the output storage buffer.
*
* This will return successfully even if the encoder is in the error
* state.
*
* WARNING: All definite-length arrays and maps opened before the
* first call to QCBOREncode_Tell() must not be closed until the
* substring is obtained and processed. Similarly, every
* definite-length array or map opened after the first call to
* QCBOREncode_Tell() must be closed before the substring is obtained
* and processed. The same applies for opened byte strings. There is
* no detection of these errors. This occurs because QCBOR goes back
* and inserts the lengths of definite-length arrays and maps when
* they are closed. This insertion will make the offsets incorrect.
*/
static size_t
QCBOREncode_Tell(QCBOREncodeContext *pCtx);


/**
* @brief Get a substring of encoded CBOR for cryptographic hash
*
* @param[in] pCtx The encoding context.
* @param[in] uStart The start offset of substring.
*
* @return Pointer and length of of substring.
*
* @c uStart is obtained by calling QCBOREncode_Tell() before encoding
* the first item in the substring. Then encode some data items. Then
* call this. The substring returned contains the encoded data items.
*
* The substring may have deeply nested arrays and maps as long as any
* opened after the call to QCBOREncode_Tell() are closed before this
* is called.
*
* This will return @c NULLUsefulBufC if the encoder is in the error
* state or if @c uStart is beyond the end of the thus-far encoded
* data items.
*
* If @c uStart is 0, all the thus-far-encoded CBOR will be returned.
* Unlike QCBOREncode_Finish(), this will succeed even if some arrays
* and maps are not closed.
*
* See important usage WARNING in QCBOREncode_Tell()
*/
UsefulBufC
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since this is the encoder side and the original buffer is mutable anyway, could this return a non-const UsefulBuf?

Copy link
Owner Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That would be counter to the UsefulBuf convention of UsefulBuf's with data always be const and empty buffers not const. I think that convention is upheld everywhere (including t_cose).

I don't mean to be pedantic about it, but I'd like to keep it as for consistency with the convention.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's fair and my need can use overall Tell offsets where modifying the encoded form is needed for efficiency.

QCBOREncode_SubString(QCBOREncodeContext *pCtx, const size_t uStart);


/**
* Encode the "head" of a CBOR data item.
*
Expand Down Expand Up @@ -4019,6 +4099,14 @@ QCBOREncode_IsBufferNULL(QCBOREncodeContext *pMe)
return UsefulOutBuf_IsBufferNULL(&(pMe->OutBuf));
}


static inline UsefulBuf
QCBOREncode_RetrieveOutputStorage(QCBOREncodeContext *pMe)
{
return UsefulOutBuf_RetrieveOutputStorage(&(pMe->OutBuf));
}


static inline QCBORError
QCBOREncode_GetErrorState(QCBOREncodeContext *pMe)
{
Expand All @@ -4040,6 +4128,12 @@ QCBOREncode_GetErrorState(QCBOREncodeContext *pMe)
}


static inline size_t
QCBOREncode_Tell(QCBOREncodeContext *pMe)
{
return UsefulOutBuf_GetEndPosition(&(pMe->OutBuf));
}

/* ========================================================================
END OF PRIVATE INLINE IMPLEMENTATION
======================================================================== */
Expand Down
30 changes: 30 additions & 0 deletions src/UsefulBuf.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@

when who what, where, why
-------- ---- ---------------------------------------------------
08/08/2024 llundblade Add UsefulOutBuf_SubString().
21/05/2024 llundblade Comment formatting and some code tidiness.
19/12/2022 llundblade Don't pass NULL to memmove when adding empty data.
4/11/2022 llundblade Add GetOutPlace and Advance to UsefulOutBuf
Expand Down Expand Up @@ -413,6 +414,35 @@ UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *pMe, UsefulBuf pDest)
}


/*
* Public function -- see UsefulBuf.h
*
* Code Reviewers: THIS FUNCTION DOES POINTER MATH
*/
UsefulBufC UsefulOutBuf_SubString(UsefulOutBuf *pMe,
const size_t uStart,
const size_t uLen)
{
const UsefulBufC Tmp = UsefulOutBuf_OutUBuf(pMe);

if(UsefulBuf_IsNULLC(Tmp)) {
return NULLUsefulBufC;
}

if(uStart > Tmp.len) {
return NULLUsefulBufC;
}

if(Tmp.len - uStart < uLen) {
return NULLUsefulBufC;
}

UsefulBufC SubString;
SubString.ptr = (const uint8_t *)Tmp.ptr + uStart;
SubString.len = uLen;

return SubString;
}


/*
Expand Down
27 changes: 26 additions & 1 deletion src/qcbor_encode.c
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ Nesting_IsInNest(QCBORTrackNesting *pNesting)
{
return pNesting->pCurrentNesting == &pNesting->pArrays[0] ? false : true;
}
#endif /* QCBOR_DISABLE_ENCODE_USAGE_GUARDS */
#endif /* ! QCBOR_DISABLE_ENCODE_USAGE_GUARDS */



Expand Down Expand Up @@ -1085,3 +1085,28 @@ QCBOREncode_FinishGetSize(QCBOREncodeContext *pMe, size_t *puEncodedLen)

return nReturn;
}


/*
* Public function to get substring of encoded-so-far. See qcbor/qcbor_encode.h
*/
UsefulBufC
QCBOREncode_SubString(QCBOREncodeContext *pMe, const size_t uStart)
{
if(pMe->uError) {
return NULLUsefulBufC;
}

/* An attempt was made to detect usage errors by comparing uStart
* to offsets of open arrays and maps in pMe->nesting, but it is
* not possible because there's not enough information in just
* the offset. It's not possible to known if Tell() was called before
* or after an Open(). To detect this error, the nesting level
* would also need to be known. This is not frequently used, so
* it is not worth adding this complexity.
*/

const size_t uEnd = QCBOREncode_Tell(pMe);

return UsefulOutBuf_SubString(&(pMe->OutBuf), uStart, uEnd - uStart);
}
Loading
Loading