summaryrefslogtreecommitdiff
path: root/src/BufBound.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/BufBound.c')
-rw-r--r--src/BufBound.c225
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);
+ }
+}