Tcl_Obj * Tcl_NewByteArrayObj(CONST unsigned char *bytes, int length)
Tcl_Obj * Tcl_NewByteArrayObj(bytes, length)
Tcl_NewByteArrayObj will create a new object of byte-array type. Both of these procedures set the object's type to be byte-array and set the object's internal representation to a copy of the array of bytes given by bytes. Tcl_NewByteArrayObj returns a pointer to a newly allocated object with a reference count of zero.
http://www.tcl.tk/man/tcl8.5/TclLib/ByteArrObj.htm
HaO: To populate a byte array by a C extension and return it as the result object, the following code might be used:
Tcl_Obj *pObj = Tcl_NewObj(); unsigned char *pChar = Tcl_SetByteArrayLength(pObj, 3); // Dummy population functionality pChar[0] = '\1'; pChar[1] = '\xff'; pChar[2] = '\x80'; Tcl_InvalidateStringRep(pObj); Tcl_SetObjResult(interp,pObj);
Remarks:
if ( Tcl_IsShared(pObj) ) pObj = Tcl_DuplicateObj(pObj);
DKF: I don't recommend using a length of 0 to Tcl_NewByteArrayObj; the behaviour of that depends on whether malloc(0) keels over (which is system dependent).
Duoas That seems me fairly obnoxious. Doesn't the Tcl_NewByteArrayObj() code know that it oughtn't bother to try allocating zero bytes, and just initialize an empty/nil internal representation to begin with? [edit2] For that matter, would it be reasonable to specify NULL for source and a non-zero length for an uninitialized block of bytes?
DKF: I merely report the current state of affairs.
Duoas :-D Perhaps I'll get the latest CVS and fix that sometime in the next couple of days.
Duoas 2008-10-31 Well, I've looked at the source (~/tcl/generic/tclBinary.c) and this is what I've found.
The documentation plainly states that 'length' must be greater than or equal to zero. Assuming no one ever passes a negative number, none of the functions will break. Zero is fine --malloc() will not get a zero size_t for a zero-length byte array, so it is malloc()-safe (remembering again not to give it negative values).
Frankly, I think I would insert a line above 327 that forces 'length' to be >= 0.
As for a NULL 'bytes' argument, if 'length' is zero, there is no problem. However, if 'length' is non-zero, then you will almost surely cause a segfault/access violation. Again, I would insert a little line above 330:331 just for that:
void Tcl_SetByteArrayObj( Tcl_Obj *objPtr, /* Object to initialize as a ByteArray. */ const unsigned char *bytes, /* The array of bytes to use as the new * value. */ int length) /* Length of the array of bytes, which must be * >= 0. */ { ByteArray *byteArrayPtr; if (Tcl_IsShared(objPtr)) { Tcl_Panic("%s called with shared object", "Tcl_SetByteArrayObj"); } TclFreeIntRep(objPtr); Tcl_InvalidateStringRep(objPtr); length = (length < 0) ? 0 : length; byteArrayPtr = (ByteArray *) ckalloc(BYTEARRAY_SIZE(length)); byteArrayPtr->used = length; byteArrayPtr->allocated = length; if (bytes && length) { memcpy(byteArrayPtr->bytes, bytes, (size_t) length); } objPtr->typePtr = &tclByteArrayType; SET_BYTEARRAY(objPtr, byteArrayPtr); }
These two simple changes make the routine idiot-proof --er-- error-proof, and improve the functionality to allow creating a new ByteArray object with an uninitialized 'length' of bytes:
Tcl_Obj *myByteArray = Tcl_NewByteArray( NULL, 1024 ); unsigned char *my1024 = Tcl_GetByteArrayFromObj( myByteArray, NULL );
Finally, I would have Tcl_GetByteArrayFromObj() return NULL if the ByteArray is zero-length.
unsigned char * Tcl_GetByteArrayFromObj( Tcl_Obj *objPtr, /* The ByteArray object. */ int *lengthPtr) /* If non-NULL, filled with length of the * array of bytes in the ByteArray object. */ { ByteArray *baPtr; if (objPtr->typePtr != &tclByteArrayType) { SetByteArrayFromAny(NULL, objPtr); } baPtr = GET_BYTEARRAY(objPtr); if (lengthPtr != NULL) { *lengthPtr = baPtr->used; } if (!baPtr->bytes) { return NULL; } return (unsigned char *) baPtr->bytes; }
But this is not essential... assuming the user is smart enough to actually verify that there is data before reading/writing it.
If you wan't I'll actually submit a patch, but as this only requires adding six lines...