Updated 2012-10-18 06:17:47 by AMG

AMG: This page exists as a temporary repository for a file that the SourceForge bug tracker won't let me attach. Will some SF administrator please file a way to get the file into the bug tracker, then delete this page? Thanks. The bug URL is: [1]

Here's the patch:
diff -ur tcl8.6b3~/generic/tclBinary.c tcl8.6b3/generic/tclBinary.c
--- tcl8.6b3~/generic/tclBinary.c        2012-09-17 07:25:44.000000000 -0500
+++ tcl8.6b3/generic/tclBinary.c        2012-10-16 19:04:02.000000000 -0500
@@ -2658,7 +2658,7 @@
     Tcl_Obj *const objv[])
 {
     Tcl_Obj *resultObj = NULL;
-    unsigned char *data, *datastart, *dataend, c;
+    unsigned char *data, *datastart, *dataend, c = '\0';
     unsigned char *begin = NULL;
     unsigned char *cursor = NULL;
     int strict = 0;
@@ -2691,43 +2691,82 @@
     while (data < dataend) {
         unsigned long value = 0;
 
-        for (i=0 ; i<4 ; i++) {
+        /*
+         * Decode the current block. Each base64 block consists of four input
+         * characters A-Z, a-z, 0-9, +, or /. Each character supplies six bits
+         * of output data, so each block's output is 24 bits (three bytes) in
+         * length. The final block can be shorter by one or two bytes, denoted
+         * by the input ending with one or two ='s, respectively.
+         */
+        for (i = 0; i < 4; i++) {
+            /*
+             * Get the next input character. At end of input, pad with at most
+             * two ='s. If more than two ='s would be needed, instead discard
+             * the block read thus far.
+             */
             if (data < dataend) {
                 c = *data++;
+            } else if (i > 1) {
+                c = '=';
+            } else {
+                cut += 3;
+                break;
+            }
 
-                if (c >= 'A' && c <= 'Z') {
-                    value = (value << 6) | ((c - 'A') & 0x3f);
-                } else if (c >= 'a' && c <= 'z') {
-                    value = (value << 6) | ((c - 'a' + 26) & 0x3f);
-                } else if (c >= '0' && c <= '9') {
-                    value = (value << 6) | ((c - '0' + 52) & 0x3f);
-                } else if (c == '+') {
-                    value = (value << 6) | 0x3e;
-                } else if (c == '/') {
-                    value = (value << 6) | 0x3f;
-                } else if (c == '=') {
+            /*
+             * Load the character into the block value. Handle ='s specially
+             * because they're only valid as the last character or two of the
+             * final block of input. Unless strict mode is enabled, skip any
+             * input whitespace characters.
+             */
+            if (cut) {
+                if (c == '=' && i > 1) {
                     value <<= 6;
-                    if (cut < 2) {
-                        cut++;
-                    }
-                } else {
-                    if (strict || !isspace(c)) {
-                        goto bad64;
-                    }
+                    cut++;
+                } else if (!strict && isspace(c)) {
                     i--;
-                    continue;
+                } else {
+                    goto bad64;
                 }
-            } else {
+            } else if (c >= 'A' && c <= 'Z') {
+                value = (value << 6) | ((c - 'A') & 0x3f);
+            } else if (c >= 'a' && c <= 'z') {
+                value = (value << 6) | ((c - 'a' + 26) & 0x3f);
+            } else if (c >= '0' && c <= '9') {
+                value = (value << 6) | ((c - '0' + 52) & 0x3f);
+            } else if (c == '+') {
+                value = (value << 6) | 0x3e;
+            } else if (c == '/') {
+                value = (value << 6) | 0x3f;
+            } else if (c == '=') {
                 value <<= 6;
                 cut++;
+            } else if (strict || !isspace(c)) {
+                goto bad64;
+            } else {
+                i--;
             }
         }
         *cursor++ = UCHAR((value >> 16) & 0xff);
         *cursor++ = UCHAR((value >> 8) & 0xff);
         *cursor++ = UCHAR(value & 0xff);
-    }
-    if (cut > size) {
-        cut = size;
+
+        /*
+         * Since = is only valid within the final block, if it was encountered
+         * but there are still more input characters, confirm that strict mode
+         * is off and all subsequent characters are whitespace.
+         */
+        if (cut && data < dataend) {
+            if (strict) {
+                goto bad64;
+            } else {
+                for (; data < dataend; data++) {
+                    if (!isspace(*data)) {
+                        goto bad64;
+                    }
+                }
+            }
+        }
     }
     Tcl_SetByteArrayLength(resultObj, cursor - begin - cut);
     Tcl_SetObjResult(interp, resultObj);
diff -ur tcl8.6b3~/tests/binary.test tcl8.6b3/tests/binary.test
--- tcl8.6b3~/tests/binary.test        2012-06-26 08:59:02.000000000 -0500
+++ tcl8.6b3/tests/binary.test        2012-10-16 18:43:50.000000000 -0500
@@ -2642,6 +2642,27 @@
 test binary-73.24 {binary decode base64} -body {
     string length [binary decode base64 " "]
 } -result 0
+test binary-73.25 {binary decode base64} -body {
+    list [string length [set r [binary decode base64 WA==\n]]] $r
+} -result {1 X}
+test binary-73.26 {binary decode base64} -body {
+    list [string length [set r [binary decode base64 WFk=\n]]] $r
+} -result {2 XY}
+test binary-73.27 {binary decode base64} -body {
+    list [string length [set r [binary decode base64 WFla\n]]] $r
+} -result {3 XYZ}
+test binary-73.28 {binary decode base64} -body {
+    list [string length [set r [binary decode base64 -strict WA==\n]]] $r
+} -returnCodes error -match glob -result {invalid base64 character *}
+test binary-73.29 {binary decode base64} -body {
+    list [string length [set r [binary decode base64 -strict WFk=\n]]] $r
+} -returnCodes error -match glob -result {invalid base64 character *}
+test binary-73.30 {binary decode base64} -body {
+    list [string length [set r [binary decode base64 -strict WFla\n]]] $r
+} -returnCodes error -match glob -result {invalid base64 character *}
+test binary-73.31 {binary decode base64} -body {
+    list [string length [set r [binary decode base64 WA==WFla]]] $r
+} -returnCodes error -match glob -result {invalid base64 character *}
 
 test binary-74.1 {binary encode uuencode} -body {
     binary encode uuencode

Hopefully the Wiki won't destroy all the tabs... *sigh*

Yup, it ate my tabs. Oh well, you can still read it.

Here's the intended file, formatted in base64 of course. :^)
begin-base64 644 tcl8.6b3-base64decode.patch
ZGlmZiAtdXIgdGNsOC42YjN+L2dlbmVyaWMvdGNsQmluYXJ5LmMgdGNsOC42
YjMvZ2VuZXJpYy90Y2xCaW5hcnkuYwotLS0gdGNsOC42YjN+L2dlbmVyaWMv
dGNsQmluYXJ5LmMJMjAxMi0wOS0xNyAwNzoyNTo0NC4wMDAwMDAwMDAgLTA1
MDAKKysrIHRjbDguNmIzL2dlbmVyaWMvdGNsQmluYXJ5LmMJMjAxMi0xMC0x
NiAxOTowNDowMi4wMDAwMDAwMDAgLTA1MDAKQEAgLTI2NTgsNyArMjY1OCw3
IEBACiAgICAgVGNsX09iaiAqY29uc3Qgb2JqdltdKQogewogICAgIFRjbF9P
YmogKnJlc3VsdE9iaiA9IE5VTEw7Ci0gICAgdW5zaWduZWQgY2hhciAqZGF0
YSwgKmRhdGFzdGFydCwgKmRhdGFlbmQsIGM7CisgICAgdW5zaWduZWQgY2hh
ciAqZGF0YSwgKmRhdGFzdGFydCwgKmRhdGFlbmQsIGMgPSAnXDAnOwogICAg
IHVuc2lnbmVkIGNoYXIgKmJlZ2luID0gTlVMTDsKICAgICB1bnNpZ25lZCBj
aGFyICpjdXJzb3IgPSBOVUxMOwogICAgIGludCBzdHJpY3QgPSAwOwpAQCAt
MjY5MSw0MyArMjY5MSw4MiBAQAogICAgIHdoaWxlIChkYXRhIDwgZGF0YWVu
ZCkgewogCXVuc2lnbmVkIGxvbmcgdmFsdWUgPSAwOwogCi0JZm9yIChpPTAg
OyBpPDQgOyBpKyspIHsKKwkvKgorCSAqIERlY29kZSB0aGUgY3VycmVudCBi
bG9jay4gRWFjaCBiYXNlNjQgYmxvY2sgY29uc2lzdHMgb2YgZm91ciBpbnB1
dAorCSAqIGNoYXJhY3RlcnMgQS1aLCBhLXosIDAtOSwgKywgb3IgLy4gRWFj
aCBjaGFyYWN0ZXIgc3VwcGxpZXMgc2l4IGJpdHMKKwkgKiBvZiBvdXRwdXQg
ZGF0YSwgc28gZWFjaCBibG9jaydzIG91dHB1dCBpcyAyNCBiaXRzICh0aHJl
ZSBieXRlcykgaW4KKwkgKiBsZW5ndGguIFRoZSBmaW5hbCBibG9jayBjYW4g
YmUgc2hvcnRlciBieSBvbmUgb3IgdHdvIGJ5dGVzLCBkZW5vdGVkCisJICog
YnkgdGhlIGlucHV0IGVuZGluZyB3aXRoIG9uZSBvciB0d28gPSdzLCByZXNw
ZWN0aXZlbHkuCisJICovCisJZm9yIChpID0gMDsgaSA8IDQ7IGkrKykgewor
CSAgICAvKgorCSAgICAgKiBHZXQgdGhlIG5leHQgaW5wdXQgY2hhcmFjdGVy
LiBBdCBlbmQgb2YgaW5wdXQsIHBhZCB3aXRoIGF0IG1vc3QKKwkgICAgICog
dHdvID0ncy4gSWYgbW9yZSB0aGFuIHR3byA9J3Mgd291bGQgYmUgbmVlZGVk
LCBpbnN0ZWFkIGRpc2NhcmQKKwkgICAgICogdGhlIGJsb2NrIHJlYWQgdGh1
cyBmYXIuCisJICAgICAqLwogCSAgICBpZiAoZGF0YSA8IGRhdGFlbmQpIHsK
IAkJYyA9ICpkYXRhKys7CisJICAgIH0gZWxzZSBpZiAoaSA+IDEpIHsKKwkJ
YyA9ICc9JzsKKwkgICAgfSBlbHNlIHsKKwkJY3V0ICs9IDM7CisJCWJyZWFr
OworCSAgICB9CiAKLQkJaWYgKGMgPj0gJ0EnICYmIGMgPD0gJ1onKSB7Ci0J
CSAgICB2YWx1ZSA9ICh2YWx1ZSA8PCA2KSB8ICgoYyAtICdBJykgJiAweDNm
KTsKLQkJfSBlbHNlIGlmIChjID49ICdhJyAmJiBjIDw9ICd6JykgewotCQkg
ICAgdmFsdWUgPSAodmFsdWUgPDwgNikgfCAoKGMgLSAnYScgKyAyNikgJiAw
eDNmKTsKLQkJfSBlbHNlIGlmIChjID49ICcwJyAmJiBjIDw9ICc5Jykgewot
CQkgICAgdmFsdWUgPSAodmFsdWUgPDwgNikgfCAoKGMgLSAnMCcgKyA1Mikg
JiAweDNmKTsKLQkJfSBlbHNlIGlmIChjID09ICcrJykgewotCQkgICAgdmFs
dWUgPSAodmFsdWUgPDwgNikgfCAweDNlOwotCQl9IGVsc2UgaWYgKGMgPT0g
Jy8nKSB7Ci0JCSAgICB2YWx1ZSA9ICh2YWx1ZSA8PCA2KSB8IDB4M2Y7Ci0J
CX0gZWxzZSBpZiAoYyA9PSAnPScpIHsKKwkgICAgLyoKKwkgICAgICogTG9h
ZCB0aGUgY2hhcmFjdGVyIGludG8gdGhlIGJsb2NrIHZhbHVlLiBIYW5kbGUg
PSdzIHNwZWNpYWxseQorCSAgICAgKiBiZWNhdXNlIHRoZXkncmUgb25seSB2
YWxpZCBhcyB0aGUgbGFzdCBjaGFyYWN0ZXIgb3IgdHdvIG9mIHRoZQorCSAg
ICAgKiBmaW5hbCBibG9jayBvZiBpbnB1dC4gVW5sZXNzIHN0cmljdCBtb2Rl
IGlzIGVuYWJsZWQsIHNraXAgYW55CisJICAgICAqIGlucHV0IHdoaXRlc3Bh
Y2UgY2hhcmFjdGVycy4KKwkgICAgICovCisJICAgIGlmIChjdXQpIHsKKwkJ
aWYgKGMgPT0gJz0nICYmIGkgPiAxKSB7CiAJCSAgICB2YWx1ZSA8PD0gNjsK
LQkJICAgIGlmIChjdXQgPCAyKSB7Ci0JCQljdXQrKzsKLQkJICAgIH0KLQkJ
fSBlbHNlIHsKLQkJICAgIGlmIChzdHJpY3QgfHwgIWlzc3BhY2UoYykpIHsK
LQkJCWdvdG8gYmFkNjQ7Ci0JCSAgICB9CisJCSAgICBjdXQrKzsKKwkJfSBl
bHNlIGlmICghc3RyaWN0ICYmIGlzc3BhY2UoYykpIHsKIAkJICAgIGktLTsK
LQkJICAgIGNvbnRpbnVlOworCQl9IGVsc2UgeworCQkgICAgZ290byBiYWQ2
NDsKIAkJfQotCSAgICB9IGVsc2UgeworCSAgICB9IGVsc2UgaWYgKGMgPj0g
J0EnICYmIGMgPD0gJ1onKSB7CisJCXZhbHVlID0gKHZhbHVlIDw8IDYpIHwg
KChjIC0gJ0EnKSAmIDB4M2YpOworCSAgICB9IGVsc2UgaWYgKGMgPj0gJ2En
ICYmIGMgPD0gJ3onKSB7CisJCXZhbHVlID0gKHZhbHVlIDw8IDYpIHwgKChj
IC0gJ2EnICsgMjYpICYgMHgzZik7CisJICAgIH0gZWxzZSBpZiAoYyA+PSAn
MCcgJiYgYyA8PSAnOScpIHsKKwkJdmFsdWUgPSAodmFsdWUgPDwgNikgfCAo
KGMgLSAnMCcgKyA1MikgJiAweDNmKTsKKwkgICAgfSBlbHNlIGlmIChjID09
ICcrJykgeworCQl2YWx1ZSA9ICh2YWx1ZSA8PCA2KSB8IDB4M2U7CisJICAg
IH0gZWxzZSBpZiAoYyA9PSAnLycpIHsKKwkJdmFsdWUgPSAodmFsdWUgPDwg
NikgfCAweDNmOworCSAgICB9IGVsc2UgaWYgKGMgPT0gJz0nKSB7CiAJCXZh
bHVlIDw8PSA2OwogCQljdXQrKzsKKwkgICAgfSBlbHNlIGlmIChzdHJpY3Qg
fHwgIWlzc3BhY2UoYykpIHsKKwkJZ290byBiYWQ2NDsKKwkgICAgfSBlbHNl
IHsKKwkJaS0tOwogCSAgICB9CiAJfQogCSpjdXJzb3IrKyA9IFVDSEFSKCh2
YWx1ZSA+PiAxNikgJiAweGZmKTsKIAkqY3Vyc29yKysgPSBVQ0hBUigodmFs
dWUgPj4gOCkgJiAweGZmKTsKIAkqY3Vyc29yKysgPSBVQ0hBUih2YWx1ZSAm
IDB4ZmYpOwotICAgIH0KLSAgICBpZiAoY3V0ID4gc2l6ZSkgewotCWN1dCA9
IHNpemU7CisKKwkvKgorCSAqIFNpbmNlID0gaXMgb25seSB2YWxpZCB3aXRo
aW4gdGhlIGZpbmFsIGJsb2NrLCBpZiBpdCB3YXMgZW5jb3VudGVyZWQKKwkg
KiBidXQgdGhlcmUgYXJlIHN0aWxsIG1vcmUgaW5wdXQgY2hhcmFjdGVycywg
Y29uZmlybSB0aGF0IHN0cmljdCBtb2RlCisJICogaXMgb2ZmIGFuZCBhbGwg
c3Vic2VxdWVudCBjaGFyYWN0ZXJzIGFyZSB3aGl0ZXNwYWNlLgorCSAqLwor
CWlmIChjdXQgJiYgZGF0YSA8IGRhdGFlbmQpIHsKKwkgICAgaWYgKHN0cmlj
dCkgeworCQlnb3RvIGJhZDY0OworCSAgICB9IGVsc2UgeworCQlmb3IgKDsg
ZGF0YSA8IGRhdGFlbmQ7IGRhdGErKykgeworCQkgICAgaWYgKCFpc3NwYWNl
KCpkYXRhKSkgeworCQkJZ290byBiYWQ2NDsKKwkJICAgIH0KKwkJfQorCSAg
ICB9CisJfQogICAgIH0KICAgICBUY2xfU2V0Qnl0ZUFycmF5TGVuZ3RoKHJl
c3VsdE9iaiwgY3Vyc29yIC0gYmVnaW4gLSBjdXQpOwogICAgIFRjbF9TZXRP
YmpSZXN1bHQoaW50ZXJwLCByZXN1bHRPYmopOwpkaWZmIC11ciB0Y2w4LjZi
M34vdGVzdHMvYmluYXJ5LnRlc3QgdGNsOC42YjMvdGVzdHMvYmluYXJ5LnRl
c3QKLS0tIHRjbDguNmIzfi90ZXN0cy9iaW5hcnkudGVzdAkyMDEyLTA2LTI2
IDA4OjU5OjAyLjAwMDAwMDAwMCAtMDUwMAorKysgdGNsOC42YjMvdGVzdHMv
YmluYXJ5LnRlc3QJMjAxMi0xMC0xNiAxODo0Mzo1MC4wMDAwMDAwMDAgLTA1
MDAKQEAgLTI2NDIsNiArMjY0MiwyNyBAQAogdGVzdCBiaW5hcnktNzMuMjQg
e2JpbmFyeSBkZWNvZGUgYmFzZTY0fSAtYm9keSB7CiAgICAgc3RyaW5nIGxl
bmd0aCBbYmluYXJ5IGRlY29kZSBiYXNlNjQgIiAiXQogfSAtcmVzdWx0IDAK
K3Rlc3QgYmluYXJ5LTczLjI1IHtiaW5hcnkgZGVjb2RlIGJhc2U2NH0gLWJv
ZHkgeworICAgIGxpc3QgW3N0cmluZyBsZW5ndGggW3NldCByIFtiaW5hcnkg
ZGVjb2RlIGJhc2U2NCBXQT09XG5dXV0gJHIKK30gLXJlc3VsdCB7MSBYfQor
dGVzdCBiaW5hcnktNzMuMjYge2JpbmFyeSBkZWNvZGUgYmFzZTY0fSAtYm9k
eSB7CisgICAgbGlzdCBbc3RyaW5nIGxlbmd0aCBbc2V0IHIgW2JpbmFyeSBk
ZWNvZGUgYmFzZTY0IFdGaz1cbl1dXSAkcgorfSAtcmVzdWx0IHsyIFhZfQor
dGVzdCBiaW5hcnktNzMuMjcge2JpbmFyeSBkZWNvZGUgYmFzZTY0fSAtYm9k
eSB7CisgICAgbGlzdCBbc3RyaW5nIGxlbmd0aCBbc2V0IHIgW2JpbmFyeSBk
ZWNvZGUgYmFzZTY0IFdGbGFcbl1dXSAkcgorfSAtcmVzdWx0IHszIFhZWn0K
K3Rlc3QgYmluYXJ5LTczLjI4IHtiaW5hcnkgZGVjb2RlIGJhc2U2NH0gLWJv
ZHkgeworICAgIGxpc3QgW3N0cmluZyBsZW5ndGggW3NldCByIFtiaW5hcnkg
ZGVjb2RlIGJhc2U2NCAtc3RyaWN0IFdBPT1cbl1dXSAkcgorfSAtcmV0dXJu
Q29kZXMgZXJyb3IgLW1hdGNoIGdsb2IgLXJlc3VsdCB7aW52YWxpZCBiYXNl
NjQgY2hhcmFjdGVyICp9Cit0ZXN0IGJpbmFyeS03My4yOSB7YmluYXJ5IGRl
Y29kZSBiYXNlNjR9IC1ib2R5IHsKKyAgICBsaXN0IFtzdHJpbmcgbGVuZ3Ro
IFtzZXQgciBbYmluYXJ5IGRlY29kZSBiYXNlNjQgLXN0cmljdCBXRms9XG5d
XV0gJHIKK30gLXJldHVybkNvZGVzIGVycm9yIC1tYXRjaCBnbG9iIC1yZXN1
bHQge2ludmFsaWQgYmFzZTY0IGNoYXJhY3RlciAqfQordGVzdCBiaW5hcnkt
NzMuMzAge2JpbmFyeSBkZWNvZGUgYmFzZTY0fSAtYm9keSB7CisgICAgbGlz
dCBbc3RyaW5nIGxlbmd0aCBbc2V0IHIgW2JpbmFyeSBkZWNvZGUgYmFzZTY0
IC1zdHJpY3QgV0ZsYVxuXV1dICRyCit9IC1yZXR1cm5Db2RlcyBlcnJvciAt
bWF0Y2ggZ2xvYiAtcmVzdWx0IHtpbnZhbGlkIGJhc2U2NCBjaGFyYWN0ZXIg
Kn0KK3Rlc3QgYmluYXJ5LTczLjMxIHtiaW5hcnkgZGVjb2RlIGJhc2U2NH0g
LWJvZHkgeworICAgIGxpc3QgW3N0cmluZyBsZW5ndGggW3NldCByIFtiaW5h
cnkgZGVjb2RlIGJhc2U2NCBXQT09V0ZsYV1dXSAkcgorfSAtcmV0dXJuQ29k
ZXMgZXJyb3IgLW1hdGNoIGdsb2IgLXJlc3VsdCB7aW52YWxpZCBiYXNlNjQg
Y2hhcmFjdGVyICp9CiAKIHRlc3QgYmluYXJ5LTc0LjEge2JpbmFyeSBlbmNv
ZGUgdXVlbmNvZGV9IC1ib2R5IHsKICAgICBiaW5hcnkgZW5jb2RlIHV1ZW5j
b2RlCg==
====