summaryrefslogtreecommitdiffstats
path: root/generic/tclBinary.c
diff options
context:
space:
mode:
authordgp <dgp@users.sourceforge.net>2014-01-21 21:32:53 (GMT)
committerdgp <dgp@users.sourceforge.net>2014-01-21 21:32:53 (GMT)
commit7460f22cc7e783b1dd480c2fbf8ef6fc90a0360c (patch)
tree16aac5fe7598b853efad37646f8665979dc074b0 /generic/tclBinary.c
parentc7ed456462861ff7aaef003c61d8fc526466017d (diff)
downloadtcl-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.c92
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.