summaryrefslogtreecommitdiffstats
path: root/generic
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
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')
-rw-r--r--generic/tclBinary.c92
-rw-r--r--generic/tclIO.c17
-rw-r--r--generic/tclInt.h2
3 files changed, 98 insertions, 13 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.
diff --git a/generic/tclIO.c b/generic/tclIO.c
index f1d8909..c1b7ee9 100644
--- a/generic/tclIO.c
+++ b/generic/tclIO.c
@@ -5586,20 +5586,8 @@ ReadBytes(
toRead = srcLen;
}
+ TclAppendBytesToByteArray(objPtr, NULL, toRead);
dst = (char *) Tcl_GetByteArrayFromObj(objPtr, &length);
- if (toRead > length - offset - 1) {
- /*
- * Double the existing size of the object or make enough room to hold
- * all the characters we may get from the source buffer, whichever is
- * larger.
- */
-
- length = offset * 2;
- if (offset < toRead) {
- length = offset + toRead + 1;
- }
- dst = (char *) Tcl_SetByteArrayLength(objPtr, length);
- }
dst += offset;
if (statePtr->flags & INPUT_NEED_NL) {
@@ -5607,6 +5595,7 @@ ReadBytes(
if ((srcLen == 0) || (*src != '\n')) {
*dst = '\r';
*offsetPtr += 1;
+ Tcl_SetByteArrayLength(objPtr, *offsetPtr);
return 1;
}
*dst++ = '\n';
@@ -5619,11 +5608,13 @@ ReadBytes(
dstWrote = toRead;
if (TranslateInputEOL(statePtr, dst, src, &dstWrote, &srcRead) != 0) {
if (dstWrote == 0) {
+ Tcl_SetByteArrayLength(objPtr, *offsetPtr);
return -1;
}
}
bufPtr->nextRemoved += srcRead;
*offsetPtr += dstWrote;
+ Tcl_SetByteArrayLength(objPtr, *offsetPtr);
return dstWrote;
}
diff --git a/generic/tclInt.h b/generic/tclInt.h
index dc28b97..64d39a0 100644
--- a/generic/tclInt.h
+++ b/generic/tclInt.h
@@ -2477,6 +2477,8 @@ MODULE_SCOPE char tclEmptyString;
*----------------------------------------------------------------
*/
+MODULE_SCOPE void TclAppendBytesToByteArray(Tcl_Obj *objPtr,
+ const unsigned char *bytes, int len);
MODULE_SCOPE void TclAdvanceContinuations(int* line, int** next, int loc);
MODULE_SCOPE void TclAdvanceLines(int *line, const char *start,
const char *end);