| /*============================================================================== |
| Copyright (c) 2016-2018, The Linux Foundation. |
| Copyright (c) 2018-2019, Laurence Lundblade. |
| All rights reserved. |
| |
| Redistribution and use in source and binary forms, with or without |
| modification, are permitted provided that the following conditions are |
| met: |
| * Redistributions of source code must retain the above copyright |
| notice, this list of conditions and the following disclaimer. |
| * Redistributions in binary form must reproduce the above |
| copyright notice, this list of conditions and the following |
| disclaimer in the documentation and/or other materials provided |
| with the distribution. |
| * Neither the name of The Linux Foundation nor the names of its |
| contributors, nor the name "Laurence Lundblade" may be used to |
| endorse or promote products derived from this software without |
| specific prior written permission. |
| |
| THIS SOFTWARE IS PROVIDED "AS IS" AND ANY EXPRESS OR IMPLIED |
| WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF |
| MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT |
| ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS |
| BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR |
| CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF |
| SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR |
| BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, |
| WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE |
| OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN |
| IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. |
| ==============================================================================*/ |
| |
| /*=================================================================================== |
| FILE: UsefulBuf.h |
| |
| DESCRIPTION: General purpose input and output buffers |
| |
| EDIT HISTORY FOR FILE: |
| |
| This section contains comments describing changes made to the module. |
| Notice that changes are listed in reverse chronological order. |
| |
| when who what, where, why |
| -------- ---- --------------------------------------------------- |
| 12/17/2018 llundblade Remove const from UsefulBuf and UsefulBufC .len |
| 12/13/2018 llundblade Documentation improvements |
| 09/18/2018 llundblade Cleaner distinction between UsefulBuf and UsefulBufC |
| 02/02/18 llundbla Full support for integers in and out; fix pointer alignment bug |
| Incompatible change: integers in/out are now in network byte order. |
| 08/12/17 llundbla Added UsefulOutBuf_AtStart and UsefulBuf_Find |
| 06/27/17 llundbla Fix UsefulBuf_Compare() bug. Only affected comparison |
| for < or > for unequal length buffers. Added |
| UsefulBuf_Set() function. |
| 05/30/17 llundbla Functions for NULL UsefulBufs and const / unconst |
| 11/13/16 llundbla Initial Version. |
| |
| |
| =====================================================================================*/ |
| |
| #ifndef _UsefulBuf_h |
| #define _UsefulBuf_h |
| |
| |
| #include <stdint.h> // for uint8_t, uint16_t.... |
| #include <string.h> // for strlen, memcpy, memmove, memset |
| #include <stddef.h> // for size_t |
| |
| /** |
| @file UsefulBuf.h |
| |
| The goal of this code is to make buffer and pointer manipulation |
| easier and safer when working with binary data. |
| |
| You use the UsefulBuf, UsefulOutBuf and UsefulInputBuf |
| structures to represent buffers rather than ad hoc pointers and lengths. |
| |
| With these it will often be possible to write code that does little or no |
| direct pointer manipulation for copying and formatting data. For example |
| the QCBOR encoder was rewritten using these and has no direct pointer |
| manipulation. |
| |
| While it is true that object code using these functions will be a little |
| larger and slower than a white-knuckle clever use of pointers might be, but |
| not by that much or enough to have an affect for most use cases. For |
| security-oriented code this is highly worthwhile. Clarity, simplicity, |
| reviewability and are more important. |
| |
| There are some extra sanity and double checks in this code to help catch |
| coding errors and simple memory corruption. They are helpful, but not a |
| substitute for proper code review, input validation and such. |
| |
| This code consists of a lot of inline functions and a few that are not. |
| It should not generate very much object code, especially with the |
| optimizer turned up to -Os or -O3. The idea is that the inline |
| functions are easier to review and understand and the optimizer does |
| the work of making the code small. |
| */ |
| |
| |
| /*...... This is a ruler that is 80 characters long...........................*/ |
| |
| /** |
| UsefulBufC and UsefulBuf are simple data structures to hold a pointer and |
| length for a binary data. In C99 this data structure can be passed on the |
| stack making a lot of code cleaner than carrying around a pointer and |
| length as two parameters. |
| |
| This is also conducive to secure code practice as the lengths are |
| always carried with the pointer and the convention for handling a |
| pointer and a length is clear. |
| |
| While it might be possible to write buffer and pointer code more |
| efficiently in some use cases, the thought is that unless there is an |
| extreme need for performance (e.g., you are building a gigabit-per-second |
| IP router), it is probably better to have cleaner code you can be most |
| certain about the security of. |
| |
| The non-const UsefulBuf is usually used to refer a buffer to be filled in. |
| The length is the size of the buffer. |
| |
| The const UsefulBufC is usually used to refer to some data that has been |
| filled in. The length is amount of valid data pointed to. |
| |
| A common use is to pass a UsefulBuf to a function, the function fills it |
| in, the function returns a UsefulBufC. The pointer is the same in both. |
| |
| A UsefulBuf is NULL, it has no value, when the ptr in it is NULL. |
| |
| There are utility functions for the following: |
| - Checking for UsefulBufs that are NULL, empty or both |
| - Copying, copying with offset, copying head or tail |
| - Comparing and finding substrings |
| - Initializating |
| - Create initialized const UsefulBufC from compiler literals |
| - Create initialized const UsefulBufC from NULL-terminated string |
| - Make an empty UsefulBuf on the stack |
| |
| See also UsefulOutBuf. It is a richer structure that has both the size of |
| the valid data and the size of the buffer. |
| |
| UsefulBuf is only 16 or 8 bytes on a 64- or 32-bit machine so it can go |
| on the stack and be a function parameter or return value. |
| |
| UsefulBuf is kind of like the Useful Pot Pooh gave Eeyore on his birthday. |
| Eeyore's balloon fits beautifully, "it goes in and out like anything". |
| |
| */ |
| typedef struct { |
| const void *ptr; |
| size_t len; |
| } UsefulBufC; |
| |
| |
| /** |
| The non-const UsefulBuf typically used for some allocated memory |
| that is to be filled in. The len is the amount of memory, |
| not the length of the valid data in the buffer. |
| */ |
| typedef struct { |
| void *ptr; |
| size_t len; |
| } UsefulBuf; |
| |
| |
| /** |
| A "NULL" UsefulBufC is one that has no value in the same way a NULL pointer has no value. |
| A UsefulBuf is NULL when the ptr field is NULL. It doesn't matter what len is. |
| See UsefulBuf_IsEmpty() for the distinction between NULL and empty. |
| */ |
| #define NULLUsefulBufC ((UsefulBufC) {NULL, 0}) |
| |
| /** A NULL UsefulBuf is one that has no memory associated the say way |
| NULL points to nothing. It does not matter what len is. |
| */ |
| #define NULLUsefulBuf ((UsefulBuf) {NULL, 0}) |
| |
| |
| /** |
| @brief Check if a UsefulBuf is NULL or not |
| |
| @param[in] UB The UsefulBuf to check |
| |
| @return 1 if it is NULL, 0 if not. |
| */ |
| static inline int UsefulBuf_IsNULL(UsefulBuf UB) { |
| return !UB.ptr; |
| } |
| |
| |
| /** |
| @brief Check if a UsefulBufC is NULL or not |
| |
| @param[in] UB The UsefulBufC to check |
| |
| @return 1 if it is NULL, 0 if not. |
| */ |
| static inline int UsefulBuf_IsNULLC(UsefulBufC UB) { |
| return !UB.ptr; |
| } |
| |
| |
| /** |
| @brief Check if a UsefulBuf is empty or not |
| |
| @param[in] UB The UsefulBuf to check |
| |
| @return 1 if it is empty, 0 if not. |
| |
| An "Empty" UsefulBuf is one that has a value and can be considered to be set, |
| but that value is of zero length. It is empty when len is zero. It |
| doesn't matter what the ptr is. |
| |
| A lot of uses will not need to clearly distinguish a NULL UsefulBuf |
| from an empty one and can have the ptr NULL and the len 0. However |
| if a use of UsefulBuf needs to make a distinction then ptr should |
| not be NULL when the UsefulBuf is considered empty, but not NULL. |
| |
| */ |
| static inline int UsefulBuf_IsEmpty(UsefulBuf UB) { |
| return !UB.len; |
| } |
| |
| |
| /** |
| @brief Check if a UsefulBufC is empty or not |
| |
| @param[in] UB The UsefulBufC to check |
| |
| @return 1 if it is empty, 0 if not. |
| */ |
| static inline int UsefulBuf_IsEmptyC(UsefulBufC UB) { |
| return !UB.len; |
| } |
| |
| |
| /** |
| @brief Check if a UsefulBuf is NULL or empty |
| |
| @param[in] UB The UsefulBuf to check |
| |
| @return 1 if it is either NULL or empty, 0 if not. |
| */ |
| static inline int UsefulBuf_IsNULLOrEmpty(UsefulBuf UB) { |
| return UsefulBuf_IsEmpty(UB) || UsefulBuf_IsNULL(UB); |
| } |
| |
| |
| /** |
| @brief Check if a UsefulBufC is NULL or empty |
| |
| @param[in] UB The UsefulBufC to check |
| |
| @return 1 if it is either NULL or empty, 0 if not. |
| */ |
| static inline int UsefulBuf_IsNULLOrEmptyC(UsefulBufC UB) { |
| return UsefulBuf_IsEmptyC(UB) || UsefulBuf_IsNULLC(UB); |
| } |
| |
| |
| /** |
| @brief Convert a non const UsefulBuf to a const UsefulBufC |
| |
| @param[in] UB The UsefulBuf to convert |
| |
| Returns: a UsefulBufC struct |
| */ |
| |
| static inline UsefulBufC UsefulBuf_Const(const UsefulBuf UB) |
| { |
| return (UsefulBufC){UB.ptr, UB.len}; |
| } |
| |
| |
| /** |
| @brief Convert a const UsefulBufC to a non-const UsefulBuf |
| |
| @param[in] UBC The UsefulBuf to convert |
| |
| Returns: a non const UsefulBuf struct |
| */ |
| static inline UsefulBuf UsefulBuf_Unconst(const UsefulBufC UBC) |
| { |
| return (UsefulBuf){(void *)UBC.ptr, UBC.len}; |
| } |
| |
| |
| /** |
| Convert a literal string to a UsefulBufC. |
| |
| szString must be a literal string that you can take sizeof. |
| This is better for literal strings than UsefulBuf_FromSZ() |
| because it generates less code. It will not work on |
| non-literal strings. |
| |
| The terminating \0 (NULL) is NOT included in the length! |
| |
| */ |
| #define UsefulBuf_FROM_SZ_LITERAL(szString) \ |
| ((UsefulBufC) {(szString), sizeof(szString)-1}) |
| |
| |
| /** |
| Convert a literal byte array to a UsefulBufC. |
| |
| pBytes must be a literal string that you can take sizeof. |
| It will not work on non-literal arrays. |
| |
| */ |
| #define UsefulBuf_FROM_BYTE_ARRAY_LITERAL(pBytes) \ |
| ((UsefulBufC) {(pBytes), sizeof(pBytes)}) |
| |
| |
| /** |
| Make an automatic variable with name of type UsefulBuf and point it to a stack |
| variable of the give size |
| */ |
| #define UsefulBuf_MAKE_STACK_UB(name, size) \ |
| uint8_t __pBuf##name[(size)];\ |
| UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )} |
| |
| |
| /** |
| Make a byte array in to a UsefulBuf |
| */ |
| #define UsefulBuf_FROM_BYTE_ARRAY(pBytes) \ |
| ((UsefulBuf) {(pBytes), sizeof(pBytes)}) |
| |
| /** |
| @brief Convert a NULL terminated string to a UsefulBufC. |
| |
| @param[in] szString The string to convert |
| |
| @return a UsefulBufC struct |
| |
| UsefulBufC.ptr points to the string so it's lifetime |
| must be maintained. |
| |
| The terminating \0 (NULL) is NOT included in the length! |
| |
| */ |
| static inline UsefulBufC UsefulBuf_FromSZ(const char *szString){ |
| return ((UsefulBufC) {szString, strlen(szString)}); |
| } |
| |
| |
| /** |
| @brief Copy one UsefulBuf into another at an offset |
| |
| @param[in] Dest Destiation buffer to copy into |
| @param[in] uOffset The byte offset in Dest at which to copy to |
| @param[in] Src The bytes to copy |
| |
| @return Pointer and length of the copy |
| |
| This fails and returns NULLUsefulBufC Src.len + uOffset > Dest.len. |
| |
| Like memcpy, there is no check for NULL. If NULL is passed |
| this will crash. |
| |
| There is an assumption that there is valid data in Dest up to |
| uOffset as the resulting UsefulBufC returned starts |
| at the beginning of Dest and goes to Src.len + uOffset. |
| |
| */ |
| UsefulBufC UsefulBuf_CopyOffset(UsefulBuf Dest, size_t uOffset, const UsefulBufC Src); |
| |
| |
| /** |
| @brief Copy one UsefulBuf into another |
| |
| @param[in] Dest The destination buffer to copy into |
| @param[out] Src The source to copy from |
| |
| @return filled in UsefulBufC on success, NULLUsefulBufC on failure |
| |
| This fails if Src.len is greater than Dest.len. |
| |
| Note that like memcpy, the pointers are not checked and |
| this will crash, rather than return NULLUsefulBufC if |
| they are NULL or invalid. |
| |
| Results are undefined if Dest and Src overlap. |
| |
| */ |
| static inline UsefulBufC UsefulBuf_Copy(UsefulBuf Dest, const UsefulBufC Src) { |
| return UsefulBuf_CopyOffset(Dest, 0, Src); |
| } |
| |
| |
| /** |
| @brief Set all bytes in a UsefulBuf to a value, for example 0 |
| |
| @param[in] pDest The destination buffer to copy into |
| @param[in] value The value to set the bytes to |
| |
| Note that like memset, the pointer in pDest is not checked and |
| this will crash if NULL or invalid. |
| |
| */ |
| static inline UsefulBufC UsefulBuf_Set(UsefulBuf pDest, uint8_t value) |
| { |
| memset(pDest.ptr, value, pDest.len); |
| return (UsefulBufC){pDest.ptr, pDest.len}; |
| } |
| |
| |
| /** |
| @brief Copy a pointer into a UsefulBuf |
| |
| @param[in,out] Dest The destination buffer to copy into |
| @param[in] ptr The source to copy from |
| @param[in] len Length of the source; amoutn to copy |
| |
| @return 0 on success, 1 on failure |
| |
| This fails and returns NULLUsefulBufC if len is greater than |
| pDest->len. |
| |
| Note that like memcpy, the pointers are not checked and |
| this will crash, rather than return 1 if they are NULL |
| or invalid. |
| |
| */ |
| inline static UsefulBufC UsefulBuf_CopyPtr(UsefulBuf Dest, const void *ptr, size_t len) |
| { |
| return UsefulBuf_Copy(Dest, (UsefulBufC){ptr, len}); |
| } |
| |
| |
| /** |
| @brief Returns a truncation of a UsefulBufC |
| |
| @param[in] UB The buffer to get the head of |
| @param[in] uAmount The number of bytes in the head |
| |
| @return A UsefulBufC that is the head of UB |
| |
| */ |
| static inline UsefulBufC UsefulBuf_Head(UsefulBufC UB, size_t uAmount) |
| { |
| if(uAmount > UB.len) { |
| return NULLUsefulBufC; |
| } |
| return (UsefulBufC){UB.ptr, uAmount}; |
| } |
| |
| |
| /** |
| @brief Returns bytes from the end of a UsefulBufC |
| |
| @param[in] UB The buffer to get the tail of |
| @param[in] uAmount The offset from the start where the tail is to begin |
| |
| @return A UsefulBufC that is the tail of UB or NULLUsefulBufC if |
| uAmount is greater than the length of the UsefulBufC |
| |
| If the input UsefulBufC is NULL, but the len is not, then the |
| length of the tail will be calculated and returned along |
| with a NULL ptr. |
| */ |
| static inline UsefulBufC UsefulBuf_Tail(UsefulBufC UB, size_t uAmount) |
| { |
| UsefulBufC ReturnValue; |
| |
| if(uAmount > UB.len) { |
| ReturnValue = NULLUsefulBufC; |
| } else if(UB.ptr == NULL) { |
| ReturnValue = (UsefulBufC){NULL, UB.len - uAmount}; |
| } else { |
| ReturnValue = (UsefulBufC){(uint8_t *)UB.ptr + uAmount, UB.len - uAmount}; |
| } |
| |
| return ReturnValue; |
| } |
| |
| |
| /** |
| @brief Compare two UsefulBufCs |
| |
| @param[in] UB1 The destination buffer to copy into |
| @param[in] UB2 The source to copy from |
| |
| @return 0 if equal... |
| |
| Returns a negative value if UB1 if is less than UB2. UB1 is |
| less than UB2 if it is shorter or the first byte that is not |
| the same is less. |
| |
| Returns 0 if the UsefulBufs are the same. |
| |
| Returns a positive value if UB2 is less than UB1. |
| |
| All that is of significance is that the result is positive, |
| negative or 0. (This doesn't return the difference between |
| the first non-matching byte like memcmp). |
| |
| */ |
| int UsefulBuf_Compare(const UsefulBufC UB1, const UsefulBufC UB2); |
| |
| |
| /** |
| @brief Find one UsefulBuf in another |
| |
| @param[in] BytesToSearch UsefulBuf to search through |
| @param[in] BytesToFind UsefulBuf with bytes to be found |
| |
| @return position of found bytes or SIZE_MAX if not found. |
| |
| */ |
| size_t UsefulBuf_FindBytes(UsefulBufC BytesToSearch, UsefulBufC BytesToFind); |
| |
| |
| |
| |
| #if 0 // NOT_DEPRECATED |
| /** Deprecated macro; use UsefulBuf_FROM_SZ_LITERAL instead */ |
| #define SZLiteralToUsefulBufC(szString) \ |
| ((UsefulBufC) {(szString), sizeof(szString)-1}) |
| |
| /** Deprecated macro; use UsefulBuf_MAKE_STACK_UB instead */ |
| #define MakeUsefulBufOnStack(name, size) \ |
| uint8_t __pBuf##name[(size)];\ |
| UsefulBuf name = {__pBuf##name , sizeof( __pBuf##name )} |
| |
| /** Deprecated macro; use UsefulBuf_FROM_BYTE_ARRAY_LITERAL instead */ |
| #define ByteArrayLiteralToUsefulBufC(pBytes) \ |
| ((UsefulBufC) {(pBytes), sizeof(pBytes)}) |
| |
| /** Deprecated function; use UsefulBuf_Unconst() instead */ |
| static inline UsefulBuf UsefulBufC_Unconst(const UsefulBufC UBC) |
| { |
| return (UsefulBuf){(void *)UBC.ptr, UBC.len}; |
| } |
| #endif |
| |
| |
| |
| /* |
| Convenient functions to avoid type punning, compiler warnings and such |
| The optimizer reduces them to a simple assignment |
| This is a crusty corner of C. It shouldn't be this hard. |
| */ |
| static inline uint32_t UsefulBufUtil_CopyFloatToUint32(float f) |
| { |
| uint32_t u32; |
| memcpy(&u32, &f, sizeof(uint32_t)); |
| return u32; |
| } |
| |
| static inline uint64_t UsefulBufUtil_CopyDoubleToUint64(double d) |
| { |
| uint64_t u64; |
| memcpy(&u64, &d, sizeof(uint64_t)); |
| return u64; |
| } |
| |
| static inline double UsefulBufUtil_CopyUint64ToDouble(uint64_t u64) |
| { |
| double d; |
| memcpy(&d, &u64, sizeof(uint64_t)); |
| return d; |
| } |
| |
| static inline float UsefulBufUtil_CopyUint32ToFloat(uint32_t u32) |
| { |
| float f; |
| memcpy(&f, &u32, sizeof(uint32_t)); |
| return f; |
| } |
| |
| |
| |
| |
| |
| /** |
| UsefulOutBuf is a structure and functions (an object) that are good |
| for serializing data into a buffer such as is often done with network |
| protocols or data written to files. |
| |
| The main idea is that all the pointer manipulation for adding data is |
| done by UsefulOutBuf functions so the caller doesn't have to do any. |
| All the pointer manipulation is centralized here. This code will |
| have been reviewed and written carefully so it spares the caller of |
| much of this work and results in much safer code with much less work. |
| |
| The functions to add data to the output buffer always check the |
| length and will never write off the end of the output buffer. If an |
| attempt to add data that will not fit is made, an internal error flag |
| will be set and further attempts to add data will not do anything. |
| |
| Basically, if you initialized with the correct buffer, there is no |
| way to ever write off the end of that buffer when calling the Add |
| and Insert functions here. |
| |
| The functions to add data do not return an error. The working model |
| is that the caller just makes all the calls to add data without any |
| error checking on each one. The error is instead checked after all the |
| data is added when the result is to be used. This makes the caller's |
| code cleaner. |
| |
| There is a utility function to get the error status anytime along the |
| way if the caller wants. There are functions to see how much room is |
| left and see if some data will fit too, but their use is generally |
| not necessary. |
| |
| The general call flow is like this: |
| |
| - Initialize the UsefulOutBuf with the buffer that is to have the |
| data added. The caller allocates the buffer. It can be heap |
| or stack or shared memory (or other). |
| |
| - Make calls to add data to the output buffer. Insert and append |
| are both supported. The append and insert calls will never write |
| off the end of the buffer. |
| |
| - When all data is added, check the error status to make sure |
| everything fit. |
| |
| - Get the resulting serialized data either as a UsefulBuf (a |
| pointer and length) or have it copied to another buffer. |
| |
| UsefulOutBuf can be initialized with just a buffer length by passing |
| NULL as the pointer to the output buffer. This is useful if you want |
| to go through the whole serialization process to either see if it |
| will fit into a given buffer or compute the size of the buffer |
| needed. Pass a very large buffer size when calling Init, if you want |
| just to compute the size. |
| |
| Some inexpensive simple sanity checks are performed before every data |
| addition to guard against use of an uninitialized or corrupted |
| UsefulOutBuf. |
| |
| This has been used to create a CBOR encoder. The CBOR encoder has |
| almost no pointer manipulation in it, is much easier to read, and |
| easier to review. |
| |
| A UsefulOutBuf is 27 bytes or 15 bytes on 64- or 32-bit machines so it |
| can go on the stack or be a C99 function parameter. |
| */ |
| |
| typedef struct { |
| UsefulBuf UB; // Memory that is being output to |
| size_t data_len; // length of the data |
| uint16_t magic; // Used to detect corruption and lack of initialization |
| uint8_t err; |
| } UsefulOutBuf; |
| |
| |
| /** |
| @brief Initialize and supply the actual output buffer |
| |
| @param[out] me The UsefulOutBuf to initialize |
| @param[in] Storage Buffer to output into |
| |
| Intializes the UsefulOutBuf with storage. Sets the current position |
| to the beginning of the buffer clears the error. |
| |
| This must be called before the UsefulOutBuf is used. |
| */ |
| void UsefulOutBuf_Init(UsefulOutBuf *me, UsefulBuf Storage); |
| |
| |
| |
| |
| /** Convenience marco to make a UsefulOutBuf on the stack and |
| initialize it with stack buffer |
| */ |
| #define UsefulOutBuf_MakeOnStack(name, size) \ |
| uint8_t __pBuf##name[(size)];\ |
| UsefulOutBuf name;\ |
| UsefulOutBuf_Init(&(name), (UsefulBuf){__pBuf##name, (size)}); |
| |
| |
| |
| /** |
| @brief Reset a UsefulOutBuf for re use |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| |
| This sets the amount of data in the output buffer to none and |
| clears the error state. |
| |
| The output buffer is still the same one and size as from the |
| UsefulOutBuf_Init() call. |
| |
| It doesn't zero the data, just resets to 0 bytes of valid data. |
| */ |
| static inline void UsefulOutBuf_Reset(UsefulOutBuf *me) |
| { |
| me->data_len = 0; |
| me->err = 0; |
| } |
| |
| |
| /** |
| @brief Returns position of end of data in the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| |
| @return position of end of data |
| |
| On a freshly initialized UsefulOutBuf with no data added, this will |
| return 0. After ten bytes have been added, it will return 10 and so |
| on. |
| |
| Generally callers will not need this function for most uses of |
| UsefulOutBuf. |
| |
| */ |
| static inline size_t UsefulOutBuf_GetEndPosition(UsefulOutBuf *me) |
| { |
| return me->data_len; |
| } |
| |
| |
| /** |
| @brief Returns whether any data has been added to the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| |
| @return 1 if output position is at start |
| |
| */ |
| static inline int UsefulOutBuf_AtStart(UsefulOutBuf *me) |
| { |
| return 0 == me->data_len; |
| } |
| |
| |
| /** |
| @brief Inserts bytes into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] NewData UsefulBuf with the bytes to insert |
| @param[in] uPos Index in output buffer at which to insert |
| |
| NewData is the pointer and length for the bytes to be added to the |
| output buffer. There must be room in the output buffer for all of |
| NewData or an error will occur. |
| |
| The insertion point must be between 0 and the current valid data. If |
| not an error will occur. Appending data to the output buffer is |
| achieved by inserting at the end of the valid data. This can be |
| retrieved by calling UsefulOutBuf_GetEndPosition(). |
| |
| When insertion is performed, the bytes between the insertion point and |
| the end of data previously added to the output buffer is slid to the |
| right to make room for the new data. |
| |
| Overlapping buffers are OK. NewData can point to data in the output |
| buffer. |
| |
| If an error occurs an error state is set in the UsefulOutBuf. No |
| error is returned. All subsequent attempts to add data will do |
| nothing. |
| |
| Call UsefulOutBuf_GetError() to find out if there is an error. This |
| is usually not needed until all additions of data are complete. |
| |
| */ |
| void UsefulOutBuf_InsertUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData, size_t uPos); |
| |
| |
| /** |
| @brief Insert a data buffer into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBul |
| @param[in] pBytes Pointer to the bytes to insert |
| @param[in] uLen Length of the bytes to insert |
| @param[in] uPos Index in output buffer at which to insert |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with |
| the difference being a pointer and length is passed in rather than an |
| UsefulBuf. |
| |
| */ |
| static inline void UsefulOutBuf_InsertData(UsefulOutBuf *me, const void *pBytes, size_t uLen, size_t uPos) |
| { |
| UsefulBufC Data = {pBytes, uLen}; |
| UsefulOutBuf_InsertUsefulBuf(me, Data, uPos); |
| } |
| |
| |
| /** |
| @brief Insert a NULL-terminated string into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] szString string to append |
| |
| */ |
| static inline void UsefulOutBuf_InsertString(UsefulOutBuf *me, const char *szString, size_t uPos) |
| { |
| UsefulOutBuf_InsertUsefulBuf(me, (UsefulBufC){szString, strlen(szString)}, uPos); |
| } |
| |
| |
| /** |
| @brief Insert a byte into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBul |
| @param[in] byte Bytes to insert |
| @param[in] uPos Index in output buffer at which to insert |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with |
| the difference being a single byte is to be inserted. |
| */ |
| static inline void UsefulOutBuf_InsertByte(UsefulOutBuf *me, uint8_t byte, size_t uPos) |
| { |
| UsefulOutBuf_InsertData(me, &byte, 1, uPos); |
| } |
| |
| |
| /** |
| @brief Insert a 16-bit integer into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBul |
| @param[in] uInteger16 Integer to insert |
| @param[in] uPos Index in output buffer at which to insert |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with |
| the difference being a single byte is to be inserted. |
| |
| The integer will be inserted in network byte order (big endian) |
| */ |
| static inline void UsefulOutBuf_InsertUint16(UsefulOutBuf *me, uint16_t uInteger16, size_t uPos) |
| { |
| // Converts native integer format to network byte order (big endian) |
| uint8_t tmp[2]; |
| tmp[0] = (uInteger16 & 0xff00) >> 8; |
| tmp[1] = (uInteger16 & 0xff); |
| UsefulOutBuf_InsertData(me, tmp, 2, uPos); |
| } |
| |
| |
| /** |
| @brief Insert a 32-bit integer into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBul |
| @param[in] uInteger32 Integer to insert |
| @param[in] uPos Index in output buffer at which to insert |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with |
| the difference being a single byte is to be inserted. |
| |
| The integer will be inserted in network byte order (big endian) |
| */ |
| static inline void UsefulOutBuf_InsertUint32(UsefulOutBuf *me, uint32_t uInteger32, size_t uPos) |
| { |
| // Converts native integer format to network byte order (big endian) |
| uint8_t tmp[4]; |
| tmp[0] = (uInteger32 & 0xff000000) >> 24; |
| tmp[1] = (uInteger32 & 0xff0000) >> 16; |
| tmp[2] = (uInteger32 & 0xff00) >> 8; |
| tmp[3] = (uInteger32 & 0xff); |
| UsefulOutBuf_InsertData(me, tmp, 4, uPos); |
| } |
| |
| |
| /** |
| @brief Insert a 64-bit integer into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBul |
| @param[in] uInteger64 Integer to insert |
| @param[in] uPos Index in output buffer at which to insert |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with |
| the difference being a single byte is to be inserted. |
| |
| The integer will be inserted in network byte order (big endian) |
| */ |
| static inline void UsefulOutBuf_InsertUint64(UsefulOutBuf *me, uint64_t uInteger64, size_t uPos) |
| { |
| // Converts native integer format to network byte order (big endian) |
| uint8_t tmp[8]; |
| tmp[0] = (uInteger64 & 0xff00000000000000) >> 56; |
| tmp[1] = (uInteger64 & 0xff000000000000) >> 48; |
| tmp[2] = (uInteger64 & 0xff0000000000) >> 40; |
| tmp[3] = (uInteger64 & 0xff00000000) >> 32; |
| tmp[4] = (uInteger64 & 0xff000000) >> 24; |
| tmp[5] = (uInteger64 & 0xff0000) >> 16; |
| tmp[6] = (uInteger64 & 0xff00) >> 8; |
| tmp[7] = (uInteger64 & 0xff); |
| UsefulOutBuf_InsertData(me, tmp, 8, uPos); |
| } |
| |
| |
| /** |
| @brief Insert a float into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBul |
| @param[in] f Integer to insert |
| @param[in] uPos Index in output buffer at which to insert |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with |
| the difference being a single byte is to be inserted. |
| |
| The float will be inserted in network byte order (big endian) |
| */ |
| static inline void UsefulOutBuf_InsertFloat(UsefulOutBuf *me, float f, size_t uPos) |
| { |
| UsefulOutBuf_InsertUint32(me, UsefulBufUtil_CopyFloatToUint32(f), uPos); |
| } |
| |
| |
| /** |
| @brief Insert a double into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBul |
| @param[in] d Integer to insert |
| @param[in] uPos Index in output buffer at which to insert |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This is the same with |
| the difference being a single byte is to be inserted. |
| |
| The double will be inserted in network byte order (big endian) |
| */ |
| static inline void UsefulOutBuf_InsertDouble(UsefulOutBuf *me, double d, size_t uPos) |
| { |
| UsefulOutBuf_InsertUint64(me, UsefulBufUtil_CopyDoubleToUint64(d), uPos); |
| } |
| |
| |
| |
| /** |
| Append a UsefulBuf into the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] NewData UsefulBuf with the bytes to append |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This does the same |
| with the insertion point at the end of the valid data. |
| |
| */ |
| static inline void UsefulOutBuf_AppendUsefulBuf(UsefulOutBuf *me, UsefulBufC NewData) |
| { |
| // An append is just a insert at the end |
| UsefulOutBuf_InsertUsefulBuf(me, NewData, UsefulOutBuf_GetEndPosition(me)); |
| } |
| |
| |
| /** |
| Append bytes to the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] pBytes Pointer to bytes to append |
| @param[in] uLen Index in output buffer at which to append |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This does the same |
| with the insertion point at the end of the valid data. |
| */ |
| |
| static inline void UsefulOutBuf_AppendData(UsefulOutBuf *me, const void *pBytes, size_t uLen) |
| { |
| UsefulBufC Data = {pBytes, uLen}; |
| UsefulOutBuf_AppendUsefulBuf(me, Data); |
| } |
| |
| |
| /** |
| Append a NULL-terminated string to the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] szString string to append |
| |
| */ |
| static inline void UsefulOutBuf_AppendString(UsefulOutBuf *me, const char *szString) |
| { |
| UsefulOutBuf_AppendUsefulBuf(me, (UsefulBufC){szString, strlen(szString)}); |
| } |
| |
| |
| /** |
| @brief Append a byte to the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] byte Bytes to append |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This does the same |
| with the insertion point at the end of the valid data. |
| */ |
| static inline void UsefulOutBuf_AppendByte(UsefulOutBuf *me, uint8_t byte) |
| { |
| UsefulOutBuf_AppendData(me, &byte, 1); |
| } |
| |
| /** |
| @brief Append an integer to the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] uInteger16 Integer to append |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This does the same |
| with the insertion point at the end of the valid data. |
| |
| The integer will be appended in network byte order (big endian). |
| */ |
| static inline void UsefulOutBuf_AppendUint16(UsefulOutBuf *me, uint16_t uInteger16){ |
| UsefulOutBuf_InsertUint16(me, uInteger16, UsefulOutBuf_GetEndPosition(me)); |
| } |
| |
| /** |
| @brief Append an integer to the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] uInteger32 Integer to append |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This does the same |
| with the insertion point at the end of the valid data. |
| |
| The integer will be appended in network byte order (big endian). |
| */ |
| static inline void UsefulOutBuf_AppendUint32(UsefulOutBuf *me, uint32_t uInteger32){ |
| UsefulOutBuf_InsertUint32(me, uInteger32, UsefulOutBuf_GetEndPosition(me)); |
| } |
| |
| /** |
| @brief Append an integer to the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] uInteger64 Integer to append |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This does the same |
| with the insertion point at the end of the valid data. |
| |
| The integer will be appended in network byte order (big endian). |
| */ |
| static inline void UsefulOutBuf_AppendUint64(UsefulOutBuf *me, uint64_t uInteger64){ |
| UsefulOutBuf_InsertUint64(me, uInteger64, UsefulOutBuf_GetEndPosition(me)); |
| } |
| |
| |
| /** |
| @brief Append a float to the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] f Float to append |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This does the same |
| with the insertion point at the end of the valid data. |
| |
| The float will be appended in network byte order (big endian). |
| */ |
| static inline void UsefulOutBuf_AppendFloat(UsefulOutBuf *me, float f){ |
| UsefulOutBuf_InsertFloat(me, f, UsefulOutBuf_GetEndPosition(me)); |
| } |
| |
| /** |
| @brief Append a float to the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] d Double to append |
| |
| See UsefulOutBuf_InsertUsefulBuf() for details. This does the same |
| with the insertion point at the end of the valid data. |
| |
| The double will be appended in network byte order (big endian). |
| */ |
| static inline void UsefulOutBuf_AppendDouble(UsefulOutBuf *me, double d){ |
| UsefulOutBuf_InsertDouble(me, d, UsefulOutBuf_GetEndPosition(me)); |
| } |
| |
| /** |
| @brief Returns the current error status |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| |
| @return 0 if all OK, 1 on error |
| |
| This is the error status since the call to either |
| UsefulOutBuf_Reset() of UsefulOutBuf_Init(). Once it goes into error |
| state it will stay until one of those functions is called. |
| |
| Possible error conditions are: |
| - bytes to be inserted will not fit |
| - insertion point is out of buffer or past valid data |
| - current position is off end of buffer (probably corruption or uninitialized) |
| - detect corruption / uninitialized by bad magic number |
| */ |
| |
| static inline int UsefulOutBuf_GetError(UsefulOutBuf *me) |
| { |
| return me->err; |
| } |
| |
| |
| /** |
| @brief Returns number of bytes unused used in the output buffer |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| |
| @return Number of unused bytes or zero |
| |
| Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf() |
| it is usually not necessary to use this. |
| */ |
| |
| static inline size_t UsefulOutBuf_RoomLeft(UsefulOutBuf *me) |
| { |
| return me->UB.len - me->data_len; |
| } |
| |
| |
| /** |
| @brief Returns true / false if some number of bytes will fit in the UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[in] uLen Number of bytes for which to check |
| |
| @return 1 or 0 if nLen bytes would fit |
| |
| Because of the error handling strategy and checks in UsefulOutBuf_InsertUsefulBuf() |
| it is usually not necessary to use this. |
| */ |
| |
| static inline int UsefulOutBuf_WillItFit(UsefulOutBuf *me, size_t uLen) |
| { |
| return uLen <= UsefulOutBuf_RoomLeft(me); |
| } |
| |
| |
| /** |
| @brief Returns the resulting valid data in a UsefulOutBuf |
| |
| @param[in] me Pointer to the UsefulOutBuf. |
| |
| @return The valid data in UsefulOutBuf. |
| |
| The storage for the returned data is Storage parameter passed |
| to UsefulOutBuf_Init(). See also UsefulOutBuf_CopyOut(). |
| |
| This can be called anytime and many times to get intermediate |
| results. It doesn't change the data or reset the current position |
| so you can keep adding data. |
| */ |
| |
| UsefulBufC UsefulOutBuf_OutUBuf(UsefulOutBuf *me); |
| |
| |
| /** |
| @brief Copies the valid data out into a supplied buffer |
| |
| @param[in] me Pointer to the UsefulOutBuf |
| @param[out] Dest The destination buffer to copy into |
| |
| @return Pointer and length of copied data. |
| |
| This is the same as UsefulOutBuf_OutUBuf() except it copies the data. |
| */ |
| |
| UsefulBufC UsefulOutBuf_CopyOut(UsefulOutBuf *me, UsefulBuf Dest); |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| |
| /** |
| UsefulInputBuf is the counterpart to UsefulOutBuf and is for parsing |
| data read or received. Initialize it with the data |
| from the network and its length. Then use the functions |
| here to get the various data types out of it. It maintains a position |
| for getting the next item. This means you don't have to track a |
| pointer as you get each object. UsefulInputBuf does that for you and |
| makes sure it never goes off the end of the buffer. The QCBOR |
| implementation parser makes use of this for all its pointer math and |
| length checking. |
| |
| UsefulInputBuf also maintains an internal error state so you do not have |
| to. Once data has been requested off the end of the buffer, it goes |
| into an error state. You can keep calling functions to get more data |
| but they will either return 0 or NULL. As long as you don't |
| dereference the NULL, you can wait until all data items have been |
| fetched before checking for the error and this can simplify your |
| code. |
| |
| The integer and float parsing expects network byte order (big endian). |
| Network byte order is what is used by TCP/IP, CBOR and most internet |
| protocols. |
| |
| Lots of inlining is used to keep code size down. The code optimizer, |
| particularly with the -Os, also reduces code size a lot. The only |
| non-inline code is UsefulInputBuf_GetBytes() which is less than 100 |
| bytes so use of UsefulInputBuf doesn't add much code for all the messy |
| hard-to-get right issues with parsing in C that is solves. |
| |
| The parse context size is: |
| 64-bit machine: 16 + 8 + 2 + 1 (5 bytes padding to align) = 32 bytes |
| 32-bit machine: 8 + 4 + 2 + 1 (1 byte padding to align) = 16 bytes |
| |
| */ |
| |
| #define UIB_MAGIC (0xB00F) |
| |
| typedef struct { |
| // Private data structure |
| UsefulBufC UB; |
| size_t cursor; |
| uint16_t magic; |
| uint8_t err; // set if off end of buffer; also can set if this structure is corrupt or inconsistent. |
| } UsefulInputBuf; |
| |
| |
| |
| /** |
| @brief Initialize the UsefulInputBuf structure before use. |
| |
| @param[in] me Pointer to the UsefulInputBuf instance. |
| @param[in] UB Pointer to the data to parse. |
| |
| */ |
| static inline void UsefulInputBuf_Init(UsefulInputBuf *me, UsefulBufC UB) |
| { |
| me->cursor = 0; |
| me->err = 0; |
| me->magic = UIB_MAGIC; |
| me->UB = UB; |
| } |
| |
| |
| /** |
| @brief Returns current position in input buffer |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return Integer position of the cursor |
| |
| The position that the next bytes will be returned from. |
| |
| */ |
| static inline size_t UsefulInputBuf_Tell(UsefulInputBuf *me) |
| { |
| return me->cursor; |
| } |
| |
| |
| /** |
| @brief Sets current position in input buffer |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| @param[in] uPos Position to set to |
| |
| If the position is off the end of the input buffer, the error state |
| is entered and all functions will do nothing. |
| |
| Seeking to a valid position in the buffer will not reset the error |
| state. Only re initialization will do that. |
| |
| */ |
| static inline void UsefulInputBuf_Seek(UsefulInputBuf *me, size_t uPos) |
| { |
| if(uPos > me->UB.len) { |
| me->err = 1; |
| } else { |
| me->cursor = uPos; |
| } |
| } |
| |
| |
| /** |
| @brief Returns the number of bytes from the cursor to the end of the buffer, |
| the uncomsummed bytes. |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return number of bytes unconsumed or 0 on error. |
| |
| This is a critical function for input length validation. This does |
| some pointer / offset math. |
| |
| Returns 0 if the cursor it invalid or corruption of the structure is |
| detected. |
| |
| Code Reviewers: THIS FUNCTION DOES POINTER MATH |
| */ |
| static inline size_t UsefulInputBuf_BytesUnconsumed(UsefulInputBuf *me) |
| { |
| // Magic number is messed up. Either the structure got overwritten |
| // or was never initialized. |
| if(me->magic != UIB_MAGIC) { |
| return 0; |
| } |
| |
| // The cursor is off the end of the input buffer given |
| // Presuming there are no bugs in this code, this should never happen. |
| // If it so, the struct was corrupted. The check is retained as |
| // as a defense in case there is a bug in this code or the struct is corrupted. |
| if(me->cursor > me->UB.len) { |
| return 0; |
| } |
| |
| // subtraction can't go neative because of check above |
| return me->UB.len - me->cursor; |
| } |
| |
| |
| /** |
| @brief Check if there are any unconsumed bytes |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return 1 if len bytes are available after the cursor, and 0 if not |
| |
| */ |
| static inline int UsefulInputBuf_BytesAvailable(UsefulInputBuf *me, size_t uLen) |
| { |
| return UsefulInputBuf_BytesUnconsumed(me) >= uLen ? 1 : 0; |
| } |
| |
| |
| /** |
| @brief Get pointer to bytes out of the input buffer |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| @param[in] uNum Number of bytes to get |
| |
| @return Pointer to bytes. |
| |
| This consumes n bytes from the input buffer. It returns a pointer to |
| the start of the n bytes. |
| |
| If there are not n bytes in the input buffer, NULL will be returned |
| and an error will be set. |
| |
| It advances the current position by n bytes. |
| */ |
| const void * UsefulInputBuf_GetBytes(UsefulInputBuf *me, size_t uNum); |
| |
| |
| /** |
| @brief Get UsefulBuf out of the input buffer |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| @param[in] uNum Number of bytes to get |
| |
| @return UsefulBufC with ptr and length for bytes consumed. |
| |
| This consumes n bytes from the input buffer and returns the pointer |
| and len to them as a UsefulBufC. The len returned will always be n. |
| |
| If there are not n bytes in the input buffer, UsefulBufC.ptr will be |
| NULL and UsefulBufC.len will be 0. An error will be set. |
| |
| It advances the current position by n bytes. |
| */ |
| static inline UsefulBufC UsefulInputBuf_GetUsefulBuf(UsefulInputBuf *me, size_t uNum) |
| { |
| const void *pResult = UsefulInputBuf_GetBytes(me, uNum); |
| if(!pResult) { |
| return NULLUsefulBufC; |
| } else { |
| return (UsefulBufC){pResult, uNum}; |
| } |
| } |
| |
| |
| /** |
| @brief Get a byte out of the input buffer. |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return The byte |
| |
| This consumes 1 byte from the input buffer. It returns the byte. |
| |
| If there is not 1 byte in the buffer, 0 will be returned for the byte |
| and an error set internally. You must check the error at some point |
| to know whether the 0 was the real value or just returned in error, |
| but you may not have to do that right away. Check the error state |
| with UsefulInputBuf_GetError(). You can also know you are in the |
| error state if UsefulInputBuf_GetBytes() returns NULL or the ptr from |
| UsefulInputBuf_GetUsefulBuf() is NULL. |
| |
| It advances the current position by 1 byte. |
| */ |
| static inline uint8_t UsefulInputBuf_GetByte(UsefulInputBuf *me) |
| { |
| const void *pResult = UsefulInputBuf_GetBytes(me, sizeof(uint8_t)); |
| |
| return pResult ? *(uint8_t *)pResult : 0; |
| } |
| |
| |
| /** |
| @brief Get a uint16_t out of the input buffer |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return The uint16_t |
| |
| See UsefulInputBuf_GetByte(). This works the same, except it returns |
| a uint16_t and two bytes are consumed. |
| |
| The input bytes must be in network order (big endian). |
| */ |
| static inline uint16_t UsefulInputBuf_GetUint16(UsefulInputBuf *me) |
| { |
| const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint16_t)); |
| |
| if(!pResult) { |
| return 0; |
| } |
| |
| return ((uint16_t)pResult[0] << 8) + (uint16_t)pResult[1]; |
| } |
| |
| |
| /** |
| @brief Get a uint32_t out of the input buffer |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return The uint32_t |
| |
| See UsefulInputBuf_GetByte(). This works the same, except it returns |
| a uint32_t and four bytes are consumed. |
| |
| The input bytes must be in network order (big endian). |
| */ |
| static inline uint32_t UsefulInputBuf_GetUint32(UsefulInputBuf *me) |
| { |
| const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint32_t)); |
| |
| if(!pResult) { |
| return 0; |
| } |
| |
| return ((uint32_t)pResult[0]<<24) + ((uint32_t)pResult[1]<<16) + ((uint32_t)pResult[2]<<8) + (uint32_t)pResult[3]; |
| } |
| |
| |
| /** |
| @brief Get a uint64_t out of the input buffer |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return The uint64_t |
| |
| See UsefulInputBuf_GetByte(). This works the same, except it returns |
| a uint64_t and eight bytes are consumed. |
| |
| The input bytes must be in network order (big endian). |
| */ |
| static inline uint64_t UsefulInputBuf_GetUint64(UsefulInputBuf *me) |
| { |
| const uint8_t *pResult = (const uint8_t *)UsefulInputBuf_GetBytes(me, sizeof(uint64_t)); |
| |
| if(!pResult) { |
| return 0; |
| } |
| |
| return ((uint64_t)pResult[0]<<56) + |
| ((uint64_t)pResult[1]<<48) + |
| ((uint64_t)pResult[2]<<40) + |
| ((uint64_t)pResult[3]<<32) + |
| ((uint64_t)pResult[4]<<24) + |
| ((uint64_t)pResult[5]<<16) + |
| ((uint64_t)pResult[6]<<8) + |
| (uint64_t)pResult[7]; |
| } |
| |
| |
| /** |
| @brief Get a float out of the input buffer |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return The float |
| |
| See UsefulInputBuf_GetByte(). This works the same, except it returns |
| a float and four bytes are consumed. |
| |
| The input bytes must be in network order (big endian). |
| */ |
| static inline float UsefulInputBuf_GetFloat(UsefulInputBuf *me) |
| { |
| uint32_t uResult = UsefulInputBuf_GetUint32(me); |
| |
| return uResult ? UsefulBufUtil_CopyUint32ToFloat(uResult) : 0; |
| } |
| |
| /** |
| @brief Get a double out of the input buffer |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return The double |
| |
| See UsefulInputBuf_GetByte(). This works the same, except it returns |
| a double and eight bytes are consumed. |
| |
| The input bytes must be in network order (big endian). |
| */ |
| static inline double UsefulInputBuf_GetDouble(UsefulInputBuf *me) |
| { |
| uint64_t uResult = UsefulInputBuf_GetUint64(me); |
| |
| return uResult ? UsefulBufUtil_CopyUint64ToDouble(uResult) : 0; |
| } |
| |
| |
| /** |
| @brief Get the error status |
| |
| @param[in] me Pointer to the UsefulInputBuf. |
| |
| @return The error. |
| |
| Zero is success, non-zero is error. Once in the error state, the only |
| way to clear it is to call Init again. |
| |
| You may be able to only check the error state at the end after all |
| the Get()'s have been done, but if what you get later depends on what |
| you get sooner you cannot. For example if you get a length or count |
| of following items you will have to check the error. |
| |
| */ |
| static inline int UsefulInputBuf_GetError(UsefulInputBuf *me) |
| { |
| return me->err; |
| } |
| |
| |
| #endif // _UsefulBuf_h |
| |
| |