diff options
Diffstat (limited to 'src/BufBound.c')
-rw-r--r-- | src/BufBound.c | 225 |
1 files changed, 225 insertions, 0 deletions
diff --git a/src/BufBound.c b/src/BufBound.c new file mode 100644 index 0000000..e9e64e3 --- /dev/null +++ b/src/BufBound.c @@ -0,0 +1,225 @@ +/* + * Copyright (c) 2019, The Linux Foundation. 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 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: AEEBufBound.c + +SERVICES: + AEEBufBound APIs + +GENERAL DESCRIPTION: + AEEBufBound provides a "bounded buffer" API that facilitates + measuring strings or character output. It's design accomodates + the implementation of functions that can have the same exact logic + for measuring and outputting char buffer content. + +REVISION HISTORY: + Sun Mar 06 11:23:10 2005 Created + +==============================================================================*/ +#include <limits.h> +#include "AEEBufBound.h" +#include "AEEstd.h" + +// Note on bounds-checking logic and saturation: +// +// Simple pointer comparisons are not adequate for bounds checking. pcBuf +// and pcEnd are assumed to be valid pointers in the address space. But +// pcWrite is not ... it is a theoretical value that can exceed pcEnd, and +// may in fact wrap around the end of the address space. In that case the +// test for (pcWrite < pcEnd) will yield TRUE, although pcWrite is outside +// the buffer. Use (pcEnd-pcWrite) > 0 to be accurate. +// +// In order to ensure this works in all cases, we need to avoid integer +// overflows. We do this by restricting pcWrite to the range +// [pcBuf..pcBuf+INT_MAX]. The ensures that pcWrite-pcBuf and pcWrite-pcBuf +// will always be valid integers. It also allows us to ensure that +// BufBound_Wrote() will not return wildly misleading results. +// +// PCSAT +// pcBuf pcEnd pcBuf+MAXINT +// |-------------------| . . . . . . . . . | +// ^ ^ +// pcWrite: (a) (b) +// + +#define PCSAT(me) ((me)->pcBuf + INT_MAX) + + +// Advance me->pcWrite, saturating. +// +// On entry: +// *pnLen = number of bytes to be written (non-negative) +// On exit: +// return value = where to write (pointer into the buffer) +// *pnLen = number of bytes to write +// +static char * +BufBound_ValidateWrite(BufBound *me, int *pnLen) +{ + int nLen = *pnLen; + char *pcWrite = me->pcWrite; + int nMaxCopy = me->pcEnd - pcWrite; // could be negative! + + if ( nMaxCopy < nLen ) { + // Must check PCSAT to validate advance + int nMaxAdvance = PCSAT(me) - pcWrite; // max amount to advance + + if (nLen > nMaxAdvance) { + nLen = nMaxAdvance; + } + if (nMaxCopy < 0) { + nMaxCopy = 0; + } + } else { + // Simple case: all fits in the buffer + nMaxCopy = nLen; + } + + *pnLen = nMaxCopy; + me->pcWrite = pcWrite + nLen; + return pcWrite; +} + +void BufBound_Write(BufBound *me, const char *pc, int nLen) +{ + if (nLen > 0) { + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + while (--nLen >= 0) { + pcDest[nLen] = pc[nLen]; + } + } +} + +void BufBound_Putnc(BufBound *me, char c, int nLen) +{ + if (nLen > 0) { + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + while (--nLen >= 0) { + pcDest[nLen] = c; + } + } +} + +void BufBound_Advance(BufBound *me, int nLen) +{ + uint32 uOffset = (uint32)((me->pcWrite - me->pcBuf) + nLen); + + if (uOffset > INT_MAX) { + uOffset = INT_MAX; + if (nLen < 0) { + uOffset = 0; + } + } + me->pcWrite = me->pcBuf + uOffset; +} + +void BufBound_Init(BufBound *me, char *pBuf, int nLen) +{ + if (nLen < 0) { + nLen = 0; + } + me->pcWrite = me->pcBuf = pBuf; + me->pcEnd = pBuf + nLen; +} + +void BufBound_Putc(BufBound *me, char c) +{ + if ( (me->pcEnd - me->pcWrite) > 0) { + *me->pcWrite++ = c; + } else if (me->pcWrite != PCSAT(me)) { + ++me->pcWrite; + } +} + +void BufBound_ForceNullTerm(BufBound *me) +{ + if ( (me->pcEnd - me->pcWrite) > 0) { + *me->pcWrite++ = '\0'; + } else { + if (me->pcWrite != PCSAT(me)) { + ++me->pcWrite; + } + // ensure null termination if non-empty buffer + if (me->pcEnd != me->pcBuf) { + me->pcEnd[-1] = '\0'; + } + } +} + +void BufBound_Puts(BufBound *me, const char* cpsz) +{ + BufBound_Write(me, cpsz, std_strlen(cpsz)); +} + +int BufBound_BufSize(BufBound* me) +{ + return me->pcEnd - me->pcBuf; +} + +int BufBound_Left(BufBound* me) +{ + return (me->pcEnd - me->pcWrite); +} + +int BufBound_ReallyWrote(BufBound* me) +{ + return STD_MIN(me->pcEnd - me->pcBuf, me->pcWrite - me->pcBuf); +} + +int BufBound_Wrote(BufBound* me) +{ + return (me->pcWrite - me->pcBuf); +} + +void BufBound_WriteLE(BufBound *me, + const void *pvSrc, int nSrcSize, + const char *pszFields) +{ + if (nSrcSize > 0) { + int nLen = nSrcSize; + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + (void)std_CopyLE(pcDest, nLen, pvSrc, nSrcSize, pszFields); + } +} + +void BufBound_WriteBE(BufBound *me, + const void *pvSrc, int nSrcSize, + const char *pszFields) +{ + if (nSrcSize > 0) { + int nLen = nSrcSize; + char *pcDest = BufBound_ValidateWrite(me, &nLen); + + (void)std_CopyBE(pcDest, nLen, pvSrc, nSrcSize, pszFields); + } +} |