diff options
author | dgp <dgp@users.sourceforge.net> | 2014-01-21 21:32:53 (GMT) |
---|---|---|
committer | dgp <dgp@users.sourceforge.net> | 2014-01-21 21:32:53 (GMT) |
commit | 7460f22cc7e783b1dd480c2fbf8ef6fc90a0360c (patch) | |
tree | 16aac5fe7598b853efad37646f8665979dc074b0 /generic/tclBinary.c | |
parent | c7ed456462861ff7aaef003c61d8fc526466017d (diff) | |
download | tcl-7460f22cc7e783b1dd480c2fbf8ef6fc90a0360c.zip tcl-7460f22cc7e783b1dd480c2fbf8ef6fc90a0360c.tar.gz tcl-7460f22cc7e783b1dd480c2fbf8ef6fc90a0360c.tar.bz2 |
Backport of bytearray append machinery to support bug fixes in ReadBytes.
Diffstat (limited to 'generic/tclBinary.c')
-rw-r--r-- | generic/tclBinary.c | 92 |
1 files changed, 92 insertions, 0 deletions
diff --git a/generic/tclBinary.c b/generic/tclBinary.c index dbb296b..68289f2 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -549,6 +549,98 @@ UpdateStringOfByteArray( /* *---------------------------------------------------------------------- * + * TclAppendBytesToByteArray -- + * + * This function appends an array of bytes to a byte array object. Note + * that the object *must* be unshared, and the array of bytes *must not* + * refer to the object being appended to. + * + * Results: + * None. + * + * Side effects: + * Allocates enough memory for an array of bytes of the requested total + * size, or possibly larger. [Bug 2992970] + * + *---------------------------------------------------------------------- + */ + +#define TCL_MIN_GROWTH 1024 +void +TclAppendBytesToByteArray( + Tcl_Obj *objPtr, + const unsigned char *bytes, + int len) +{ + ByteArray *byteArrayPtr; + int needed; + + if (Tcl_IsShared(objPtr)) { + Tcl_Panic("%s called with shared object","TclAppendBytesToByteArray"); + } + if (len < 0) { + Tcl_Panic("%s must be called with definite number of bytes to append", + "TclAppendBytesToByteArray"); + } + if (len == 0) { + /* Append zero bytes is a no-op. */ + return; + } + if (objPtr->typePtr != &tclByteArrayType) { + SetByteArrayFromAny(NULL, objPtr); + } + byteArrayPtr = GET_BYTEARRAY(objPtr); + + if (len > INT_MAX - byteArrayPtr->used) { + Tcl_Panic("max size for a Tcl value (%d bytes) exceeded", INT_MAX); + } + + needed = byteArrayPtr->used + len; + /* + * If we need to, resize the allocated space in the byte array. + */ + + if (needed > byteArrayPtr->allocated) { + ByteArray *ptr = NULL; + int attempt; + + if (needed <= INT_MAX/2) { + /* Try to allocate double the total space that is needed. */ + attempt = 2 * needed; + ptr = (ByteArray *) attemptckrealloc((void *) byteArrayPtr, + BYTEARRAY_SIZE(attempt)); + } + if (ptr == NULL) { + /* Try to allocate double the increment that is needed (plus). */ + unsigned int limit = INT_MAX - needed; + unsigned int extra = len + TCL_MIN_GROWTH; + int growth = (int) ((extra > limit) ? limit : extra); + + attempt = needed + growth; + ptr = (ByteArray *) attemptckrealloc((void *) byteArrayPtr, + BYTEARRAY_SIZE(attempt)); + } + if (ptr == NULL) { + /* Last chance: Try to allocate exactly what is needed. */ + attempt = needed; + ptr = (ByteArray *) ckrealloc((void *)byteArrayPtr, + BYTEARRAY_SIZE(attempt)); + } + byteArrayPtr = ptr; + byteArrayPtr->allocated = attempt; + SET_BYTEARRAY(objPtr, byteArrayPtr); + } + + if (bytes) { + memcpy(byteArrayPtr->bytes + byteArrayPtr->used, bytes, len); + } + byteArrayPtr->used += len; + TclInvalidateStringRep(objPtr); +} + +/* + *---------------------------------------------------------------------- + * * Tcl_BinaryObjCmd -- * * This procedure implements the "binary" Tcl command. |