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: * [Alexandre Ferrieux]: '''Tcl_NewObj'''() may be replaced by '''Tcl_NewByteArrayObj'''( "", 1 ). * [DGP]: If the object is not newly created (for example a parameter object is modified, one should check the object to be shared: ====== 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... ---- !!!!!! %| [Category Tcl Library] |% !!!!!!