summaryrefslogtreecommitdiff
path: root/src/lib/BufBound.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib/BufBound.c')
-rw-r--r--src/lib/BufBound.c228
1 files changed, 228 insertions, 0 deletions
diff --git a/src/lib/BufBound.c b/src/lib/BufBound.c
new file mode 100644
index 0000000..ab85e86
--- /dev/null
+++ b/src/lib/BufBound.c
@@ -0,0 +1,228 @@
+/*
+* Copyright (c) 2017, The Linux Foundation. All rights reserved.
+* All rights reserved.
+*
+* Redistribution and use in source and binary forms, with or without
+* modification, are permitted provided that the following conditions are met:
+*
+* 1. Redistributions of source code must retain the above copyright notice,
+* this list of conditions and the following disclaimer.
+*
+* 2. 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.
+*
+* 3. Neither the name of the copyright holder 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 BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+* ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+* LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+* CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+* POSSIBILITY OF SUCH DAMAGE.
+*/
+#include <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);
+ }
+}
+