summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--generic/tclBinary.c68
-rw-r--r--tests/binary.test3
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