diff options
-rw-r--r-- | generic/tclBinary.c | 68 | ||||
-rw-r--r-- | tests/binary.test | 3 |
2 files changed, 46 insertions, 25 deletions
diff --git a/generic/tclBinary.c b/generic/tclBinary.c index ce816d9..6802f99 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -2665,6 +2665,7 @@ BinaryDecodeHex( Tcl_SetObjResult(interp, Tcl_ObjPrintf( "invalid hexadecimal digit \"%c\" at position %d", c, (int) (data - datastart - 1))); + Tcl_SetErrorCode(interp, "TCL", "BINARY", "DECODE", "INVALID", NULL); return TCL_ERROR; } @@ -2673,16 +2674,10 @@ BinaryDecodeHex( * * BinaryEncode64 -- * - * This implements a generic 6 bit binary encoding. Input is broken into - * 6 bit chunks and a lookup table passed in via clientData is used to - * turn these values into output characters. This is used to implement - * base64 binary encodings. + * This procedure implements the "binary encode base64" Tcl command. * * Results: - * Interp result set to an encoded byte array object - * - * Side effects: - * None + * The base64 encoded value prescribed by the input arguments. * *---------------------------------------------------------------------- */ @@ -2711,11 +2706,11 @@ BinaryEncode64( Tcl_Obj *const objv[]) { Tcl_Obj *resultObj; - unsigned char *data, *cursor, *limit; + unsigned char *data, *limit; int maxlen = 0; const char *wrapchar = "\n"; int wrapcharlen = 1; - int offset, i, index, size, outindex = 0, count = 0; + int offset, i, index, size, outindex = 0, count = 0, purewrap = 1; enum { OPT_MAXLEN, OPT_WRAPCHAR }; static const char *const optStrings[] = { "-maxlen", "-wrapchar", NULL }; @@ -2743,17 +2738,24 @@ BinaryEncode64( } break; case OPT_WRAPCHAR: - wrapchar = TclGetStringFromObj(objv[i + 1], &wrapcharlen); - if (wrapcharlen == 0) { - maxlen = 0; + wrapchar = (const char *)TclGetBytesFromObj(NULL, + objv[i + 1], &wrapcharlen); + if (wrapchar == NULL) { + purewrap = 0; + wrapchar = TclGetStringFromObj(objv[i + 1], &wrapcharlen); } break; } } + if (wrapcharlen == 0) { + maxlen = 0; + } resultObj = Tcl_NewObj(); data = Tcl_GetByteArrayFromObj(objv[objc - 1], &count); if (count > 0) { + unsigned char *cursor = NULL; + size = (((count * 4) / 3) + 3) & ~3; /* ensure 4 byte chunks */ if (maxlen > 0 && size > maxlen) { int adjusted = size + (wrapcharlen * (size / maxlen)); @@ -2762,8 +2764,17 @@ BinaryEncode64( adjusted -= wrapcharlen; } size = adjusted; + + if (purewrap == 0) { + /* Wrapchar is (possibly) non-byte, so build result as + * general string, not bytearray */ + Tcl_SetObjLength(resultObj, size); + cursor = (unsigned char *) TclGetString(resultObj); + } + } + if (cursor == NULL) { + cursor = Tcl_SetByteArrayLength(resultObj, size); } - cursor = Tcl_SetByteArrayLength(resultObj, size); limit = cursor + size; for (offset = 0; offset < count; offset += 3) { unsigned char d[3] = {0, 0, 0}; @@ -3100,8 +3111,9 @@ BinaryDecode64( unsigned char *data, *datastart, *dataend, c = '\0'; unsigned char *begin = NULL; unsigned char *cursor = NULL; - int strict = 0; + int pure = 1, strict = 0; int i, index, size, cut = 0, count = 0; + Tcl_UniChar ch; enum { OPT_STRICT }; static const char *const optStrings[] = { "-strict", NULL }; @@ -3122,8 +3134,12 @@ BinaryDecode64( } TclNewObj(resultObj); - datastart = data = (unsigned char *) - TclGetStringFromObj(objv[objc - 1], &count); + data = TclGetBytesFromObj(NULL, objv[objc - 1], &count); + if (data == NULL) { + pure = 0; + data = (unsigned char *) TclGetStringFromObj(objv[objc - 1], &count); + } + datastart = data; dataend = data + count; size = ((count + 3) & ~3) * 3 / 4; begin = cursor = Tcl_SetByteArrayLength(resultObj, size); @@ -3224,21 +3240,23 @@ BinaryDecode64( return TCL_OK; bad64: - { + if (pure) { + ch = c; + } else { /* The decoder is byte-oriented. If we saw a byte that's not a * valid member of the base64 alphabet, it could be the lead byte * of a multi-byte character. */ - Tcl_UniChar ch; /* Safe because we know data is NUL-terminated */ TclUtfToUniChar((const char *)(data - 1), &ch); - - Tcl_SetObjResult(interp, Tcl_ObjPrintf( - "invalid base64 character \"%c\" at position %d", ch, - (int) (data - datastart - 1))); - TclDecrRefCount(resultObj); - return TCL_ERROR; } + + Tcl_SetObjResult(interp, Tcl_ObjPrintf( + "invalid base64 character \"%c\" at position %d", ch, + (int) (data - datastart - 1))); + Tcl_SetErrorCode(interp, "TCL", "BINARY", "DECODE", "INVALID", NULL); + TclDecrRefCount(resultObj); + return TCL_ERROR; } /* diff --git a/tests/binary.test b/tests/binary.test index ae94ab4..915f170 100644 --- a/tests/binary.test +++ b/tests/binary.test @@ -2633,6 +2633,9 @@ test binary-72.27 {binary encode base64} -body { test binary-72.28 {binary encode base64} -body { binary encode base64 -maxlen 6 -wrapchar 0123456789 abcabcabc } -result {YWJjYW0123456789JjYWJj} +test binary-72.29 {binary encode base64} { + string length [binary encode base64 -maxlen 3 -wrapchar \xca abc] +} 5 test binary-73.1 {binary decode base64} -body { binary decode base64 |