diff --git a/apr-1.7.0-encoding.patch b/apr-1.7.0-encoding.patch new file mode 100644 index 0000000..f6c9dae --- /dev/null +++ b/apr-1.7.0-encoding.patch @@ -0,0 +1,2839 @@ + +https://svn.apache.org/viewvc?view=revision&revision=1877195 +https://svn.apache.org/viewvc?view=revision&revision=1883879 +https://svn.apache.org/viewvc?view=revision&revision=1883880 +https://svn.apache.org/viewvc?view=revision&revision=1904675 + +--- apr-1.7.0/encoding/apr_encode.c.encoding ++++ apr-1.7.0/encoding/apr_encode.c +@@ -211,19 +211,20 @@ + APR_DECLARE(apr_status_t) apr_encode_base64(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len) + { ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + const char *base; + +- if (!src) { +- return APR_NOTFOUND; ++ if (src && slen == APR_ENCODE_STRING) { ++ count = strlen(src); + } +- +- if (APR_ENCODE_STRING == slen) { +- slen = strlen(src); ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + + if (dest) { +- register char *bufout = dest; +- int i; ++ char *bufout = dest; ++ apr_size_t i = 0; + + if (0 == ((flags & APR_ENCODE_BASE64URL))) { + base = base64; +@@ -232,60 +233,64 @@ + base = base64url; + } + +- for (i = 0; i < slen - 2; i += 3) { +- *bufout++ = base[ENCODE_TO_ASCII(((src[i]) >> 2) & 0x3F)]; +- *bufout++ = base[ENCODE_TO_ASCII((((src[i]) & 0x3) << 4) +- | ((int)((src[i + 1]) & 0xF0) >> 4))]; +- *bufout++ = base[ENCODE_TO_ASCII((((src[i + 1]) & 0xF) << 2) +- | ((int)(ENCODE_TO_ASCII(src[i + 2]) & 0xC0) >> 6))]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 2]) & 0x3F)]; +- } +- if (i < slen) { +- *bufout++ = base[ENCODE_TO_ASCII(((src[i]) >> 2) & 0x3F)]; +- if (i == (slen - 1)) { +- *bufout++ = base[ENCODE_TO_ASCII((((src[i]) & 0x3) << 4))]; ++ if (count > 2) { ++ for (; i < count - 2; i += 3) { ++ *bufout++ = base[(TO_ASCII(src[i]) >> 2) & 0x3F]; ++ *bufout++ = base[((TO_ASCII(src[i]) & 0x3) << 4 | ++ (TO_ASCII(src[i + 1]) & 0xF0) >> 4)]; ++ *bufout++ = base[((TO_ASCII(src[i + 1]) & 0xF) << 2 | ++ (TO_ASCII(src[i + 2]) & 0xC0) >> 6)]; ++ *bufout++ = base[TO_ASCII(src[i + 2]) & 0x3F]; ++ } ++ } ++ if (i < count) { ++ *bufout++ = base[(TO_ASCII(src[i]) >> 2) & 0x3F]; ++ if (i == (count - 1)) { ++ *bufout++ = base[(TO_ASCII(src[i]) & 0x3) << 4]; + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; + } + } + else { +- *bufout++ = base[ENCODE_TO_ASCII((((src[i]) & 0x3) << 4) +- | ((int)((src[i + 1]) & 0xF0) >> 4))]; +- *bufout++ = base[ENCODE_TO_ASCII(((src[i + 1]) & 0xF) << 2)]; ++ *bufout++ = base[((TO_ASCII(src[i]) & 0x3) << 4 | ++ (TO_ASCII(src[i + 1]) & 0xF0) >> 4)]; ++ *bufout++ = base[(TO_ASCII(src[i + 1]) & 0xF) << 2]; + } + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; + } + } + +- if (len) { +- *len = bufout - dest; ++ dlen = bufout - dest; ++ dest[dlen] = '\0'; ++ } ++ else { ++ dlen = ((count + 2u) / 3u) * 4u + 1u; ++ if (dlen <= count) { ++ status = APR_ENOSPC; + } +- +- *bufout++ = '\0'; +- +- return APR_SUCCESS; + } + + if (len) { +- *len = ((slen + 2) / 3 * 4) + 1; ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(apr_status_t) apr_encode_base64_binary(char *dest, const unsigned char *src, + apr_ssize_t slen, int flags, apr_size_t * len) + { ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + const char *base; + +- if (!src) { +- return APR_NOTFOUND; ++ if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + + if (dest) { +- register char *bufout = dest; +- int i; ++ char *bufout = dest; ++ apr_size_t i = 0; + + if (0 == ((flags & APR_ENCODE_BASE64URL))) { + base = base64; +@@ -294,46 +299,48 @@ + base = base64url; + } + +- for (i = 0; i < slen - 2; i += 3) { +- *bufout++ = base[(src[i] >> 2) & 0x3F]; +- *bufout++ = base[((src[i] & 0x3) << 4) +- | ((int)(src[i + 1] & 0xF0) >> 4)]; +- *bufout++ = base[((src[i + 1] & 0xF) << 2) +- | ((int)(src[i + 2] & 0xC0) >> 6)]; +- *bufout++ = base[src[i + 2] & 0x3F]; ++ if (count > 2) { ++ for (; i < count - 2; i += 3) { ++ *bufout++ = base[(src[i] >> 2) & 0x3F]; ++ *bufout++ = base[((src[i] & 0x3) << 4 | ++ (src[i + 1] & 0xF0) >> 4)]; ++ *bufout++ = base[((src[i + 1] & 0xF) << 2 | ++ (src[i + 2] & 0xC0) >> 6)]; ++ *bufout++ = base[src[i + 2] & 0x3F]; ++ } + } +- if (i < slen) { ++ if (i < count) { + *bufout++ = base[(src[i] >> 2) & 0x3F]; +- if (i == (slen - 1)) { ++ if (i == (count - 1)) { + *bufout++ = base[((src[i] & 0x3) << 4)]; + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; + } + } + else { +- *bufout++ = base[((src[i] & 0x3) << 4) +- | ((int)(src[i + 1] & 0xF0) >> 4)]; +- *bufout++ = base[((src[i + 1] & 0xF) << 2)]; ++ *bufout++ = base[((src[i] & 0x3) << 4 | ++ (src[i + 1] & 0xF0) >> 4)]; ++ *bufout++ = base[(src[i + 1] & 0xF) << 2]; + } + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; + } + } + +- if (len) { +- *len = bufout - dest; ++ dlen = bufout - dest; ++ dest[dlen] = '\0'; ++ } ++ else { ++ dlen = ((count + 2u) / 3u) * 4u + 1u; ++ if (dlen <= count) { ++ status = APR_ENOSPC; + } +- +- *bufout++ = '\0'; +- +- return APR_SUCCESS; + } + + if (len) { +- *len = ((slen + 2) / 3 * 4) + 1; ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(const char *)apr_pencode_base64(apr_pool_t * p, const char *src, +@@ -341,13 +348,19 @@ + { + apr_size_t size; + ++ if (!src) { ++ return NULL; ++ } ++ + switch (apr_encode_base64(NULL, src, slen, flags, &size)) { + case APR_SUCCESS:{ + char *cmd = apr_palloc(p, size); +- apr_encode_base64(cmd, src, slen, flags, len); ++ if (cmd) { ++ apr_encode_base64(cmd, src, slen, flags, len); ++ } + return cmd; + } +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -360,13 +373,19 @@ + { + apr_size_t size; + ++ if (!src) { ++ return NULL; ++ } ++ + switch (apr_encode_base64_binary(NULL, src, slen, flags, &size)) { + case APR_SUCCESS:{ + char *cmd = apr_palloc(p, size); +- apr_encode_base64_binary(cmd, src, slen, flags, len); ++ if (cmd) { ++ apr_encode_base64_binary(cmd, src, slen, flags, len); ++ } + return cmd; + } +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -377,149 +396,184 @@ + APR_DECLARE(apr_status_t) apr_decode_base64(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len) + { +- if (!src) { +- return APR_NOTFOUND; +- } ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + +- if (APR_ENCODE_STRING == slen) { +- slen = strlen(src); ++ if (src && slen == APR_ENCODE_STRING) { ++ count = strlen(src); ++ } ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + +- if (dest) { +- register const unsigned char *bufin; +- register unsigned char *bufout; +- register apr_size_t nprbytes; +- register apr_size_t count = slen; +- +- apr_status_t status; ++ if (src) { ++ const unsigned char *bufin; + + bufin = (const unsigned char *)src; +- while (pr2six[*(bufin++)] < 64 && count) +- count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2six[*(bufin++)] > 64 && count) ++ while (count) { ++ if (pr2six[*bufin] >= 64) { ++ if (!(flags & APR_ENCODE_RELAXED)) { ++ if (count <= 2) { ++ do { ++ if (pr2six[bufin[count - 1]] <= 64) ++ break; ++ } while (--count); ++ } ++ if (count) { ++ status = APR_BADCH; ++ } ++ } ++ break; ++ } + count--; ++ bufin++; ++ } ++ count = bufin - (const unsigned char *)src; + +- status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : +- count ? APR_BADCH : APR_SUCCESS; ++ if (dest) { ++ unsigned char *bufout; + +- bufout = (unsigned char *)dest; +- bufin = (const unsigned char *)src; ++ bufout = (unsigned char *)dest; ++ bufin = (const unsigned char *)src; + +- while (nprbytes > 4) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE(pr2six[bufin[0]] << 2 +- | pr2six[bufin[1]] >> 4); +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE( +- pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE( +- pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); +- bufin += 4; +- nprbytes -= 4; +- } ++ while (count >= 4) { ++ *(bufout++) = TO_NATIVE(pr2six[bufin[0]] << 2 | ++ pr2six[bufin[1]] >> 4); ++ *(bufout++) = TO_NATIVE(pr2six[bufin[1]] << 4 | ++ pr2six[bufin[2]] >> 2); ++ *(bufout++) = TO_NATIVE(pr2six[bufin[2]] << 6 | ++ pr2six[bufin[3]]); ++ bufin += 4; ++ count -= 4; ++ } + +- if (nprbytes == 1) { +- status = APR_BADCH; +- } +- if (nprbytes > 1) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE( +- pr2six[*bufin] << 2 | pr2six[bufin[1]] >> 4); +- } +- if (nprbytes > 2) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE( +- pr2six[bufin[1]] << 4 | pr2six[bufin[2]] >> 2); +- } +- if (nprbytes > 3) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE( +- pr2six[bufin[2]] << 6 | pr2six[bufin[3]]); +- } ++ if (count == 1) { ++ status = APR_EINCOMPLETE; ++ } ++ if (count > 1) { ++ *(bufout++) = TO_NATIVE(pr2six[bufin[0]] << 2 | ++ pr2six[bufin[1]] >> 4); ++ } ++ if (count > 2) { ++ *(bufout++) = TO_NATIVE(pr2six[bufin[1]] << 4 | ++ pr2six[bufin[2]] >> 2); ++ } + +- if (len) { +- *len = bufout - (unsigned char *)dest; ++ dlen = bufout - (unsigned char *)dest; ++ dest[dlen] = '\0'; + } ++ } + +- *(bufout++) = 0; +- +- return status; ++ if (!src || !dest) { ++ dlen = (count / 4u) * 3u + 1u; ++ switch (count % 4) { ++ case 3: ++ dlen += 2; ++ break; ++ case 2: ++ dlen++; ++ break; ++ case 1: ++ status = APR_EINCOMPLETE; ++ break; ++ } + } + + if (len) { +- *len = (((int)slen + 3) / 4) * 3 + 1; ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(apr_status_t) apr_decode_base64_binary(unsigned char *dest, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len) + { +- if (!src) { +- return APR_NOTFOUND; +- } ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + +- if (APR_ENCODE_STRING == slen) { +- slen = strlen(src); ++ if (src && slen == APR_ENCODE_STRING) { ++ count = strlen(src); ++ } ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + +- if (dest) { +- register const unsigned char *bufin; +- register unsigned char *bufout; +- register apr_size_t nprbytes; +- register apr_size_t count = slen; +- +- apr_status_t status; ++ if (src) { ++ const unsigned char *bufin; + + bufin = (const unsigned char *)src; +- while (pr2six[*(bufin++)] < 64 && count) +- count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2six[*(bufin++)] > 64 && count) ++ while (count) { ++ if (pr2six[*bufin] >= 64) { ++ if (!(flags & APR_ENCODE_RELAXED)) { ++ if (count <= 2) { ++ do { ++ if (pr2six[bufin[count - 1]] <= 64) ++ break; ++ } while (--count); ++ } ++ if (count) { ++ status = APR_BADCH; ++ } ++ } ++ break; ++ } + count--; ++ bufin++; ++ } ++ count = bufin - (const unsigned char *)src; + +- status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : +- count ? APR_BADCH : APR_SUCCESS; ++ if (dest) { ++ unsigned char *bufout; + +- bufout = (unsigned char *)dest; +- bufin = (const unsigned char *)src; ++ bufout = (unsigned char *)dest; ++ bufin = (const unsigned char *)src; + +- while (nprbytes > 4) { +- *(bufout++) = (unsigned char)(pr2six[bufin[0]] << 2 +- | pr2six[bufin[1]] >> 4); +- *(bufout++) = (unsigned char)(pr2six[bufin[1]] << 4 +- | pr2six[bufin[2]] >> 2); +- *(bufout++) = (unsigned char)(pr2six[bufin[2]] << 6 +- | pr2six[bufin[3]]); +- bufin += 4; +- nprbytes -= 4; +- } ++ while (count >= 4) { ++ *(bufout++) = (pr2six[bufin[0]] << 2 | ++ pr2six[bufin[1]] >> 4); ++ *(bufout++) = (pr2six[bufin[1]] << 4 | ++ pr2six[bufin[2]] >> 2); ++ *(bufout++) = (pr2six[bufin[2]] << 6 | ++ pr2six[bufin[3]]); ++ bufin += 4; ++ count -= 4; ++ } + +- if (nprbytes == 1) { +- status = APR_BADCH; +- } +- if (nprbytes > 1) { +- *(bufout++) = (unsigned char)(pr2six[bufin[0]] << 2 +- | pr2six[bufin[1]] >> 4); +- } +- if (nprbytes > 2) { +- *(bufout++) = (unsigned char)(pr2six[bufin[1]] << 4 +- | pr2six[bufin[2]] >> 2); +- } +- if (nprbytes > 3) { +- *(bufout++) = (unsigned char)(pr2six[bufin[2]] << 6 +- | pr2six[bufin[3]]); +- } ++ if (count == 1) { ++ status = APR_EINCOMPLETE; ++ } ++ if (count > 1) { ++ *(bufout++) = (pr2six[bufin[0]] << 2 | ++ pr2six[bufin[1]] >> 4); ++ } ++ if (count > 2) { ++ *(bufout++) = (pr2six[bufin[1]] << 4 | ++ pr2six[bufin[2]] >> 2); ++ } + +- if (len) { +- *len = bufout - dest; ++ dlen = bufout - dest; + } ++ } + +- return status; ++ if (!src || !dest) { ++ dlen = (count / 4u) * 3u; ++ switch (count % 4) { ++ case 3: ++ dlen += 2; ++ break; ++ case 2: ++ dlen++; ++ break; ++ case 1: ++ status = APR_EINCOMPLETE; ++ break; ++ } + } + + if (len) { +- *len = (((int)slen + 3) / 4) * 3; ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(const char *)apr_pdecode_base64(apr_pool_t * p, const char *str, +@@ -527,14 +581,19 @@ + { + apr_size_t size; + ++ if (!str) { ++ return NULL; ++ } ++ + switch (apr_decode_base64(NULL, str, slen, flags, &size)) { + case APR_SUCCESS:{ + void *cmd = apr_palloc(p, size); +- apr_decode_base64(cmd, str, slen, flags, len); ++ if (cmd) { ++ apr_decode_base64(cmd, str, slen, flags, len); ++ } + return cmd; + } +- case APR_BADCH: +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -547,15 +606,20 @@ + { + apr_size_t size; + ++ if (!str) { ++ return NULL; ++ } ++ + switch (apr_decode_base64_binary(NULL, str, slen, flags, &size)) { + case APR_SUCCESS:{ + unsigned char *cmd = apr_palloc(p, size + 1); +- cmd[size] = 0; +- apr_decode_base64_binary(cmd, str, slen, flags, len); ++ if (cmd) { ++ apr_decode_base64_binary(cmd, str, slen, flags, len); ++ cmd[size] = 0; ++ } + return cmd; + } +- case APR_BADCH: +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -566,19 +630,20 @@ + APR_DECLARE(apr_status_t) apr_encode_base32(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len) + { ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + const char *base; + +- if (!src) { +- return APR_NOTFOUND; ++ if (src && slen == APR_ENCODE_STRING) { ++ count = strlen(src); + } +- +- if (APR_ENCODE_STRING == slen) { +- slen = strlen(src); ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + + if (dest) { +- register char *bufout = dest; +- int i; ++ char *bufout = dest; ++ apr_size_t i = 0; + + if (!((flags & APR_ENCODE_BASE32HEX))) { + base = base32; +@@ -587,24 +652,26 @@ + base = base32hex; + } + +- for (i = 0; i < slen - 4; i += 5) { +- *bufout++ = base[ENCODE_TO_ASCII((src[i] >> 3) & 0x1F)]; +- *bufout++ = base[ENCODE_TO_ASCII(((src[i] << 2) & 0x1C) +- | ((src[i + 1] >> 6) & 0x3))]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 1] >> 1) & 0x1F)]; +- *bufout++ = base[ENCODE_TO_ASCII(((src[i + 1] << 4) & 0x10) +- | ((src[i + 2] >> 4) & 0xF))]; +- *bufout++ = base[ENCODE_TO_ASCII(((src[i + 2] << 1) & 0x1E) +- | ((src[i + 3] >> 7) & 0x1))]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 3] >> 2) & 0x1F)]; +- *bufout++ = base[ENCODE_TO_ASCII(((src[i + 3] << 3) & 0x18) +- | ((src[i + 4] >> 5) & 0x7))]; +- *bufout++ = base[ENCODE_TO_ASCII(src[i + 4] & 0x1F)]; +- } +- if (i < slen) { +- *bufout++ = base[ENCODE_TO_ASCII(src[i] >> 3) & 0x1F]; +- if (i == (slen - 1)) { +- *bufout++ = base[ENCODE_TO_ASCII((src[i] << 2) & 0x1C)]; ++ if (count > 4) { ++ for (; i < count - 4; i += 5) { ++ *bufout++ = base[(TO_ASCII(src[i]) >> 3) & 0x1F]; ++ *bufout++ = base[(((TO_ASCII(src[i]) << 2) & 0x1C) | ++ ((TO_ASCII(src[i + 1]) >> 6) & 0x3))]; ++ *bufout++ = base[(TO_ASCII(src[i + 1]) >> 1) & 0x1F]; ++ *bufout++ = base[(((TO_ASCII(src[i + 1]) << 4) & 0x10) | ++ ((TO_ASCII(src[i + 2]) >> 4) & 0xF))]; ++ *bufout++ = base[(((TO_ASCII(src[i + 2]) << 1) & 0x1E) | ++ ((TO_ASCII(src[i + 3]) >> 7) & 0x1))]; ++ *bufout++ = base[(TO_ASCII(src[i + 3]) >> 2) & 0x1F]; ++ *bufout++ = base[(((TO_ASCII(src[i + 3]) << 3) & 0x18) | ++ ((TO_ASCII(src[i + 4]) >> 5) & 0x7))]; ++ *bufout++ = base[TO_ASCII(src[i + 4]) & 0x1F]; ++ } ++ } ++ if (i < count) { ++ *bufout++ = base[(TO_ASCII(src[i]) >> 3) & 0x1F]; ++ if (i == (count - 1)) { ++ *bufout++ = base[(TO_ASCII(src[i]) << 2) & 0x1C]; + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; + *bufout++ = '='; +@@ -614,11 +681,11 @@ + *bufout++ = '='; + } + } +- else if (i == (slen - 2)) { +- *bufout++ = base[ENCODE_TO_ASCII(((src[i] << 2) & 0x1C) +- | ((src[i + 1] >> 6) & 0x3))]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 1] >> 1) & 0x1F)]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 1] << 4) & 0x10)]; ++ else if (i == (count - 2)) { ++ *bufout++ = base[(((TO_ASCII(src[i]) << 2) & 0x1C) | ++ ((TO_ASCII(src[i + 1]) >> 6) & 0x3))]; ++ *bufout++ = base[(TO_ASCII(src[i + 1]) >> 1) & 0x1F]; ++ *bufout++ = base[(TO_ASCII(src[i + 1]) << 4) & 0x10]; + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; + *bufout++ = '='; +@@ -626,13 +693,13 @@ + *bufout++ = '='; + } + } +- else if (i == (slen - 3)) { +- *bufout++ = base[ENCODE_TO_ASCII(((src[i] << 2) & 0x1C) +- | ((src[i + 1] >> 6) & 0x3))]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 1] >> 1) & 0x1F)]; +- *bufout++ = base[ENCODE_TO_ASCII(((src[i + 1] << 4) & 0x10) +- | ((src[i + 2] >> 4) & 0xF))]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 2] << 1) & 0x1E)]; ++ else if (i == (count - 3)) { ++ *bufout++ = base[(((TO_ASCII(src[i]) << 2) & 0x1C) | ++ ((TO_ASCII(src[i + 1]) >> 6) & 0x3))]; ++ *bufout++ = base[(TO_ASCII(src[i + 1]) >> 1) & 0x1F]; ++ *bufout++ = base[(((TO_ASCII(src[i + 1]) << 4) & 0x10) | ++ ((TO_ASCII(src[i + 2]) >> 4) & 0xF))]; ++ *bufout++ = base[(TO_ASCII(src[i + 2]) << 1) & 0x1E]; + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; + *bufout++ = '='; +@@ -640,49 +707,51 @@ + } + } + else { +- *bufout++ = base[ENCODE_TO_ASCII(((src[i] << 2) & 0x1C) +- | ((src[i + 1] >> 6) & 0x3))]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 1] >> 1) & 0x1F)]; +- *bufout++ = base[ENCODE_TO_ASCII(((src[i + 1] << 4) & 0x10) +- | ((src[i + 2] >> 4) & 0xF))]; +- *bufout++ = base[ENCODE_TO_ASCII(((src[i + 2] << 1) & 0x1E) +- | ((src[i + 3] >> 7) & 0x1))]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 3] >> 2) & 0x1F)]; +- *bufout++ = base[ENCODE_TO_ASCII((src[i + 3] << 3) & 0x18)]; ++ *bufout++ = base[(((TO_ASCII(src[i]) << 2) & 0x1C) | ++ ((TO_ASCII(src[i + 1]) >> 6) & 0x3))]; ++ *bufout++ = base[(TO_ASCII(src[i + 1]) >> 1) & 0x1F]; ++ *bufout++ = base[(((TO_ASCII(src[i + 1]) << 4) & 0x10) | ++ ((TO_ASCII(src[i + 2]) >> 4) & 0xF))]; ++ *bufout++ = base[(((TO_ASCII(src[i + 2]) << 1) & 0x1E) | ++ ((TO_ASCII(src[i + 3]) >> 7) & 0x1))]; ++ *bufout++ = base[(TO_ASCII(src[i + 3]) >> 2) & 0x1F]; ++ *bufout++ = base[(TO_ASCII(src[i + 3]) << 3) & 0x18]; + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; + } + } + } + +- if (len) { +- *len = bufout - dest; ++ dlen = bufout - dest; ++ dest[dlen] = '\0'; ++ } ++ else { ++ dlen = ((count + 4u) / 5u) * 8u + 1u; ++ if (dlen <= count) { ++ status = APR_ENOSPC; + } +- +- *bufout++ = '\0'; +- +- return APR_SUCCESS; + } + + if (len) { +- *len = ((slen + 2) / 3 * 4) + 1; ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(apr_status_t) apr_encode_base32_binary(char *dest, const unsigned char *src, + apr_ssize_t slen, int flags, apr_size_t * len) + { ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + const char *base; + +- if (!src) { +- return APR_NOTFOUND; ++ if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + + if (dest) { +- register char *bufout = dest; +- int i; ++ char *bufout = dest; ++ apr_size_t i = 0; + + if (!((flags & APR_ENCODE_BASE32HEX))) { + base = base32; +@@ -691,23 +760,25 @@ + base = base32hex; + } + +- for (i = 0; i < slen - 4; i += 5) { +- *bufout++ = base[((src[i] >> 3) & 0x1F)]; +- *bufout++ = base[(((src[i] << 2) & 0x1C) +- | ((src[i + 1] >> 6) & 0x3))]; +- *bufout++ = base[((src[i + 1] >> 1) & 0x1F)]; +- *bufout++ = base[(((src[i + 1] << 4) & 0x10) +- | ((src[i + 2] >> 4) & 0xF))]; +- *bufout++ = base[(((src[i + 2] << 1) & 0x1E) +- | ((src[i + 3] >> 7) & 0x1))]; +- *bufout++ = base[((src[i + 3] >> 2) & 0x1F)]; +- *bufout++ = base[(((src[i + 3] << 3) & 0x18) +- | ((src[i + 4] >> 5) & 0x7))]; +- *bufout++ = base[(src[i + 4] & 0x1F)]; ++ if (count > 4) { ++ for (; i < count - 4; i += 5) { ++ *bufout++ = base[((src[i] >> 3) & 0x1F)]; ++ *bufout++ = base[(((src[i] << 2) & 0x1C) | ++ ((src[i + 1] >> 6) & 0x3))]; ++ *bufout++ = base[((src[i + 1] >> 1) & 0x1F)]; ++ *bufout++ = base[(((src[i + 1] << 4) & 0x10) | ++ ((src[i + 2] >> 4) & 0xF))]; ++ *bufout++ = base[(((src[i + 2] << 1) & 0x1E) | ++ ((src[i + 3] >> 7) & 0x1))]; ++ *bufout++ = base[((src[i + 3] >> 2) & 0x1F)]; ++ *bufout++ = base[(((src[i + 3] << 3) & 0x18) | ++ ((src[i + 4] >> 5) & 0x7))]; ++ *bufout++ = base[(src[i + 4] & 0x1F)]; ++ } + } +- if (i < slen) { ++ if (i < count) { + *bufout++ = base[(src[i] >> 3) & 0x1F]; +- if (i == (slen - 1)) { ++ if (i == (count - 1)) { + *bufout++ = base[((src[i] << 2) & 0x1C)]; + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; +@@ -718,9 +789,9 @@ + *bufout++ = '='; + } + } +- else if (i == (slen - 2)) { +- *bufout++ = base[(((src[i] << 2) & 0x1C) +- | ((src[i + 1] >> 6) & 0x3))]; ++ else if (i == (count - 2)) { ++ *bufout++ = base[(((src[i] << 2) & 0x1C) | ++ ((src[i + 1] >> 6) & 0x3))]; + *bufout++ = base[((src[i + 1] >> 1) & 0x1F)]; + *bufout++ = base[((src[i + 1] << 4) & 0x10)]; + if (!(flags & APR_ENCODE_NOPADDING)) { +@@ -730,12 +801,12 @@ + *bufout++ = '='; + } + } +- else if (i == (slen - 3)) { +- *bufout++ = base[(((src[i] << 2) & 0x1C) +- | ((src[i + 1] >> 6) & 0x3))]; ++ else if (i == (count - 3)) { ++ *bufout++ = base[(((src[i] << 2) & 0x1C) | ++ ((src[i + 1] >> 6) & 0x3))]; + *bufout++ = base[((src[i + 1] >> 1) & 0x1F)]; +- *bufout++ = base[(((src[i + 1] << 4) & 0x10) +- | ((int)(src[i + 2] >> 4) & 0xF))]; ++ *bufout++ = base[(((src[i + 1] << 4) & 0x10) | ++ ((src[i + 2] >> 4) & 0xF))]; + *bufout++ = base[((src[i + 2] << 1) & 0x1E)]; + if (!(flags & APR_ENCODE_NOPADDING)) { + *bufout++ = '='; +@@ -744,13 +815,13 @@ + } + } + else { +- *bufout++ = base[(((src[i] << 2) & 0x1C) +- | ((src[i + 1] >> 6) & 0x3))]; ++ *bufout++ = base[(((src[i] << 2) & 0x1C) | ++ ((src[i + 1] >> 6) & 0x3))]; + *bufout++ = base[((src[i + 1] >> 1) & 0x1F)]; +- *bufout++ = base[(((src[i + 1] << 4) & 0x10) +- | ((src[i + 2] >> 4) & 0xF))]; +- *bufout++ = base[(((src[i + 2] << 1) & 0x1E) +- | ((src[i + 3] >> 7) & 0x1))]; ++ *bufout++ = base[(((src[i + 1] << 4) & 0x10) | ++ ((src[i + 2] >> 4) & 0xF))]; ++ *bufout++ = base[(((src[i + 2] << 1) & 0x1E) | ++ ((src[i + 3] >> 7) & 0x1))]; + *bufout++ = base[((src[i + 3] >> 2) & 0x1F)]; + *bufout++ = base[((src[i + 3] << 3) & 0x18)]; + if (!(flags & APR_ENCODE_NOPADDING)) { +@@ -759,20 +830,20 @@ + } + } + +- if (len) { +- *len = bufout - dest; ++ dlen = bufout - dest; ++ dest[dlen] = '\0'; ++ } ++ else { ++ dlen = ((count + 4u) / 5u) * 8u + 1u; ++ if (dlen <= count) { ++ status = APR_ENOSPC; + } +- +- *bufout++ = '\0'; +- +- return APR_SUCCESS; + } + + if (len) { +- *len = ((slen + 4) / 5 * 8) + 1; ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(const char *)apr_pencode_base32(apr_pool_t * p, const char *src, +@@ -780,13 +851,19 @@ + { + apr_size_t size; + ++ if (!src) { ++ return NULL; ++ } ++ + switch (apr_encode_base32(NULL, src, slen, flags, &size)) { + case APR_SUCCESS:{ + char *cmd = apr_palloc(p, size); +- apr_encode_base32(cmd, src, slen, flags, len); ++ if (cmd) { ++ apr_encode_base32(cmd, src, slen, flags, len); ++ } + return cmd; + } +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -799,13 +876,19 @@ + { + apr_size_t size; + ++ if (!src) { ++ return NULL; ++ } ++ + switch (apr_encode_base32_binary(NULL, src, slen, flags, &size)) { + case APR_SUCCESS:{ + char *cmd = apr_palloc(p, size); +- apr_encode_base32_binary(cmd, src, slen, flags, len); ++ if (cmd) { ++ apr_encode_base32_binary(cmd, src, slen, flags, len); ++ } + return cmd; + } +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -816,24 +899,20 @@ + APR_DECLARE(apr_status_t) apr_decode_base32(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len) + { +- if (!src) { +- return APR_NOTFOUND; +- } ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + +- if (APR_ENCODE_STRING == slen) { +- slen = strlen(src); ++ if (src && slen == APR_ENCODE_STRING) { ++ count = strlen(src); ++ } ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + +- if (dest) { +- register const unsigned char *bufin; +- register unsigned char *bufout; +- register apr_size_t nprbytes; +- register apr_size_t count = slen; +- ++ if (src) { ++ const unsigned char *bufin; + const unsigned char *pr2; + +- apr_status_t status; +- + if ((flags & APR_ENCODE_BASE32HEX)) { + pr2 = pr2fivehex; + } +@@ -842,101 +921,130 @@ + } + + bufin = (const unsigned char *)src; +- while (pr2[*(bufin++)] < 32 && count) +- count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2[*(bufin++)] > 32 && count) ++ while (count) { ++ if (pr2[*bufin] >= 32) { ++ if (!(flags & APR_ENCODE_RELAXED)) { ++ if (count <= 6) { ++ do { ++ if (pr2[bufin[count - 1]] <= 32) ++ break; ++ } while (--count); ++ } ++ if (count) { ++ status = APR_BADCH; ++ } ++ } ++ break; ++ } + count--; ++ bufin++; ++ } ++ count = bufin - (const unsigned char *)src; + +- status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : +- count ? APR_BADCH : APR_SUCCESS; ++ if (dest) { ++ unsigned char *bufout; + +- bufout = (unsigned char *)dest; +- bufin = (const unsigned char *)src; ++ bufout = (unsigned char *)dest; ++ bufin = (const unsigned char *)src; + +- while (nprbytes > 8) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE(pr2[bufin[0]] << 3 +- | pr2[bufin[1]] >> 2); +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE(pr2[bufin[1]] << 6 +- | pr2[bufin[2]] << 1 | pr2[bufin[3]] >> 4); +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE(pr2[bufin[3]] << 4 +- | pr2[bufin[4]] >> 1); +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE(pr2[bufin[4]] << 7 +- | pr2[bufin[5]] << 2 | pr2[bufin[6]] >> 3); +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE(pr2[bufin[6]] << 5 +- | pr2[bufin[7]]); +- bufin += 8; +- nprbytes -= 8; +- } ++ while (count >= 8) { ++ *(bufout++) = TO_NATIVE(pr2[bufin[0]] << 3 | ++ pr2[bufin[1]] >> 2); ++ *(bufout++) = TO_NATIVE(pr2[bufin[1]] << 6 | ++ pr2[bufin[2]] << 1 | ++ pr2[bufin[3]] >> 4); ++ *(bufout++) = TO_NATIVE(pr2[bufin[3]] << 4 | ++ pr2[bufin[4]] >> 1); ++ *(bufout++) = TO_NATIVE(pr2[bufin[4]] << 7 | ++ pr2[bufin[5]] << 2 | ++ pr2[bufin[6]] >> 3); ++ *(bufout++) = TO_NATIVE(pr2[bufin[6]] << 5 | ++ pr2[bufin[7]]); ++ bufin += 8; ++ count -= 8; ++ } + +- if (nprbytes == 1) { +- status = APR_BADCH; +- } +- if (nprbytes >= 2) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE( +- pr2[bufin[0]] << 3 | pr2[bufin[1]] >> 2); +- } +- if (nprbytes == 3) { +- status = APR_BADCH; +- } +- if (nprbytes >= 4) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE( +- pr2[bufin[1]] << 6 | pr2[bufin[2]] << 1 +- | pr2[bufin[3]] >> 4); +- } +- if (nprbytes >= 5) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE(pr2[bufin[3]] << 4 +- | pr2[bufin[4]] >> 1); +- } +- if (nprbytes == 6) { +- status = APR_BADCH; +- } +- if (nprbytes >= 7) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE(pr2[bufin[4]] << 7 +- | pr2[bufin[5]] << 2 | pr2[bufin[6]] >> 3); +- } +- if (nprbytes == 8) { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE(pr2[bufin[6]] << 5 +- | pr2[bufin[7]]); +- } ++ if (count == 1) { ++ status = APR_EINCOMPLETE; ++ } ++ if (count >= 2) { ++ *(bufout++) = TO_NATIVE(pr2[bufin[0]] << 3 | ++ pr2[bufin[1]] >> 2); ++ } ++ if (count == 3) { ++ status = APR_EINCOMPLETE; ++ } ++ if (count >= 4) { ++ *(bufout++) = TO_NATIVE(pr2[bufin[1]] << 6 | ++ pr2[bufin[2]] << 1 | ++ pr2[bufin[3]] >> 4); ++ } ++ if (count >= 5) { ++ *(bufout++) = TO_NATIVE(pr2[bufin[3]] << 4 | ++ pr2[bufin[4]] >> 1); ++ } ++ if (count == 6) { ++ status = APR_EINCOMPLETE; ++ } ++ if (count >= 7) { ++ *(bufout++) = TO_NATIVE(pr2[bufin[4]] << 7 | ++ pr2[bufin[5]] << 2 | ++ pr2[bufin[6]] >> 3); ++ } + +- if (len) { +- *len = bufout - (unsigned char *)dest; ++ dlen = bufout - (unsigned char *)dest; ++ dest[dlen] = '\0'; + } ++ } + +- *(bufout++) = 0; +- +- return status; ++ if (!src || !dest) { ++ dlen = (count / 8u) * 5u + 1u; ++ switch (count % 8) { ++ case 7: ++ dlen += 4; ++ break; ++ case 6: ++ status = APR_EINCOMPLETE; ++ case 5: ++ dlen += 3; ++ break; ++ case 4: ++ dlen += 2; ++ break; ++ case 3: ++ status = APR_EINCOMPLETE; ++ case 2: ++ dlen++; ++ break; ++ case 1: ++ status = APR_EINCOMPLETE; ++ break; ++ } + } + + if (len) { +- *len = (((int)slen + 7) / 8) * 5 + 1; ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(apr_status_t) apr_decode_base32_binary(unsigned char *dest, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len) + { +- if (!src) { +- return APR_NOTFOUND; +- } ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + +- if (APR_ENCODE_STRING == slen) { +- slen = strlen(src); ++ if (src && slen == APR_ENCODE_STRING) { ++ count = strlen(src); ++ } ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + +- if (dest) { +- register const unsigned char *bufin; +- register unsigned char *bufout; +- register apr_size_t nprbytes; +- register apr_size_t count = slen; +- ++ if (src) { ++ const unsigned char *bufin; + const unsigned char *pr2; + +- apr_status_t status; +- + if ((flags & APR_ENCODE_BASE32HEX)) { + pr2 = pr2fivehex; + } +@@ -945,76 +1053,110 @@ + } + + bufin = (const unsigned char *)src; +- while (pr2[*(bufin++)] < 32 && count) +- count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2[*(bufin++)] > 32 && count) ++ while (count) { ++ if (pr2[*bufin] >= 32) { ++ if (!(flags & APR_ENCODE_RELAXED)) { ++ if (count <= 6) { ++ do { ++ if (pr2[bufin[count - 1]] <= 32) ++ break; ++ } while (--count); ++ } ++ if (count) { ++ status = APR_BADCH; ++ } ++ } ++ break; ++ } + count--; ++ bufin++; ++ } ++ count = bufin - (const unsigned char *)src; + +- status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : +- count ? APR_BADCH : APR_SUCCESS; ++ if (dest) { ++ unsigned char *bufout; + +- bufout = (unsigned char *)dest; +- bufin = (const unsigned char *)src; ++ bufout = (unsigned char *)dest; ++ bufin = (const unsigned char *)src; + +- while (nprbytes > 8) { +- *(bufout++) = (unsigned char)(pr2[bufin[0]] << 3 +- | pr2[bufin[1]] >> 2); +- *(bufout++) = (unsigned char)(pr2[bufin[1]] << 6 +- | pr2[bufin[2]] << 1 | pr2[bufin[3]] >> 4); +- *(bufout++) = (unsigned char)(pr2[bufin[3]] << 4 +- | pr2[bufin[4]] >> 1); +- *(bufout++) = (unsigned char)(pr2[bufin[4]] << 7 +- | pr2[bufin[5]] << 2 | pr2[bufin[6]] >> 3); +- *(bufout++) = (unsigned char)(pr2[bufin[6]] << 5 +- | pr2[bufin[7]]); +- bufin += 8; +- nprbytes -= 8; +- } ++ while (count >= 8) { ++ *(bufout++) = (pr2[bufin[0]] << 3 | ++ pr2[bufin[1]] >> 2); ++ *(bufout++) = (pr2[bufin[1]] << 6 | ++ pr2[bufin[2]] << 1 | ++ pr2[bufin[3]] >> 4); ++ *(bufout++) = (pr2[bufin[3]] << 4 | ++ pr2[bufin[4]] >> 1); ++ *(bufout++) = (pr2[bufin[4]] << 7 | ++ pr2[bufin[5]] << 2 | ++ pr2[bufin[6]] >> 3); ++ *(bufout++) = (pr2[bufin[6]] << 5 | ++ pr2[bufin[7]]); ++ bufin += 8; ++ count -= 8; ++ } + +- if (nprbytes == 1) { +- status = APR_BADCH; +- } +- if (nprbytes >= 2) { +- *(bufout++) = (unsigned char)( +- pr2[bufin[0]] << 3 | pr2[bufin[1]] >> 2); +- } +- if (nprbytes == 3) { +- status = APR_BADCH; +- } +- if (nprbytes >= 4) { +- *(bufout++) = (unsigned char)( +- pr2[bufin[1]] << 6 | pr2[bufin[2]] << 1 +- | pr2[bufin[3]] >> 4); +- } +- if (nprbytes >= 5) { +- *(bufout++) = (unsigned char)(pr2[bufin[3]] << 4 +- | pr2[bufin[4]] >> 1); +- } +- if (nprbytes == 6) { +- status = APR_BADCH; +- } +- if (nprbytes >= 7) { +- *(bufout++) = (unsigned char)(pr2[bufin[4]] << 7 +- | pr2[bufin[5]] << 2 | pr2[bufin[6]] >> 3); +- } +- if (nprbytes == 8) { +- *(bufout++) = (unsigned char)(pr2[bufin[6]] << 5 +- | pr2[bufin[7]]); +- } ++ if (count == 1) { ++ status = APR_EINCOMPLETE; ++ } ++ if (count >= 2) { ++ *(bufout++) = (pr2[bufin[0]] << 3 | ++ pr2[bufin[1]] >> 2); ++ } ++ if (count == 3) { ++ status = APR_EINCOMPLETE; ++ } ++ if (count >= 4) { ++ *(bufout++) = (pr2[bufin[1]] << 6 | ++ pr2[bufin[2]] << 1 | ++ pr2[bufin[3]] >> 4); ++ } ++ if (count >= 5) { ++ *(bufout++) = (pr2[bufin[3]] << 4 | ++ pr2[bufin[4]] >> 1); ++ } ++ if (count == 6) { ++ status = APR_EINCOMPLETE; ++ } ++ if (count >= 7) { ++ *(bufout++) = (pr2[bufin[4]] << 7 | ++ pr2[bufin[5]] << 2 | ++ pr2[bufin[6]] >> 3); ++ } + +- if (len) { +- *len = bufout - dest; ++ dlen = bufout - dest; + } ++ } + +- return status; ++ if (!src || !dest) { ++ dlen = (count / 8u) * 5u; ++ switch (count % 8) { ++ case 7: ++ dlen += 4; ++ break; ++ case 6: ++ status = APR_EINCOMPLETE; ++ case 5: ++ dlen += 3; ++ break; ++ case 4: ++ dlen += 2; ++ break; ++ case 3: ++ status = APR_EINCOMPLETE; ++ case 2: ++ dlen++; ++ break; ++ case 1: ++ status = APR_EINCOMPLETE; ++ break; ++ } + } + + if (len) { +- *len = (((int)slen + 7) / 8) * 5; ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(const char *)apr_pdecode_base32(apr_pool_t * p, const char *str, +@@ -1022,14 +1164,19 @@ + { + apr_size_t size; + ++ if (!str) { ++ return NULL; ++ } ++ + switch (apr_decode_base32(NULL, str, slen, flags, &size)) { + case APR_SUCCESS:{ + void *cmd = apr_palloc(p, size); +- apr_decode_base32(cmd, str, slen, flags, len); ++ if (cmd) { ++ apr_decode_base32(cmd, str, slen, flags, len); ++ } + return cmd; + } +- case APR_BADCH: +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -1042,15 +1189,20 @@ + { + apr_size_t size; + ++ if (!str) { ++ return NULL; ++ } ++ + switch (apr_decode_base32_binary(NULL, str, slen, flags, &size)) { + case APR_SUCCESS:{ + unsigned char *cmd = apr_palloc(p, size + 1); +- cmd[size] = 0; +- apr_decode_base32_binary(cmd, str, slen, flags, len); ++ if (cmd) { ++ apr_decode_base32_binary(cmd, str, slen, flags, len); ++ cmd[size] = 0; ++ } + return cmd; + } +- case APR_BADCH: +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -1061,16 +1213,20 @@ + APR_DECLARE(apr_status_t) apr_encode_base16(char *dest, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len) + { +- const char *in = src; +- apr_size_t size; ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + +- if (!src) { +- return APR_NOTFOUND; ++ if (src && slen == APR_ENCODE_STRING) { ++ count = strlen(src); ++ } ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + + if (dest) { +- register char *bufout = dest; ++ char *bufout = dest; + const char *base; ++ apr_size_t i; + + if ((flags & APR_ENCODE_LOWER)) { + base = base16lower; +@@ -1079,51 +1235,51 @@ + base = base16; + } + +- for (size = 0; (APR_ENCODE_STRING == slen) ? in[size] : size < slen; size++) { +- if ((flags & APR_ENCODE_COLON) && size) { ++ for (i = 0; i < count; i++) { ++ if ((flags & APR_ENCODE_COLON) && i) { + *(bufout++) = ':'; + } +- *(bufout++) = base[(const unsigned char)(ENCODE_TO_ASCII(in[size])) >> 4]; +- *(bufout++) = base[(const unsigned char)(ENCODE_TO_ASCII(in[size])) & 0xf]; ++ *(bufout++) = base[TO_ASCII(src[i]) >> 4]; ++ *(bufout++) = base[TO_ASCII(src[i]) & 0xf]; + } + +- if (len) { +- *len = bufout - dest; ++ dlen = bufout - dest; ++ dest[dlen] = '\0'; ++ } ++ else { ++ dlen = count * 2u + 1u; ++ if (dlen <= count) { ++ status = APR_ENOSPC; ++ } ++ if ((flags & APR_ENCODE_COLON) && count > 1) { ++ apr_size_t more = dlen + count - 1; ++ if (more <= dlen) { ++ status = APR_ENOSPC; ++ } ++ dlen = more; + } +- +- *bufout = '\0'; +- +- return APR_SUCCESS; + } + + if (len) { +- if (APR_ENCODE_STRING == slen) { +- slen = strlen(src); +- } +- if ((flags & APR_ENCODE_COLON) && slen) { +- *len = slen * 3; +- } +- else { +- *len = slen * 2 + 1; +- } ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(apr_status_t) apr_encode_base16_binary(char *dest, + const unsigned char *src, apr_ssize_t slen, int flags, apr_size_t * len) + { +- const unsigned char *in = src; +- apr_size_t size; ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + +- if (!src) { +- return APR_NOTFOUND; ++ if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + + if (dest) { +- register char *bufout = dest; ++ char *bufout = dest; + const char *base; ++ apr_size_t i; + + if ((flags & APR_ENCODE_LOWER)) { + base = base16lower; +@@ -1132,33 +1288,35 @@ + base = base16; + } + +- for (size = 0; size < slen; size++) { +- if ((flags & APR_ENCODE_COLON) && size) { ++ for (i = 0; i < count; i++) { ++ if ((flags & APR_ENCODE_COLON) && i) { + *(bufout++) = ':'; + } +- *(bufout++) = base[in[size] >> 4]; +- *(bufout++) = base[in[size] & 0xf]; ++ *(bufout++) = base[src[i] >> 4]; ++ *(bufout++) = base[src[i] & 0xf]; + } + +- if (len) { +- *len = bufout - dest; ++ dlen = bufout - dest; ++ dest[dlen] = '\0'; ++ } ++ else { ++ dlen = count * 2u + 1u; ++ if (dlen <= count) { ++ status = APR_ENOSPC; ++ } ++ if ((flags & APR_ENCODE_COLON) && count > 1) { ++ apr_size_t more = dlen + count - 1; ++ if (more <= dlen) { ++ status = APR_ENOSPC; ++ } ++ dlen = more; + } +- +- *bufout = 0; +- +- return APR_SUCCESS; + } + + if (len) { +- if ((flags & APR_ENCODE_COLON) && slen) { +- *len = slen * 3; +- } +- else { +- *len = slen * 2 + 1; +- } ++ *len = dlen; + } +- +- return APR_SUCCESS; ++ return status; + } + + APR_DECLARE(const char *)apr_pencode_base16(apr_pool_t * p, +@@ -1166,13 +1324,19 @@ + { + apr_size_t size; + ++ if (!src) { ++ return NULL; ++ } ++ + switch (apr_encode_base16(NULL, src, slen, flags, &size)) { + case APR_SUCCESS:{ + char *cmd = apr_palloc(p, size); +- apr_encode_base16(cmd, src, slen, flags, len); ++ if (cmd) { ++ apr_encode_base16(cmd, src, slen, flags, len); ++ } + return cmd; + } +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -1186,13 +1350,19 @@ + { + apr_size_t size; + ++ if (!src) { ++ return NULL; ++ } ++ + switch (apr_encode_base16_binary(NULL, src, slen, flags, &size)) { + case APR_SUCCESS:{ + char *cmd = apr_palloc(p, size); +- apr_encode_base16_binary(cmd, src, slen, flags, len); ++ if (cmd) { ++ apr_encode_base16_binary(cmd, src, slen, flags, len); ++ } + return cmd; + } +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -1203,178 +1373,156 @@ + APR_DECLARE(apr_status_t) apr_decode_base16(char *dest, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len) + { +- register const unsigned char *bufin; +- register unsigned char *bufout; +- register apr_size_t nprbytes; +- register apr_size_t count; +- +- apr_status_t status; ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + +- if (!src) { +- return APR_NOTFOUND; ++ if (src && slen == APR_ENCODE_STRING) { ++ count = strlen(src); + } +- +- if (APR_ENCODE_STRING == slen) { +- slen = strlen(src); ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + +- count = slen; +- bufin = (const unsigned char *)src; +- while (pr2two[*(bufin++)] != 16 && count) +- count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2two[*(bufin++)] > 16 && count) +- count--; +- +- status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : +- count ? APR_BADCH : APR_SUCCESS; +- +- if (dest) { ++ if (src) { ++ const unsigned char *bufin; + +- bufout = (unsigned char *)dest; + bufin = (const unsigned char *)src; +- +- while (nprbytes >= 2) { +- if (pr2two[bufin[0]] > 16) { +- bufin += 1; +- nprbytes -= 1; +- } +- else { +- *(bufout++) = (unsigned char)ENCODE_TO_NATIVE( +- pr2two[bufin[0]] << 4 | pr2two[bufin[1]]); +- bufin += 2; +- nprbytes -= 2; ++ while (count) { ++ if (pr2two[*bufin] >= 16 ++ && (!(flags & APR_ENCODE_COLON) ++ || pr2two[*bufin] != 32 /* ':' */)) { ++ if (!(flags & APR_ENCODE_RELAXED)) { ++ status = APR_BADCH; ++ } ++ break; + } ++ count--; ++ bufin++; + } ++ count = bufin - (const unsigned char *)src; + +- if (nprbytes == 1) { +- status = APR_BADCH; +- } +- +- if (len) { +- *len = bufout - (unsigned char *)dest; +- } +- +- *(bufout++) = 0; ++ if (dest) { ++ unsigned char *bufout; + +- return status; +- } ++ bufout = (unsigned char *)dest; ++ bufin = (const unsigned char *)src; + +- else { +- +- count = 0; +- bufin = (const unsigned char *)src; +- +- while (nprbytes >= 2) { +- if (pr2two[bufin[0]] > 16) { +- bufin += 1; +- nprbytes -= 1; ++ while (count >= 2) { ++ if (pr2two[bufin[0]] == 32 /* ':' */) { ++ bufin += 1; ++ count -= 1; ++ } ++ else { ++ *(bufout++) = TO_NATIVE(pr2two[bufin[0]] << 4 | ++ pr2two[bufin[1]]); ++ bufin += 2; ++ count -= 2; ++ } + } +- else { +- count++; +- bufin += 2; +- nprbytes -= 2; ++ ++ if (count == 1) { ++ status = APR_EINCOMPLETE; + } +- } + +- if (nprbytes == 1) { +- status = APR_BADCH; ++ dlen = bufout - (unsigned char *)dest; ++ dest[dlen] = '\0'; + } ++ } + +- if (len) { +- *len = count + 1; ++ if (!src || !dest) { ++ if (flags & APR_ENCODE_COLON) { ++ if (count && (count + 1u) % 3u) { ++ status = APR_EINCOMPLETE; ++ } ++ count -= count / 3u; + } +- +- return status; ++ if (count % 2u) { ++ status = APR_EINCOMPLETE; ++ } ++ dlen = count / 2u + 1u; + } + ++ if (len) { ++ *len = dlen; ++ } ++ return status; + } + + APR_DECLARE(apr_status_t) apr_decode_base16_binary(unsigned char *dest, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len) + { +- register const unsigned char *bufin; +- register unsigned char *bufout; +- register apr_size_t nprbytes; +- register apr_size_t count; ++ apr_status_t status = APR_SUCCESS; ++ apr_size_t count = slen, dlen = 0; + +- apr_status_t status; +- +- if (!src) { +- return APR_NOTFOUND; ++ if (src && slen == APR_ENCODE_STRING) { ++ count = strlen(src); + } +- +- if (APR_ENCODE_STRING == slen) { +- slen = strlen(src); ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + +- count = slen; +- bufin = (const unsigned char *)src; +- while (pr2two[*(bufin++)] != 16 && count) +- count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2two[*(bufin++)] > 16 && count) +- count--; ++ if (src) { ++ const unsigned char *bufin; + +- status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : +- count ? APR_BADCH : APR_SUCCESS; +- +- if (dest) { +- +- bufout = (unsigned char *)dest; + bufin = (const unsigned char *)src; +- +- while (nprbytes >= 2) { +- if (pr2two[bufin[0]] > 16) { +- bufin += 1; +- nprbytes -= 1; +- } +- else { +- *(bufout++) = (unsigned char)( +- pr2two[bufin[0]] << 4 | pr2two[bufin[1]]); +- bufin += 2; +- nprbytes -= 2; ++ while (count) { ++ if (pr2two[*bufin] >= 16 ++ && (!(flags & APR_ENCODE_COLON) ++ || pr2two[*bufin] != 32 /* ':' */)) { ++ if (!(flags & APR_ENCODE_RELAXED)) { ++ status = APR_BADCH; ++ } ++ break; + } ++ count--; ++ bufin++; + } ++ count = bufin - (const unsigned char *)src; + +- if (nprbytes == 1) { +- status = APR_BADCH; +- } +- +- if (len) { +- *len = bufout - (unsigned char *)dest; +- } +- +- return status; +- } ++ if (dest) { ++ unsigned char *bufout; + +- else { ++ bufout = (unsigned char *)dest; ++ bufin = (const unsigned char *)src; + +- count = 0; +- bufin = (const unsigned char *)src; +- +- while (nprbytes >= 2) { +- if (pr2two[bufin[0]] > 16) { +- bufin += 1; +- nprbytes -= 1; ++ while (count >= 2) { ++ if (pr2two[bufin[0]] == 32 /* ':' */) { ++ bufin += 1; ++ count -= 1; ++ } ++ else { ++ *(bufout++) = (pr2two[bufin[0]] << 4 | ++ pr2two[bufin[1]]); ++ bufin += 2; ++ count -= 2; ++ } + } +- else { +- count++; +- bufin += 2; +- nprbytes -= 2; ++ ++ if (count == 1) { ++ status = APR_EINCOMPLETE; + } +- } + +- if (nprbytes == 1) { +- status = APR_BADCH; ++ dlen = bufout - (unsigned char *)dest; + } ++ } + +- if (len) { +- *len = count; ++ if (!src || !dest) { ++ if (flags & APR_ENCODE_COLON) { ++ if (count && (count + 1u) % 3u) { ++ status = APR_EINCOMPLETE; ++ } ++ count -= count / 3u; ++ } ++ if (count % 2u) { ++ status = APR_EINCOMPLETE; + } ++ dlen = count / 2u; ++ } + +- return status; ++ if (len) { ++ *len = dlen; + } ++ return status; + } + + APR_DECLARE(const char *)apr_pdecode_base16(apr_pool_t * p, +@@ -1382,14 +1530,19 @@ + { + apr_size_t size; + ++ if (!str) { ++ return NULL; ++ } ++ + switch (apr_decode_base16(NULL, str, slen, flags, &size)) { + case APR_SUCCESS:{ + void *cmd = apr_palloc(p, size); +- apr_decode_base16(cmd, str, slen, flags, len); ++ if (cmd) { ++ apr_decode_base16(cmd, str, slen, flags, len); ++ } + return cmd; + } +- case APR_BADCH: +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +@@ -1402,15 +1555,20 @@ + { + apr_size_t size; + ++ if (!str) { ++ return NULL; ++ } ++ + switch (apr_decode_base16_binary(NULL, str, slen, flags, &size)) { + case APR_SUCCESS:{ + unsigned char *cmd = apr_palloc(p, size + 1); +- cmd[size] = 0; +- apr_decode_base16_binary(cmd, str, slen, flags, len); ++ if (cmd) { ++ apr_decode_base16_binary(cmd, str, slen, flags, len); ++ cmd[size] = 0; ++ } + return cmd; + } +- case APR_BADCH: +- case APR_NOTFOUND:{ ++ default:{ + break; + } + } +--- apr-1.7.0/encoding/apr_escape.c.encoding ++++ apr-1.7.0/encoding/apr_escape.c +@@ -131,7 +131,7 @@ + xstr[2]=what[0]; + xstr[3]=what[1]; + xstr[4]='\0'; +- digit = ENCODE_TO_NATIVE[0xFF & strtol(xstr, NULL, 16)]; ++ digit = TO_NATIVE(strtol(xstr, NULL, 16)); + #endif /*APR_CHARSET_EBCDIC*/ + return (digit); + } +@@ -716,7 +716,7 @@ + size--; + } + else { +- *d = ENCODE_TO_ASCII(val); ++ *d = TO_ASCII(val); + found = 1; + } + } +@@ -737,7 +737,7 @@ + *d = '&'; /* unknown */ + } + else { +- *d = ENCODE_TO_ASCII(((const unsigned char *) ents)[j]); ++ *d = TO_ASCII(ents[j]); + s += i; + slen -= i; + found = 1; +--- apr-1.7.0/include/apr_encode.h.encoding ++++ apr-1.7.0/include/apr_encode.h +@@ -146,35 +146,44 @@ + + /** + * Convert text data to base64. +- * @param dest The destination string, can be NULL. +- * @param src The original string. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for encoding. ++ * @param src The original string, can be NULL if \c dest is NULL and \c slen ++ * is positive or nul. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 64 Encoding. If + * APR_ENCODE_NOPADDING, omit the = padding character. If APR_ENCODE_URL, + * use RFC4648 Base 64 Encoding with URL and Filename Safe Alphabet. +- * If APR_ENCODE_BASE64URL, use RFC7515 base64url Encoding. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination string, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL. ++ * If APR_ENCODE_BASE64URL, use RFC7515 base64url Encoding. ++ * @param len If not NULL, outputs the length of the buffer needed for encoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the encoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is not APR_ENCODE_STRING and ++ * negative, or APR_NOTFOUND if \c dest is not NULL and \c src is NULL, or ++ * APR_ENOSPC if \c dest is NULL and the source length (based on \c slen or ++ * APR_ENCODE_STRING) is too big to encode. + */ + APR_DECLARE(apr_status_t) apr_encode_base64(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len); + + /** + * Convert binary data to base64. +- * @param dest The destination string, can be NULL. +- * @param src The original buffer. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for encoding. ++ * @param src The original buffer, can be NULL if \c dest is NULL. + * @param slen The length of the original buffer. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 64 Encoding. If + * APR_ENCODE_NOPADDING, omit the = padding character. If APR_ENCODE_URL, + * use RFC4648 Base 64 Encoding with URL and Filename Safe Alphabet. +- * If APR_ENCODE_BASE64URL, use RFC7515 base64url Encoding. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination string, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL. ++ * If APR_ENCODE_BASE64URL, use RFC7515 base64url Encoding. ++ * @param len If not NULL, outputs the length of the buffer needed for encoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the encoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is negative, or APR_NOTFOUND ++ * if \c dest is not NULL and \c src is NULL, or APR_ENOSPC if \c dest is NULL ++ * and the source length (based on \c slen or APR_ENCODE_STRING) is too big to ++ * encode. + */ + APR_DECLARE(apr_status_t) apr_encode_base64_binary(char *dest, const unsigned char *src, + apr_ssize_t slen, int flags, apr_size_t * len); +@@ -184,15 +193,16 @@ + * @param p Pool to allocate from. + * @param src The original string. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 64 Encoding. If + * APR_ENCODE_NOPADDING, omit the = padding character. If APR_ENCODE_URL, + * use RFC4648 Base 64 Encoding with URL and Filename Safe Alphabet. +- * If APR_ENCODE_BASE64URL, use RFC7515 base64url Encoding. +- * @param len If present, returns the number of characters written excluding +- * the zero pad. +- * @return A zero padded string allocated from the pool on success, or +- * NULL if src was NULL. ++ * If APR_ENCODE_BASE64URL, use RFC7515 base64url Encoding. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the encoding is not ++ * possible (see apr_encode_base64 errors). + */ + APR_DECLARE(const char *)apr_pencode_base64(apr_pool_t * p, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len)__attribute__((nonnull(1))); +@@ -205,47 +215,62 @@ + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 64 Encoding. If + * APR_ENCODE_NOPADDING, omit the = padding character. If APR_ENCODE_URL, + * use RFC4648 Base 64 Encoding with URL and Filename Safe Alphabet. +- * If APR_ENCODE_BASE64URL, use RFC7515 base64url Encoding. +- * @param len If present, returns the number of characters written excluding +- * the zero pad. +- * @return A zero padded string allocated from the pool on success, or +- * NULL if src was NULL. ++ * If APR_ENCODE_BASE64URL, use RFC7515 base64url Encoding. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the encoding is not ++ * possible (see apr_encode_base64_binary errors). + */ + APR_DECLARE(const char *)apr_pencode_base64_binary(apr_pool_t * p, const unsigned char *src, + apr_ssize_t slen, int flags, apr_size_t * len)__attribute__((nonnull(1))); + + /** + * Convert base64 or base64url with or without padding to text data. +- * @param dest The destination string, can be NULL. +- * @param src The original string. +- * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. +- * @param flags If APR_ENCODE_NONE, attempt to decode the full original buffer, ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for decoding. ++ * @param src The base64 string, can be NULL if \c dest is NULL and \c slen ++ * is positive or nul. ++ * @param slen The length of the base64 string, or APR_ENCODE_STRING if ++ * the actual length should be computed based on NUL termination. ++ * @param flags If APR_ENCODE_NONE, attempt to decode the full base64 string, + * and return NULL if any bad character is detected. If APR_ENCODE_RELAXED, + * decode until the first non base64/base64url character. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination string, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL, or APR_BADCH +- * if a non hex character is present. ++ * @param len If not NULL, outputs the length of the buffer needed for decoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the decoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is not APR_ENCODE_STRING and ++ * negative, or APR_NOTFOUND if \c dest is not NULL and \c src is NULL, or ++ * APR_ENOSPC if \c dest is NULL and the source length (based on \c slen or ++ * APR_ENCODE_STRING) is too big to decode, or APR_EINCOMPLETE if the source ++ * length (based on \c slen or APR_ENCODE_STRING) is invalid for a base64 ++ * encoding, or APR_BADCH if a non base64 character is present and ++ * APR_ENCODE_RELAXED is not specified. + */ + APR_DECLARE(apr_status_t) apr_decode_base64(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len); + + /** + * Convert base64 or base64url with or without padding to binary data. +- * @param dest The destination buffer, can be NULL. +- * @param src The original string. +- * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. +- * @param flags If APR_ENCODE_NONE, attempt to decode the full original buffer, ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for decoding. ++ * @param src The base64 string, can be NULL if \c dest is NULL and \c slen ++ * is positive or nul. ++ * @param slen The length of the base64 string, or APR_ENCODE_STRING if ++ * the actual length should be computed based on NUL termination. ++ * @param flags If APR_ENCODE_NONE, attempt to decode the full base64 string, + * and return NULL if any bad character is detected. If APR_ENCODE_RELAXED, + * decode until the first non base64/base64url character. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination buffer, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the src was NULL, or APR_BADCH +- * if a non base64 character is present. ++ * @param len If not NULL, outputs the length of the buffer needed for decoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the decoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is not APR_ENCODE_STRING and ++ * negative, or APR_NOTFOUND if \c dest is not NULL and \c src is NULL, or ++ * APR_ENOSPC if \c dest is NULL and the source length (based on \c slen or ++ * APR_ENCODE_STRING) is too big to decode, or APR_EINCOMPLETE if the source ++ * length (based on \c slen or APR_ENCODE_STRING) is invalid for a base64 ++ * encoding, or APR_BADCH if a non base64 character is present and ++ * APR_ENCODE_RELAXED is not specified. + */ + APR_DECLARE(apr_status_t) apr_decode_base64_binary(unsigned char *dest, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len); +@@ -255,15 +280,16 @@ + * return the results from a pool. + * @param p Pool to allocate from. + * @param src The base64 string to decode. +- * @param slen The length of the base64 string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * @param slen The length of the original string, or APR_ENCODE_STRING if ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, attempt to decode the full original buffer, + * and return NULL if any bad character is detected. If APR_ENCODE_RELAXED, + * decode until the first non base64/base64url character. +- * @param len If present, returns the number of characters written, excluding +- * the zero padding. +- * @return A string allocated from the pool containing the result with a zero +- * pad. If src was NULL, or an error occurred, NULL is returned. ++ * @param len If not NULL, outputs the length of the decoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the decoding is not ++ * possible (see apr_decode_base64_binary errors). + */ + APR_DECLARE(const char *)apr_pdecode_base64(apr_pool_t * p, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len) +@@ -273,16 +299,17 @@ + * Convert base64 or base64url with or without padding to binary data, and + * return the results from a pool. + * @param p Pool to allocate from. +- * @param src The original string. ++ * @param src The base64 string to decode. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, attempt to decode the full original buffer, + * and return NULL if any bad character is detected. If APR_ENCODE_RELAXED, + * decode until the first non base64/base64url character. +- * @param len If present, returns the number of characters written, excluding +- * the zero padding. +- * @return A buffer allocated from the pool containing the result with a zero +- * pad. If src was NULL, or an error occurred, NULL is returned. ++ * @param len If not NULL, outputs the length of the decoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the decoding is not ++ * possible (see apr_decode_base64_binary errors). + */ + APR_DECLARE(const unsigned char *)apr_pdecode_base64_binary(apr_pool_t * p, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len) +@@ -290,33 +317,42 @@ + + /** + * Convert text data to base32. +- * @param dest The destination string, can be NULL. +- * @param src The original string. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for encoding. ++ * @param src The original string, can be NULL if \c dest is NULL and \c slen ++ * is positive or nul. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 32 Encoding. If + * APR_ENCODE_NOPADDING, omit the = padding character. If APR_ENCODE_BASE32HEX, + * use RFC4648 base32hex Encoding. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination string, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL. ++ * @param len If not NULL, outputs the length of the buffer needed for encoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the encoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is not APR_ENCODE_STRING and ++ * negative, or APR_NOTFOUND if \c dest is not NULL and \c src is NULL, or ++ * APR_ENOSPC if \c dest is NULL and the source length (based on \c slen or ++ * APR_ENCODE_STRING) is too big to encode. + */ + APR_DECLARE(apr_status_t) apr_encode_base32(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len); + + /** + * Convert binary data to base32. +- * @param dest The destination string, can be NULL. +- * @param src The original buffer. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for encoding. ++ * @param src The original buffer, can be NULL if \c dest is NULL. + * @param slen The length of the original buffer. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 32 Encoding. If + * APR_ENCODE_NOPADDING, omit the = padding character. If APR_ENCODE_BASE32HEX, + * use RFC4648 base32hex Encoding. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination string, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL. ++ * @param len If not NULL, outputs the length of the buffer needed for encoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the encoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is negative, or APR_NOTFOUND ++ * if \c dest is not NULL and \c src is NULL, or APR_ENOSPC if \c dest is NULL ++ * and the source length (based on \c slen or APR_ENCODE_STRING) is too big to ++ * encode. + */ + APR_DECLARE(apr_status_t) apr_encode_base32_binary(char *dest, const unsigned char *src, + apr_ssize_t slen, int flags, apr_size_t * len); +@@ -326,14 +362,15 @@ + * @param p Pool to allocate from. + * @param src The original string. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 32 Encoding. If + * APR_ENCODE_NOPADDING, omit the = padding character. If APR_ENCODE_BASE32HEX, + * use RFC4648 base32hex Encoding. +- * @param len If present, returns the number of characters written excluding +- * the zero pad. +- * @return A zero padded string allocated from the pool on success, or +- * NULL if src was NULL. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the encoding is not ++ * possible (see apr_encode_base32 errors). + */ + APR_DECLARE(const char *)apr_pencode_base32(apr_pool_t * p, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len) +@@ -346,11 +383,12 @@ + * @param slen The length of the original buffer. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 32 Encoding. If + * APR_ENCODE_NOPADDING, omit the = padding character. If APR_ENCODE_BASE32HEX, +- * use RFC7515 base32hex Encoding. +- * @param len If present, returns the number of characters written excluding +- * the zero pad. +- * @return A zero padded string allocated from the pool on success, or +- * NULL if src was NULL. ++ * use RFC4648 base32hex Encoding. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the encoding is not ++ * possible (see apr_encode_base32_binary errors). + */ + APR_DECLARE(const char *)apr_pencode_base32_binary(apr_pool_t * p, const unsigned char *src, + apr_ssize_t slen, int flags, apr_size_t * len) +@@ -358,34 +396,48 @@ + + /** + * Convert base32 or base32hex with or without padding to text data. +- * @param dest The destination string, can be NULL. +- * @param src The original string. +- * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for decoding. ++ * @param src The base32 string, can be NULL if \c dest is NULL and \c slen ++ * is positive or nul. ++ * @param slen The length of the base32 string, or APR_ENCODE_STRING if ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, parse RFC4648 Base 32 Encoding. If + * APR_ENCODE_BASE32HEX, use RFC4648 base32hex Encoding. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination buffer, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL, or APR_BADCH +- * if a non base32 character is present. ++ * @param len If not NULL, outputs the length of the buffer needed for decoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the decoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is not APR_ENCODE_STRING and ++ * negative, or APR_NOTFOUND if \c dest is not NULL and \c src is NULL, or ++ * APR_ENOSPC if \c dest is NULL and the source length (based on \c slen or ++ * APR_ENCODE_STRING) is too big to decode, or APR_EINCOMPLETE if the source ++ * length (based on \c slen or APR_ENCODE_STRING) is invalid for a base32 ++ * encoding, or APR_BADCH if a non base32 character is present and ++ * APR_ENCODE_RELAXED is not specified. + */ + APR_DECLARE(apr_status_t) apr_decode_base32(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len); + + /** + * Convert base32 or base32hex with or without padding to binary data. +- * @param dest The destination buffer, can be NULL. +- * @param src The original string. +- * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for decoding. ++ * @param src The base32 string, can be NULL if \c dest is NULL and \c slen ++ * is positive or nul. ++ * @param slen The length of the base32 string, or APR_ENCODE_STRING if ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, parse RFC4648 Base 32 Encoding. If + * APR_ENCODE_BASE32HEX, use RFC4648 base32hex Encoding. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination buffer, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the src was NULL, or APR_BADCH +- * if a non base32 character is present. ++ * @param len If not NULL, outputs the length of the buffer needed for decoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the decoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is not APR_ENCODE_STRING and ++ * negative, or APR_NOTFOUND if \c dest is not NULL and \c src is NULL, or ++ * APR_ENOSPC if \c dest is NULL and the source length (based on \c slen or ++ * APR_ENCODE_STRING) is too big to decode, or APR_EINCOMPLETE if the source ++ * length (based on \c slen or APR_ENCODE_STRING) is invalid for a base32 ++ * encoding, or APR_BADCH if a non base32 character is present and ++ * APR_ENCODE_RELAXED is not specified. + */ + APR_DECLARE(apr_status_t) apr_decode_base32_binary(unsigned char *dest, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len); +@@ -395,14 +447,15 @@ + * return the results from a pool. + * @param p Pool to allocate from. + * @param src The base32 string to decode. +- * @param slen The length of the base32 string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * @param slen The length of the original string, or APR_ENCODE_STRING if ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, parse RFC4648 Base 32 Encoding. If + * APR_ENCODE_BASE32HEX, use RFC4648 base32hex Encoding. +- * @param len If present, returns the number of characters written, excluding +- * the zero padding. +- * @return A string allocated from the pool containing the result with a zero +- * pad. If src was NULL, or an error occurred, NULL is returned. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the decoding is not ++ * possible (see apr_decode_base32 errors). + */ + APR_DECLARE(const char *)apr_pdecode_base32(apr_pool_t * p, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len) +@@ -412,15 +465,16 @@ + * Convert base32 or base32hex with or without padding to binary data, and + * return the results from a pool. + * @param p Pool to allocate from. +- * @param src The original string. ++ * @param src The base32 string to decode. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, parse RFC4648 Base 32 Encoding. If + * APR_ENCODE_BASE32HEX, use RFC4648 base32hex Encoding. +- * @param len If present, returns the number of characters written, excluding +- * the zero padding. +- * @return A buffer allocated from the pool containing the result with a zero +- * pad. If src was NULL, or an error occurred, NULL is returned. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the decoding is not ++ * possible (see apr_decode_base32_binary errors). + */ + APR_DECLARE(const unsigned char *)apr_pdecode_base32_binary(apr_pool_t * p, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len) +@@ -428,31 +482,40 @@ + + /** + * Convert text data to base16 (hex). +- * @param dest The destination string, can be NULL. +- * @param src The original string. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for encoding. ++ * @param src The original string, can be NULL if \c dest is NULL and \c slen ++ * is positive or nul. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 16 Encoding. If + * APR_ENCODE_COLON, separate each token with a colon. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination buffer, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL. ++ * @param len If not NULL, outputs the length of the buffer needed for encoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the encoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is not APR_ENCODE_STRING and ++ * negative, or APR_NOTFOUND if \c dest is not NULL and \c src is NULL, or ++ * APR_ENOSPC if \c dest is NULL and the source length (based on \c slen or ++ * APR_ENCODE_STRING) is too big to encode. + */ + APR_DECLARE(apr_status_t) apr_encode_base16(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len); + + /** + * Convert binary data to base16 (hex). +- * @param dest The destination string, can be NULL. +- * @param src The original buffer. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for encoding. ++ * @param src The original buffer, can be NULL if \c dest is NULL. + * @param slen The length of the original buffer. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 16 Encoding. If + * APR_ENCODE_COLON, separate each token with a colon. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination buffer, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL. ++ * @param len If not NULL, outputs the length of the buffer needed for encoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the encoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is negative, or APR_NOTFOUND ++ * if \c dest is not NULL and \c src is NULL, or APR_ENOSPC if \c dest is NULL ++ * and the source length (based on \c slen or APR_ENCODE_STRING) is too big to ++ * encode. + */ + APR_DECLARE(apr_status_t) apr_encode_base16_binary(char *dest, + const unsigned char *src, apr_ssize_t slen, int flags, +@@ -464,13 +527,14 @@ + * @param p Pool to allocate from. + * @param src The original string. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 16 Encoding. If + * APR_ENCODE_COLON, separate each token with a colon. +- * @param len If present, returns the number of characters written, excluding +- * the zero padding. +- * @return A string allocated from the pool containing the result with a zero +- * pad. If src was NULL, or an error occurred, NULL is returned. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the encoding is not ++ * possible (see apr_encode_base16 errors). + */ + APR_DECLARE(const char *)apr_pencode_base16(apr_pool_t * p, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len) +@@ -484,10 +548,11 @@ + * @param slen The length of the original buffer. + * @param flags If APR_ENCODE_NONE, emit RFC4648 Base 16 Encoding. If + * APR_ENCODE_COLON, separate each token with a colon. +- * @param len If present, returns the number of characters written, excluding +- * the zero padding. +- * @return A string allocated from the pool containing the result with a zero +- * pad. If src was NULL, or an error occurred, NULL is returned. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the encoding is not ++ * possible (see apr_encode_base16_binary errors). + */ + APR_DECLARE(const char *)apr_pencode_base16_binary(apr_pool_t * p, + const unsigned char *src, apr_ssize_t slen, +@@ -495,34 +560,48 @@ + + /** + * Convert base16 (hex) to text data. +- * @param dest The destination string, can be NULL. +- * @param src The original string. +- * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for decoding. ++ * @param src The base16 string, can be NULL if \c dest is NULL and \c slen ++ * is positive or nul. ++ * @param slen The length of the base16 string, or APR_ENCODE_STRING if ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, parse RFC4648 Base 16 Encoding. If + * APR_ENCODE_COLON, allow tokens to be separated with a colon. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination buffer, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL, or APR_BADCH +- * if a non hex character is present. A zero pad is appended to the buffer. ++ * @param len If not NULL, outputs the length of the buffer needed for decoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the decoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is not APR_ENCODE_STRING and ++ * negative, or APR_NOTFOUND if \c dest is not NULL and \c src is NULL, or ++ * APR_ENOSPC if \c dest is NULL and the source length (based on \c slen or ++ * APR_ENCODE_STRING) is too big to decode, or APR_EINCOMPLETE if the source ++ * length (based on \c slen or APR_ENCODE_STRING) is invalid for a base16 ++ * encoding, or APR_BADCH if a non base16 character is present and ++ * APR_ENCODE_RELAXED is not specified. + */ + APR_DECLARE(apr_status_t) apr_decode_base16(char *dest, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len); + + /** + * Convert base16 (hex) to binary data. +- * @param dest The destination buffer, can be NULL. +- * @param src The original string. +- * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * @param dest The destination string, can be NULL to output in \c len the ++ * needed buffer length for decoding. ++ * @param src The base16 string, can be NULL if \c dest is NULL and \c slen ++ * is positive or nul. ++ * @param slen The length of the base16 string, or APR_ENCODE_STRING if ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, parse RFC4648 Base 16 Encoding. If + * APR_ENCODE_COLON, allow tokens to be separated with a colon. +- * @param len If present and src is NULL, returns the maximum possible length +- * of the destination buffer, including a zero pad. If present and src is +- * not NULL, returns the number of characters actually written. +- * @return APR_SUCCESS, or APR_NOTFOUND if the string was NULL, or APR_BADCH +- * if a non hex character is present. No zero pad is written to the buffer. ++ * @param len If not NULL, outputs the length of the buffer needed for decoding ++ * (including the trailing NUL) if \c dest is NULL, or the actual length of ++ * the decoding (excluding the trailing NUL) if \c dest is not NULL. ++ * @return APR_SUCCESS, or APR_EINVAL if \c slen is not APR_ENCODE_STRING and ++ * negative, or APR_NOTFOUND if \c dest is not NULL and \c src is NULL, or ++ * APR_ENOSPC if \c dest is NULL and the source length (based on \c slen or ++ * APR_ENCODE_STRING) is too big to decode, or APR_EINCOMPLETE if the source ++ * length (based on \c slen or APR_ENCODE_STRING) is invalid for a base16 ++ * encoding, or APR_BADCH if a non base16 character is present and ++ * APR_ENCODE_RELAXED is not specified. + */ + APR_DECLARE(apr_status_t) apr_decode_base16_binary(unsigned char *dest, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len); +@@ -530,15 +609,16 @@ + /** + * Convert base16 (hex) and return the results from a pool. + * @param p Pool to allocate from. +- * @param src The original string. ++ * @param src The base16 string to decode. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, parse RFC4648 Base 16 Encoding. If + * APR_ENCODE_COLON, allow tokens to be separated with a colon. +- * @param len If present, returns the number of characters written, excluding +- * the zero padding. +- * @return A buffer allocated from the pool containing the result with a zero +- * pad. If src was NULL, or an error occurred, NULL is returned. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the decoding is not ++ * possible (see apr_decode_base16 errors). + */ + APR_DECLARE(const char *)apr_pdecode_base16(apr_pool_t * p, const char *src, + apr_ssize_t slen, int flags, apr_size_t * len) +@@ -547,15 +627,16 @@ + /** + * Convert base16 (hex) to binary data, and return the results from a pool. + * @param p Pool to allocate from. +- * @param src The original string. ++ * @param src The base16 string to decode. + * @param slen The length of the original string, or APR_ENCODE_STRING if +- * NUL terminated. ++ * the actual length should be computed based on NUL termination. + * @param flags If APR_ENCODE_NONE, parse RFC4648 Base 16 Encoding. If + * APR_ENCODE_COLON, allow tokens to be separated with a colon. +- * @param len If present, returns the number of characters written, excluding +- * the zero padding. +- * @return A buffer allocated from the pool containing the result with a zero +- * pad. If src was NULL, or an error occurred, NULL is returned. ++ * @param len If not NULL, outputs the length of the encoding (excluding the ++ * trailing NUL). ++ * @return A NUL terminated string allocated from the pool on success, ++ * or NULL if src is NULL or allocation failed or the decoding is not ++ * possible (see apr_decode_base16_binary errors). + */ + APR_DECLARE(const unsigned char *)apr_pdecode_base16_binary(apr_pool_t * p, + const char *src, apr_ssize_t slen, int flags, apr_size_t * len) +--- apr-1.7.0/include/private/apr_encode_private.h.encoding ++++ apr-1.7.0/include/private/apr_encode_private.h +@@ -34,7 +34,8 @@ + */ + + #if APR_CHARSET_EBCDIC +- static int convert_a2e[256] = { ++ ++static unsigned char convert_a2e[256] = { + 0x00, 0x01, 0x02, 0x03, 0x37, 0x2D, 0x2E, 0x2F, 0x16, 0x05, 0x15, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x3C, 0x3D, 0x32, 0x26, 0x18, 0x19, 0x3F, 0x27, 0x1C, 0x1D, 0x1E, 0x1F, + 0x40, 0x5A, 0x7F, 0x7B, 0x5B, 0x6C, 0x50, 0x7D, 0x4D, 0x5D, 0x5C, 0x4E, 0x6B, 0x60, 0x4B, 0x61, +@@ -52,7 +53,7 @@ + 0x44, 0x45, 0x42, 0x46, 0x43, 0x47, 0x9C, 0x48, 0x54, 0x51, 0x52, 0x53, 0x58, 0x55, 0x56, 0x57, + 0x8C, 0x49, 0xCD, 0xCE, 0xCB, 0xCF, 0xCC, 0xE1, 0x70, 0xDD, 0xDE, 0xDB, 0xDC, 0x8D, 0x8E, 0xDF}; + +- static int convert_e2a[256] = { ++static unsigned char convert_e2a[256] = { + 0x00, 0x01, 0x02, 0x03, 0x9C, 0x09, 0x86, 0x7F, 0x97, 0x8D, 0x8E, 0x0B, 0x0C, 0x0D, 0x0E, 0x0F, + 0x10, 0x11, 0x12, 0x13, 0x9D, 0x0A, 0x08, 0x87, 0x18, 0x19, 0x92, 0x8F, 0x1C, 0x1D, 0x1E, 0x1F, + 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x17, 0x1B, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x05, 0x06, 0x07, +@@ -69,12 +70,16 @@ + 0x7D, 0x4A, 0x4B, 0x4C, 0x4D, 0x4E, 0x4F, 0x50, 0x51, 0x52, 0xB9, 0xFB, 0xFC, 0xF9, 0xFA, 0xFF, + 0x5C, 0xF7, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5A, 0xB2, 0xD4, 0xD6, 0xD2, 0xD3, 0xD5, + 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0xB3, 0xDB, 0xDC, 0xD9, 0xDA, 0x9F}; +-#define decode ENCODE_TO_ASCII(ch) convert_e2a[(unsigned char)ch] +-#define decode ENCODE_TO_NATIVE(ch) convert_a2e[(unsigned char)ch] +-#else /* APR_CHARSET_EBCDIC */ +-#define ENCODE_TO_ASCII(ch) (ch) +-#define ENCODE_TO_NATIVE(ch) (ch) +-#endif /* !APR_CHARSET_EBCDIC */ ++ ++#define TO_ASCII(ch) (convert_e2a[(unsigned char)(ch)]) ++#define TO_NATIVE(ch) (convert_a2e[(unsigned char)(ch)]) ++ ++#else /* APR_CHARSET_EBCDIC */ ++ ++#define TO_ASCII(ch) ((unsigned char)(ch)) ++#define TO_NATIVE(ch) ((unsigned char)(ch)) ++ ++#endif /* !APR_CHARSET_EBCDIC */ + + /** @} */ + #ifdef __cplusplus +--- apr-1.7.0/test/testencode.c.encoding ++++ apr-1.7.0/test/testencode.c +@@ -905,6 +905,202 @@ + apr_pool_destroy(pool); + } + ++static void test_encode_errors(abts_case * tc, void *data) ++{ ++ char dest[64]; ++ apr_size_t len; ++ apr_status_t rv; ++ ++ /* Can't test APR_ENOSPC without a NUL terminated buffer of ++ * length APR_SIZE_MAX / 4 * 3 and passing APR_ENCODE_STRING, ++ * which we won't even think about :) ++ */ ++ ++ /* base64 */ ++ rv = apr_encode_base64(dest, "", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_encode_base64(dest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ ++ /* base64_binary */ ++ rv = apr_encode_base64_binary(dest, (const unsigned char *)"", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_encode_base64_binary(dest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ ++ /* base32 */ ++ rv = apr_encode_base32(dest, "", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_encode_base32(dest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ ++ /* base32_binary */ ++ rv = apr_encode_base32_binary(dest, (const unsigned char *)"", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_encode_base32_binary(dest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ ++ /* base16 */ ++ rv = apr_encode_base16(dest, "", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_encode_base16(dest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ ++ /* base16_binary */ ++ rv = apr_encode_base16_binary(dest, (const unsigned char *)"", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_encode_base16_binary(dest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++} ++ ++static void test_decode_errors(abts_case * tc, void *data) ++{ ++ char dest[64]; ++ apr_size_t len; ++ apr_status_t rv; ++ unsigned char *udest = (unsigned char *)dest; ++ ++ /* base64 */ ++ rv = apr_decode_base64(dest, "", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_decode_base64(dest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ rv = apr_decode_base64(NULL, NULL, 5, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base64(dest, "ABCDE", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base64(dest, "ABCD*EF", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_BADCH, rv); ++ rv = apr_decode_base64(dest, "ABCD*EF", APR_ENCODE_STRING, ++ APR_ENCODE_RELAXED, &len); ++ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ++ ABTS_SIZE_EQUAL(tc, 3, len); ++ ++ /* base64_binary */ ++ rv = apr_decode_base64_binary(udest, "", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_decode_base64_binary(udest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ rv = apr_decode_base64_binary(NULL, NULL, 5, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base64_binary(udest, "ABCDE", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base64_binary(udest, "ABCD*EF", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_BADCH, rv); ++ rv = apr_decode_base64_binary(udest, "ABCD*EF", APR_ENCODE_STRING, ++ APR_ENCODE_RELAXED, &len); ++ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ++ ABTS_SIZE_EQUAL(tc, 3, len); ++ ++ /* base32 */ ++ rv = apr_decode_base32(dest, "", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_decode_base32(dest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ rv = apr_decode_base32(NULL, NULL, 9, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32(NULL, NULL, 11, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32(NULL, NULL, 14, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32(dest, "ABCDEFGHI", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32(dest, "ABCDEFGHIJK", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32(dest, "ABCDEFGHIJKLMN", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32(dest, "ABCDEFGH*IJ", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_BADCH, rv); ++ rv = apr_decode_base32(dest, "ABCEEFGH*IJ", APR_ENCODE_STRING, ++ APR_ENCODE_RELAXED, &len); ++ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ++ ABTS_SIZE_EQUAL(tc, 5, len); ++ ++ /* base32_binary */ ++ rv = apr_decode_base32_binary(udest, "", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_decode_base32_binary(udest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ rv = apr_decode_base32_binary(NULL, NULL, 9, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32_binary(NULL, NULL, 11, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32_binary(NULL, NULL, 14, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32_binary(udest, "ABCDEFGHI", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32_binary(udest, "ABCDEFGHIJK", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32_binary(udest, "ABCDEFGHIJKLMN", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base32_binary(udest, "ABCDEFGH*IJ", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_BADCH, rv); ++ rv = apr_decode_base32_binary(udest, "ABCEEFGH*IJ", APR_ENCODE_STRING, ++ APR_ENCODE_RELAXED, &len); ++ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ++ ABTS_SIZE_EQUAL(tc, 5, len); ++ ++ /* base16 */ ++ rv = apr_decode_base16(dest, "", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_decode_base16(dest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ rv = apr_decode_base16(NULL, NULL, 3, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base16(dest, "ABC", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base16(dest, "ABCD*EF", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_BADCH, rv); ++ rv = apr_decode_base16(dest, "ABCD*EF", APR_ENCODE_STRING, ++ APR_ENCODE_RELAXED, &len); ++ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ++ ABTS_SIZE_EQUAL(tc, 2, len); ++ /* base16 with colon */ ++ rv = apr_decode_base16(dest, "AB:", APR_ENCODE_STRING, ++ APR_ENCODE_COLON, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base16(dest, "AB:C", APR_ENCODE_STRING, ++ APR_ENCODE_COLON, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base16(dest, "AB:CD*EF", APR_ENCODE_STRING, ++ APR_ENCODE_COLON, &len); ++ ABTS_INT_EQUAL(tc, APR_BADCH, rv); ++ rv = apr_decode_base16(dest, "AB:CD*EF", APR_ENCODE_STRING, ++ APR_ENCODE_COLON|APR_ENCODE_RELAXED, &len); ++ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ++ ABTS_SIZE_EQUAL(tc, 2, len); ++ ++ /* base16_binary */ ++ rv = apr_decode_base16_binary(udest, "", -2, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINVAL, rv); ++ rv = apr_decode_base16_binary(udest, NULL, APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_NOTFOUND, rv); ++ rv = apr_decode_base16_binary(NULL, NULL, 3, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base16_binary(udest, "ABC", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base16_binary(udest, "ABCD*EF", APR_ENCODE_STRING, 0, &len); ++ ABTS_INT_EQUAL(tc, APR_BADCH, rv); ++ rv = apr_decode_base16_binary(udest, "ABCD*EF", APR_ENCODE_STRING, ++ APR_ENCODE_RELAXED, &len); ++ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ++ ABTS_SIZE_EQUAL(tc, 2, len); ++ /* base16_binary with colon */ ++ rv = apr_decode_base16_binary(udest, "AB:", APR_ENCODE_STRING, ++ APR_ENCODE_COLON, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base16_binary(udest, "AB:C", APR_ENCODE_STRING, ++ APR_ENCODE_COLON, &len); ++ ABTS_INT_EQUAL(tc, APR_EINCOMPLETE, rv); ++ rv = apr_decode_base16_binary(udest, "AB:CD*EF", APR_ENCODE_STRING, ++ APR_ENCODE_COLON, &len); ++ ABTS_INT_EQUAL(tc, APR_BADCH, rv); ++ rv = apr_decode_base16_binary(udest, "AB:CD*EF", APR_ENCODE_STRING, ++ APR_ENCODE_COLON|APR_ENCODE_RELAXED, &len); ++ ABTS_INT_EQUAL(tc, APR_SUCCESS, rv); ++ ABTS_SIZE_EQUAL(tc, 2, len); ++} ++ + abts_suite *testencode(abts_suite * suite) + { + suite = ADD_SUITE(suite); +@@ -921,6 +1117,8 @@ + abts_run_test(suite, test_encode_base16_binary, NULL); + abts_run_test(suite, test_decode_base16, NULL); + abts_run_test(suite, test_decode_base16_binary, NULL); ++ abts_run_test(suite, test_encode_errors, NULL); ++ abts_run_test(suite, test_decode_errors, NULL); + + return suite; + } diff --git a/apr.spec b/apr.spec index 99c7503..6d34524 100644 --- a/apr.spec +++ b/apr.spec @@ -6,7 +6,7 @@ Summary: Apache Portable Runtime library Name: apr Version: 1.7.0 -Release: 11%{?dist} +Release: 12%{?dist} # ASL 2.0: everything # ISC: network_io/apr-1.4.6/network_io/unix/inet_?to?.c # BSD with advertising: strings/apr_snprintf.c, strings/apr_fnmatch.c, @@ -22,6 +22,7 @@ Patch2: apr-1.2.7-pkgconf.patch Patch3: apr-1.7.0-deepbind.patch Patch4: apr-1.7.0-r1891269+.patch Patch5: apr-1.7.0-r1894167.patch +Patch6: apr-1.7.0-encoding.patch BuildRequires: gcc, autoconf, libtool, libuuid-devel, python3 BuildRequires: make @@ -49,6 +50,7 @@ C data structures and routines. %patch3 -p1 -b .deepbind %patch4 -p1 -b .r1891269+ %patch5 -p1 -b .r1894167 +%patch6 -p1 -b .encoding %build # regenerate configure script etc. @@ -136,6 +138,10 @@ popd %{_datadir}/aclocal/*.m4 %changelog +* Thu Dec 7 2023 Joe Orton - 1.7.0-12 +- fix integer bounds checking in apr_encode_* + Resolves: RHEL-17123 + * Mon Dec 6 2021 Joe Orton - 1.7.0-11 - always disable SCTP support at build time (#1997107) diff --git a/pullrev.sh b/pullrev.sh index 8787970..ca166b0 100755 --- a/pullrev.sh +++ b/pullrev.sh @@ -6,7 +6,7 @@ if [ $# -lt 1 ]; then fi repo="https://svn.apache.org/repos/asf/apr/apr/trunk" -#repo="https://svn.apache.org/repos/asf/apr/apr/branches/1.7.x" +repo="https://svn.apache.org/repos/asf/apr/apr/branches/1.7.x" ver=1.7.0 prefix="apr-${ver}" suffix="r$1${2:++}"