diff options
-rw-r--r-- | generic/tclBinary.c | 301 |
1 files changed, 158 insertions, 143 deletions
diff --git a/generic/tclBinary.c b/generic/tclBinary.c index 246c371..831a427 100644 --- a/generic/tclBinary.c +++ b/generic/tclBinary.c @@ -159,93 +159,88 @@ static const EnsembleImplMap decodeMap[] = { }; /* - * The following object types represent an array of bytes. The intent is - * to allow arbitrary binary data to pass through Tcl as a Tcl value - * without loss or damage. Such values are useful for things like - * encoded strings or Tk images to name just two. - * - * It's strange to have two Tcl_ObjTypes in place for this task when - * one would do, so a bit of detail and history how we got to this point - * and where we might go from here. - * - * A bytearray is an ordered sequence of bytes. Each byte is an integer - * value in the range [0-255]. To be a Tcl value type, we need a way to - * encode each value in the value set as a Tcl string. The simplest - * encoding is to represent each byte value as the same codepoint value. - * A bytearray of N bytes is encoded into a Tcl string of N characters - * where the codepoint of each character is the value of corresponding byte. - * This approach creates a one-to-one map between all bytearray values - * and a subset of Tcl string values. + * The following object types represent an array of bytes. The intent is to + * allow arbitrary binary data to pass through Tcl as a Tcl value without loss + * or damage. Such values are useful for things like encoded strings or Tk + * images to name just two. + * + * It's strange to have two Tcl_ObjTypes in place for this task when one would + * do, so a bit of detail and history how we got to this point and where we + * might go from here. + * + * A bytearray is an ordered sequence of bytes. Each byte is an integer value + * in the range [0-255]. To be a Tcl value type, we need a way to encode each + * value in the value set as a Tcl string. The simplest encoding is to + * represent each byte value as the same codepoint value. A bytearray of N + * bytes is encoded into a Tcl string of N characters where the codepoint of + * each character is the value of corresponding byte. This approach creates a + * one-to-one map between all bytearray values and a subset of Tcl string + * values. * * When converting a Tcl string value to the bytearray internal rep, the * question arises what to do with strings outside that subset? That is, - * those Tcl strings containing at least one codepoint greater than 255? - * The obviously correct answer is to raise an error! That string value - * does not represent any valid bytearray value. Full Stop. The - * setFromAnyProc signature has a completion code return value for just - * this reason, to reject invalid inputs. - * - * Unfortunately this was not the path taken by the authors of the - * original tclByteArrayType. They chose to accept all Tcl string values - * as acceptable string encodings of the bytearray values that result - * from masking away the high bits of any codepoint value at all. This - * meant that every bytearray value had multiple accepted string - * representations. - * - * The implications of this choice are truly ugly. When a Tcl value has - * a string representation, we are required to accept that as the true - * value. Bytearray values that possess a string representation cannot - * be processed as bytearrays because we cannot know which true value - * that bytearray represents. The consequence is that we drag around - * an internal rep that we cannot make any use of. This painful price - * is extracted at any point after a string rep happens to be generated - * for the value. This happens even when the troublesome codepoints - * outside the byte range never show up. This happens rather routinely - * in normal Tcl operations unless we burden the script writer with the - * cognitive burden of avoiding it. The price is also paid by callers - * of the C interface. The routine + * those Tcl strings containing at least one codepoint greater than 255? The + * obviously correct answer is to raise an error! That string value does not + * represent any valid bytearray value. Full Stop. The setFromAnyProc + * signature has a completion code return value for just this reason, to + * reject invalid inputs. + * + * Unfortunately this was not the path taken by the authors of the original + * tclByteArrayType. They chose to accept all Tcl string values as acceptable + * string encodings of the bytearray values that result from masking away the + * high bits of any codepoint value at all. This meant that every bytearray + * value had multiple accepted string representations. + * + * The implications of this choice are truly ugly. When a Tcl value has a + * string representation, we are required to accept that as the true value. + * Bytearray values that possess a string representation cannot be processed + * as bytearrays because we cannot know which true value that bytearray + * represents. The consequence is that we drag around an internal rep that we + * cannot make any use of. This painful price is extracted at any point after + * a string rep happens to be generated for the value. This happens even when + * the troublesome codepoints outside the byte range never show up. This + * happens rather routinely in normal Tcl operations unless we burden the + * script writer with the cognitive burden of avoiding it. The price is also + * paid by callers of the C interface. The routine * * unsigned char *Tcl_GetByteArrayFromObj(objPtr, lenPtr) * - * has a guarantee to always return a non-NULL value, but that value - * points to a byte sequence that cannot be used by the caller to - * process the Tcl value absent some sideband testing that objPtr - * is "pure". Tcl offers no public interface to perform this test, - * so callers either break encapsulation or are unavoidably buggy. Tcl - * has defined a public interface that cannot be used correctly. The - * Tcl source code itself suffers the same problem, and has been buggy, - * but progressively less so as more and more portions of the code have - * been retrofitted with the required "purity testing". The set of values - * able to pass the purity test can be increased via the introduction of - * a "canonical" flag marker, but the only way the broken interface itself + * has a guarantee to always return a non-NULL value, but that value points to + * a byte sequence that cannot be used by the caller to process the Tcl value + * absent some sideband testing that objPtr is "pure". Tcl offers no public + * interface to perform this test, so callers either break encapsulation or + * are unavoidably buggy. Tcl has defined a public interface that cannot be + * used correctly. The Tcl source code itself suffers the same problem, and + * has been buggy, but progressively less so as more and more portions of the + * code have been retrofitted with the required "purity testing". The set of + * values able to pass the purity test can be increased via the introduction + * of a "canonical" flag marker, but the only way the broken interface itself * can be discarded is to start over and define the Tcl_ObjType properly. - * Bytearrays should simply be usable as bytearrays without a kabuki - * dance of testing. - * - * The Tcl_ObjType "properByteArrayType" is (nearly) a correct - * implementation of bytearrays. Any Tcl value with the type - * properByteArrayType can have its bytearray value fetched and - * used with confidence that acting on that value is equivalent to - * acting on the true Tcl string value. This still implies a side - * testing burden -- past mistakes will not let us avoid that - * immediately, but it is at least a conventional test of type, and - * can be implemented entirely by examining the objPtr fields, with - * no need to query the intrep, as a canonical flag would require. - * - * Until Tcl_GetByteArrayFromObj() and Tcl_SetByteArrayLength() can - * be revised to admit the possibility of returning NULL when the true - * value is not a valid bytearray, we need a mechanism to retain - * compatibility with the deployed callers of the broken interface. - * That's what the retained "tclByteArrayType" provides. In those - * unusual circumstances where we convert an invalid bytearray value - * to a bytearray type, it is to this legacy type. Essentially any - * time this legacy type gets used, it's a signal of a bug being ignored. - * A TIP should be drafted to remove this connection to the broken past - * so that Tcl 9 will no longer have any trace of it. Prescribing a - * migration path will be the key element of that work. The internal - * changes now in place are the limit of what can be done short of - * interface repair. They provide a great expansion of the histories - * over which bytearray values can be useful in the meanwhile. + * Bytearrays should simply be usable as bytearrays without a kabuki dance of + * testing. + * + * The Tcl_ObjType "properByteArrayType" is (nearly) a correct implementation + * of bytearrays. Any Tcl value with the type properByteArrayType can have + * its bytearray value fetched and used with confidence that acting on that + * value is equivalent to acting on the true Tcl string value. This still + * implies a side testing burden -- past mistakes will not let us avoid that + * immediately, but it is at least a conventional test of type, and can be + * implemented entirely by examining the objPtr fields, with no need to query + * the intrep, as a canonical flag would require. + * + * Until Tcl_GetByteArrayFromObj() and Tcl_SetByteArrayLength() can be revised + * to admit the possibility of returning NULL when the true value is not a + * valid bytearray, we need a mechanism to retain compatibility with the + * deployed callers of the broken interface. That's what the retained + * "tclByteArrayType" provides. In those unusual circumstances where we + * convert an invalid bytearray value to a bytearray type, it is to this + * legacy type. Essentially any time this legacy type gets used, it's a + * signal of a bug being ignored. A TIP should be drafted to remove this + * connection to the broken past so that Tcl 9 will no longer have any trace + * of it. Prescribing a migration path will be the key element of that work. + * The internal changes now in place are the limit of what can be done short + * of interface repair. They provide a great expansion of the histories over + * which bytearray values can be useful in the meanwhile. */ static const Tcl_ObjType properByteArrayType = { @@ -400,10 +395,10 @@ Tcl_DbNewByteArrayObj( 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. May be NULL even if length > 0. */ + const unsigned char *bytes, /* The array of bytes to use as the new value. + * May be NULL even if length > 0. */ int length) /* Length of the array of bytes, which must - be >= 0. */ + * be >= 0. */ { ByteArray *byteArrayPtr; Tcl_ObjIntRep ir; @@ -723,14 +718,16 @@ UpdateStringOfByteArray( if (size == length) { char *dst = Tcl_InitStringRep(objPtr, (char *)src, size); + TclOOM(dst, size); } else { char *dst = Tcl_InitStringRep(objPtr, NULL, size); + TclOOM(dst, size); for (i = 0; i < length; i++) { dst += Tcl_UniCharToUtf(src[i], dst); } - (void)Tcl_InitStringRep(objPtr, NULL, size); + (void) Tcl_InitStringRep(objPtr, NULL, size); } } @@ -778,7 +775,7 @@ TclAppendBytesToByteArray( return; } - length = (unsigned int)len; + length = (unsigned int) len; irPtr = TclFetchIntRep(objPtr, &properByteArrayType); if (irPtr == NULL) { @@ -807,12 +804,18 @@ TclAppendBytesToByteArray( unsigned int attempt; if (needed <= INT_MAX/2) { - /* Try to allocate double the total space that is needed. */ + /* + * Try to allocate double the total space that is needed. + */ + attempt = 2 * needed; ptr = attemptckrealloc(byteArrayPtr, BYTEARRAY_SIZE(attempt)); } if (ptr == NULL) { - /* Try to allocate double the increment that is needed (plus). */ + /* + * Try to allocate double the increment that is needed (plus). + */ + unsigned int limit = INT_MAX - needed; unsigned int extra = length + TCL_MIN_GROWTH; int growth = (int) ((extra > limit) ? limit : extra); @@ -821,7 +824,10 @@ TclAppendBytesToByteArray( ptr = attemptckrealloc(byteArrayPtr, BYTEARRAY_SIZE(attempt)); } if (ptr == NULL) { - /* Last chance: Try to allocate exactly what is needed. */ + /* + * Last chance: Try to allocate exactly what is needed. + */ + attempt = needed; ptr = ckrealloc(byteArrayPtr, BYTEARRAY_SIZE(attempt)); } @@ -896,7 +902,7 @@ BinaryFormatCmd( int count; /* Count associated with current format * character. */ int flags; /* Format field flags */ - const char *format; /* Pointer to current position in format + const char *format; /* Pointer to current position in format * string. */ Tcl_Obj *resultPtr = NULL; /* Object holding result buffer. */ unsigned char *buffer; /* Start of result buffer. */ @@ -1082,9 +1088,9 @@ BinaryFormatCmd( memset(buffer, 0, length); /* - * Pack the data into the result object. Note that we can skip the - * error checking during this pass, since we have already parsed the - * string once. + * Pack the data into the result object. Note that we can skip the error + * checking during this pass, since we have already parsed the string + * once. */ arg = 2; @@ -1297,7 +1303,7 @@ BinaryFormatCmd( } arg++; for (i = 0; i < count; i++) { - if (FormatNumber(interp, cmd, listv[i], &cursor)!=TCL_OK) { + if (FormatNumber(interp, cmd, listv[i], &cursor) != TCL_OK) { Tcl_DecrRefCount(resultPtr); return TCL_ERROR; } @@ -1401,7 +1407,7 @@ BinaryScanCmd( int count; /* Count associated with current format * character. */ int flags; /* Format field flags */ - const char *format; /* Pointer to current position in format + const char *format; /* Pointer to current position in format * string. */ Tcl_Obj *resultPtr = NULL; /* Object holding result buffer. */ unsigned char *buffer; /* Start of result buffer. */ @@ -1460,7 +1466,7 @@ BinaryScanCmd( if (cmd == 'A') { while (size > 0) { - if (src[size-1] != '\0' && src[size-1] != ' ') { + if (src[size - 1] != '\0' && src[size - 1] != ' ') { break; } size--; @@ -2055,6 +2061,7 @@ FormatNumber( if (Tcl_GetDoubleFromObj(interp, src, &dvalue) != TCL_OK) { const Tcl_ObjIntRep *irPtr = TclFetchIntRep(src, &tclDoubleType); + if (irPtr == NULL) { return TCL_ERROR; } @@ -2067,7 +2074,7 @@ FormatNumber( * valid range for float. */ - if (fabs(dvalue) > (double)FLT_MAX) { + if (fabs(dvalue) > (double) FLT_MAX) { fvalue = (dvalue >= 0.0) ? FLT_MAX : -FLT_MAX; } else { fvalue = (float) dvalue; @@ -2188,9 +2195,9 @@ ScanNumber( int type, /* Format character from "binary scan" */ int flags, /* Format field flags */ Tcl_HashTable **numberCachePtrPtr) - /* Place to look for cache of scanned - * value objects, or NULL if too many - * different numbers have been scanned. */ + /* Place to look for cache of scanned value + * objects, or NULL if too many different + * numbers have been scanned. */ { long value; float fvalue; @@ -2264,6 +2271,7 @@ ScanNumber( /* * Check to see if the value was sign extended properly on systems * where an int is more than 32-bits. + * * We avoid caching unsigned integers as we cannot distinguish between * 32bit signed and unsigned in the hash (short and char are ok). */ @@ -2271,9 +2279,9 @@ ScanNumber( if (flags & BINARY_UNSIGNED) { return Tcl_NewWideIntObj((Tcl_WideInt)(unsigned long)value); } - if ((value & (((unsigned) 1)<<31)) && (value > 0)) { - value -= (((unsigned) 1)<<31); - value -= (((unsigned) 1)<<31); + if ((value & (((unsigned) 1) << 31)) && (value > 0)) { + value -= (((unsigned) 1) << 31); + value -= (((unsigned) 1) << 31); } returnNumericObject: @@ -2473,8 +2481,8 @@ BinaryEncodeHex( data = Tcl_GetByteArrayFromObj(objv[1], &count); cursor = Tcl_SetByteArrayLength(resultObj, count * 2); for (offset = 0; offset < count; ++offset) { - *cursor++ = HexDigits[((data[offset] >> 4) & 0x0f)]; - *cursor++ = HexDigits[(data[offset] & 0x0f)]; + *cursor++ = HexDigits[(data[offset] >> 4) & 0x0f]; + *cursor++ = HexDigits[data[offset] & 0x0f]; } Tcl_SetObjResult(interp, resultObj); return TCL_OK; @@ -2514,7 +2522,7 @@ BinaryDecodeHex( Tcl_WrongNumArgs(interp, 1, objv, "?options? data"); return TCL_ERROR; } - for (i = 1; i < objc-1; ++i) { + for (i = 1; i < objc - 1; ++i) { if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; @@ -2528,13 +2536,13 @@ BinaryDecodeHex( TclNewObj(resultObj); datastart = data = (unsigned char *) - TclGetStringFromObj(objv[objc-1], &count); + TclGetStringFromObj(objv[objc - 1], &count); dataend = data + count; size = (count + 1) / 2; begin = cursor = Tcl_SetByteArrayLength(resultObj, size); while (data < dataend) { value = 0; - for (i=0 ; i<2 ; i++) { + for (i = 0 ; i < 2 ; i++) { if (data >= dataend) { value <<= 4; break; @@ -2557,7 +2565,7 @@ BinaryDecodeHex( if (c > 16) { c += ('A' - 'a'); } - value |= (c & 0xf); + value |= c & 0xf; } if (i < 2) { cut++; @@ -2628,22 +2636,22 @@ BinaryEncode64( const char *wrapchar = "\n"; int wrapcharlen = 1; int offset, i, index, size, outindex = 0, count = 0; - enum {OPT_MAXLEN, OPT_WRAPCHAR }; + enum { OPT_MAXLEN, OPT_WRAPCHAR }; static const char *const optStrings[] = { "-maxlen", "-wrapchar", NULL }; - if (objc < 2 || objc%2 != 0) { + if (objc < 2 || objc % 2 != 0) { Tcl_WrongNumArgs(interp, 1, objv, "?-maxlen len? ?-wrapchar char? data"); return TCL_ERROR; } - for (i = 1; i < objc-1; i += 2) { + for (i = 1; i < objc - 1; i += 2) { if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case OPT_MAXLEN: - if (Tcl_GetIntFromObj(interp, objv[i+1], &maxlen) != TCL_OK) { + if (Tcl_GetIntFromObj(interp, objv[i + 1], &maxlen) != TCL_OK) { return TCL_ERROR; } if (maxlen < 0) { @@ -2655,7 +2663,7 @@ BinaryEncode64( } break; case OPT_WRAPCHAR: - wrapchar = TclGetStringFromObj(objv[i+1], &wrapcharlen); + wrapchar = TclGetStringFromObj(objv[i + 1], &wrapcharlen); if (wrapcharlen == 0) { maxlen = 0; } @@ -2664,9 +2672,9 @@ BinaryEncode64( } resultObj = Tcl_NewObj(); - data = Tcl_GetByteArrayFromObj(objv[objc-1], &count); + data = Tcl_GetByteArrayFromObj(objv[objc - 1], &count); if (count > 0) { - size = (((count * 4) / 3) + 3) & ~3; /* ensure 4 byte chunks */ + size = (((count * 4) / 3) + 3) & ~3; /* ensure 4 byte chunks */ if (maxlen > 0 && size > maxlen) { int adjusted = size + (wrapcharlen * (size / maxlen)); @@ -2677,15 +2685,15 @@ BinaryEncode64( } cursor = Tcl_SetByteArrayLength(resultObj, size); limit = cursor + size; - for (offset = 0; offset < count; offset+=3) { + for (offset = 0; offset < count; offset += 3) { unsigned char d[3] = {0, 0, 0}; - for (i = 0; i < 3 && offset+i < count; ++i) { + for (i = 0; i < 3 && offset + i < count; ++i) { d[i] = data[offset + i]; } OUTPUT(B64Digits[d[0] >> 2]); OUTPUT(B64Digits[((d[0] & 0x03) << 4) | (d[1] >> 4)]); - if (offset+1 < count) { + if (offset + 1 < count) { OUTPUT(B64Digits[((d[1] & 0x0f) << 2) | (d[2] >> 6)]); } else { OUTPUT(B64Digits[64]); @@ -2738,19 +2746,20 @@ BinaryEncodeUu( enum { OPT_MAXLEN, OPT_WRAPCHAR }; static const char *const optStrings[] = { "-maxlen", "-wrapchar", NULL }; - if (objc < 2 || objc%2 != 0) { + if (objc < 2 || objc % 2 != 0) { Tcl_WrongNumArgs(interp, 1, objv, "?-maxlen len? ?-wrapchar char? data"); return TCL_ERROR; } - for (i = 1; i < objc-1; i += 2) { + for (i = 1; i < objc - 1; i += 2) { if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; } switch (index) { case OPT_MAXLEN: - if (Tcl_GetIntFromObj(interp, objv[i+1], &lineLength) != TCL_OK) { + if (Tcl_GetIntFromObj(interp, objv[i + 1], + &lineLength) != TCL_OK) { return TCL_ERROR; } if (lineLength < 3 || lineLength > 85) { @@ -2762,7 +2771,7 @@ BinaryEncodeUu( } break; case OPT_WRAPCHAR: - wrapchar = Tcl_GetByteArrayFromObj(objv[i+1], &wrapcharlen); + wrapchar = Tcl_GetByteArrayFromObj(objv[i + 1], &wrapcharlen); break; } } @@ -2774,7 +2783,7 @@ BinaryEncodeUu( resultObj = Tcl_NewObj(); offset = 0; - data = Tcl_GetByteArrayFromObj(objv[objc-1], &count); + data = Tcl_GetByteArrayFromObj(objv[objc - 1], &count); rawLength = (lineLength - 1) * 3 / 4; start = cursor = Tcl_SetByteArrayLength(resultObj, (lineLength + wrapcharlen) * @@ -2795,11 +2804,11 @@ BinaryEncodeUu( lineLen = rawLength; } *cursor++ = UueDigits[lineLen]; - for (i=0 ; i<lineLen ; i++) { + for (i = 0 ; i < lineLen ; i++) { n <<= 8; n |= data[offset++]; for (bits += 8; bits > 6 ; bits -= 6) { - *cursor++ = UueDigits[(n >> (bits-6)) & 0x3f]; + *cursor++ = UueDigits[(n >> (bits - 6)) & 0x3f]; } } if (bits > 0) { @@ -2807,7 +2816,7 @@ BinaryEncodeUu( *cursor++ = UueDigits[(n >> (bits + 2)) & 0x3f]; bits = 0; } - for (j=0 ; j<wrapcharlen ; ++j) { + for (j = 0 ; j < wrapcharlen ; ++j) { *cursor++ = wrapchar[j]; } } @@ -2816,7 +2825,7 @@ BinaryEncodeUu( * Fix the length of the output bytearray. */ - Tcl_SetByteArrayLength(resultObj, cursor-start); + Tcl_SetByteArrayLength(resultObj, cursor - start); Tcl_SetObjResult(interp, resultObj); return TCL_OK; } @@ -2849,14 +2858,14 @@ BinaryDecodeUu( unsigned char *begin, *cursor; int i, index, size, count = 0, strict = 0, lineLen; unsigned char c; - enum {OPT_STRICT }; + enum { OPT_STRICT }; static const char *const optStrings[] = { "-strict", NULL }; if (objc < 2 || objc > 3) { Tcl_WrongNumArgs(interp, 1, objv, "?options? data"); return TCL_ERROR; } - for (i = 1; i < objc-1; ++i) { + for (i = 1; i < objc - 1; ++i) { if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; @@ -2870,7 +2879,7 @@ BinaryDecodeUu( TclNewObj(resultObj); datastart = data = (unsigned char *) - TclGetStringFromObj(objv[objc-1], &count); + TclGetStringFromObj(objv[objc - 1], &count); dataend = data + count; size = ((count + 3) & ~3) * 3 / 4; begin = cursor = Tcl_SetByteArrayLength(resultObj, size); @@ -2902,7 +2911,7 @@ BinaryDecodeUu( * Now we read a four-character grouping. */ - for (i=0 ; i<4 ; i++) { + for (i = 0 ; i < 4 ; i++) { if (data < dataend) { d[i] = c = *data++; if (c < 32 || c > 96) { @@ -3020,7 +3029,7 @@ BinaryDecode64( Tcl_WrongNumArgs(interp, 1, objv, "?options? data"); return TCL_ERROR; } - for (i = 1; i < objc-1; ++i) { + for (i = 1; i < objc - 1; ++i) { if (Tcl_GetIndexFromObj(interp, objv[i], optStrings, "option", TCL_EXACT, &index) != TCL_OK) { return TCL_ERROR; @@ -3034,7 +3043,7 @@ BinaryDecode64( TclNewObj(resultObj); datastart = data = (unsigned char *) - TclGetStringFromObj(objv[objc-1], &count); + TclGetStringFromObj(objv[objc - 1], &count); dataend = data + count; size = ((count + 3) & ~3) * 3 / 4; begin = cursor = Tcl_SetByteArrayLength(resultObj, size); @@ -3062,8 +3071,11 @@ BinaryDecode64( c = '='; } else { if (strict && i <= 1) { - /* single resp. unfulfilled char (each 4th next single char) - * is rather bad64 error case in strict mode */ + /* + * Single resp. unfulfilled char (each 4th next single + * char) is rather bad64 error case in strict mode. + */ + goto bad64; } cut += 3; @@ -3079,10 +3091,10 @@ BinaryDecode64( if (cut) { if (c == '=' && i > 1) { - value <<= 6; - cut++; + value <<= 6; + cut++; } else if (!strict && TclIsSpaceProc(c)) { - i--; + i--; } else { goto bad64; } @@ -3096,11 +3108,15 @@ BinaryDecode64( value = (value << 6) | 0x3e; } else if (c == '/') { value = (value << 6) | 0x3f; - } else if (c == '=' && ( - !strict || i > 1) /* "=" and "a=" is rather bad64 error case in strict mode */ - ) { + } else if (c == '=' && (!strict || i > 1)) { + /* + * "=" and "a=" is rather bad64 error case in strict mode. + */ + value <<= 6; - if (i) cut++; + if (i) { + cut++; + } } else if (strict || !TclIsSpaceProc(c)) { goto bad64; } else { @@ -3147,4 +3163,3 @@ BinaryDecode64( * fill-column: 78 * End: */ - |