Version in base suite: 1.7.0-6+deb11u1 Base version: apr_1.7.0-6+deb11u1 Target version: apr_1.7.0-6+deb11u2 Base file: /srv/ftp-master.debian.org/ftp/pool/main/a/apr/apr_1.7.0-6+deb11u1.dsc Target file: /srv/ftp-master.debian.org/policy/pool/main/a/apr/apr_1.7.0-6+deb11u2.dsc changelog | 11 patches/Address-some-warnings-raised-by-MSVC-32-64.patch | 181 patches/apr_decode_base-64-32-16-stop-reading-before-not-inc.patch | 199 patches/apr_encode_base32-fix-advertised-output-len-when-cal.patch | 27 patches/encoding-Better-check-inputs-of-apr_-encode-decode-_.patch | 2924 ++++++++++ patches/series | 4 6 files changed, 3346 insertions(+) diff -Nru apr-1.7.0/debian/changelog apr-1.7.0/debian/changelog --- apr-1.7.0/debian/changelog 2021-08-24 07:18:26.000000000 +0000 +++ apr-1.7.0/debian/changelog 2023-03-01 14:22:18.000000000 +0000 @@ -1,3 +1,14 @@ +apr (1.7.0-6+deb11u2) bullseye-security; urgency=high + + * Non-maintainer upload by the Security Team. + * Address some warnings raised by MSVC-32/64 + * apr_encode_base32: fix advertised output *len when called with dst == NULL + * apr_decode_base{64,32,16}: stop reading before (not including) NUL byte. + * encoding: Better check inputs of apr_{encode,decode}_* functions + (CVE-2022-24963) + + -- Salvatore Bonaccorso Wed, 01 Mar 2023 15:22:18 +0100 + apr (1.7.0-6+deb11u1) bullseye; urgency=medium * Team upload diff -Nru apr-1.7.0/debian/patches/Address-some-warnings-raised-by-MSVC-32-64.patch apr-1.7.0/debian/patches/Address-some-warnings-raised-by-MSVC-32-64.patch --- apr-1.7.0/debian/patches/Address-some-warnings-raised-by-MSVC-32-64.patch 1970-01-01 00:00:00.000000000 +0000 +++ apr-1.7.0/debian/patches/Address-some-warnings-raised-by-MSVC-32-64.patch 2023-03-01 14:20:46.000000000 +0000 @@ -0,0 +1,181 @@ +From: Yann Ylavic +Date: Wed, 3 Apr 2019 13:54:46 +0000 +Subject: Address some warnings raised by MSVC-32/64. +Origin: https://github.com/apache/apr/commit/66e41846004d40fd6d12811fd0acf08920a3d1cd + +git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1856873 13f79535-47bb-0310-9956-ffa450edef68 +--- + atomic/win32/apr_atomic64.c | 50 ++++++++----------------------------- + encoding/apr_encode.c | 4 +-- + file_io/win32/seek.c | 2 +- + memory/unix/apr_pools.c | 8 +++--- + 4 files changed, 18 insertions(+), 46 deletions(-) + +diff --git a/atomic/win32/apr_atomic64.c b/atomic/win32/apr_atomic64.c +index a5acc945e405..e2cd06d6c319 100644 +--- a/atomic/win32/apr_atomic64.c ++++ b/atomic/win32/apr_atomic64.c +@@ -18,55 +18,35 @@ + #include "apr_atomic.h" + #include "apr_thread_mutex.h" + +-APR_DECLARE(apr_uint64_t) apr_atomic_add64(volatile apr_uint64_t *mem, apr_uint64_t val) +-{ +-#if (defined(_M_IA64) || defined(_M_AMD64)) +- return InterlockedExchangeAdd64(mem, val); +-#else +- return InterlockedExchangeAdd64((long *)mem, val); +-#endif +-} +- + /* Of course we want the 2's compliment of the unsigned value, val */ + #ifdef _MSC_VER + #pragma warning(disable: 4146) + #endif + ++APR_DECLARE(apr_uint64_t) apr_atomic_add64(volatile apr_uint64_t *mem, apr_uint64_t val) ++{ ++ return InterlockedExchangeAdd64((volatile LONG64 *)mem, val); ++} ++ + APR_DECLARE(void) apr_atomic_sub64(volatile apr_uint64_t *mem, apr_uint64_t val) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) +- InterlockedExchangeAdd64(mem, -val); +-#else +- InterlockedExchangeAdd64((long *)mem, -val); +-#endif ++ InterlockedExchangeAdd64((volatile LONG64 *)mem, -val); + } + + APR_DECLARE(apr_uint64_t) apr_atomic_inc64(volatile apr_uint64_t *mem) + { + /* we return old value, win64 returns new value :( */ +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- return InterlockedIncrement64(mem) - 1; +-#else +- return InterlockedIncrement64((long *)mem) - 1; +-#endif ++ return InterlockedIncrement64((volatile LONG64 *)mem) - 1; + } + + APR_DECLARE(int) apr_atomic_dec64(volatile apr_uint64_t *mem) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- return InterlockedDecrement64(mem); +-#else +- return InterlockedDecrement64((long *)mem); +-#endif ++ return !!InterlockedDecrement64((volatile LONG64 *)mem); + } + + APR_DECLARE(void) apr_atomic_set64(volatile apr_uint64_t *mem, apr_uint64_t val) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- InterlockedExchange64(mem, val); +-#else +- InterlockedExchange64((long*)mem, val); +-#endif ++ InterlockedExchange64((volatile LONG64 *)mem, val); + } + + APR_DECLARE(apr_uint64_t) apr_atomic_read64(volatile apr_uint64_t *mem) +@@ -77,18 +57,10 @@ APR_DECLARE(apr_uint64_t) apr_atomic_read64(volatile apr_uint64_t *mem) + APR_DECLARE(apr_uint64_t) apr_atomic_cas64(volatile apr_uint64_t *mem, apr_uint64_t with, + apr_uint64_t cmp) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- return InterlockedCompareExchange64(mem, with, cmp); +-#else +- return InterlockedCompareExchange64((long*)mem, with, cmp); +-#endif ++ return InterlockedCompareExchange64((volatile LONG64 *)mem, with, cmp); + } + + APR_DECLARE(apr_uint64_t) apr_atomic_xchg64(volatile apr_uint64_t *mem, apr_uint64_t val) + { +-#if (defined(_M_IA64) || defined(_M_AMD64)) && !defined(RC_INVOKED) +- return InterlockedExchange64(mem, val); +-#else +- return InterlockedExchange64((long *)mem, val); +-#endif ++ return InterlockedExchange64((volatile LONG64 *)mem, val); + } +diff --git a/encoding/apr_encode.c b/encoding/apr_encode.c +index 905185921d91..e44ae11f0a9c 100644 +--- a/encoding/apr_encode.c ++++ b/encoding/apr_encode.c +@@ -1062,7 +1062,7 @@ 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_ssize_t size; + + if (!src) { + return APR_NOTFOUND; +@@ -1115,7 +1115,7 @@ 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_ssize_t size; + + if (!src) { + return APR_NOTFOUND; +diff --git a/file_io/win32/seek.c b/file_io/win32/seek.c +index afe6edb00504..dfef57716cb9 100644 +--- a/file_io/win32/seek.c ++++ b/file_io/win32/seek.c +@@ -170,7 +170,7 @@ APR_DECLARE(apr_status_t) apr_file_trunc(apr_file_t *thefile, apr_off_t offset) + thefile->bufpos = 0; + } + else if (offset < thefile->filePtr + (apr_off_t)thefile->bufpos) { +- thefile->bufpos = offset - thefile->filePtr; ++ thefile->bufpos = (apr_size_t)(offset - thefile->filePtr); + } + + if (thefile->bufpos != 0) { +diff --git a/memory/unix/apr_pools.c b/memory/unix/apr_pools.c +index 5fa7da1b5be1..0ca715efa06b 100644 +--- a/memory/unix/apr_pools.c ++++ b/memory/unix/apr_pools.c +@@ -407,7 +407,7 @@ apr_memnode_t *allocator_alloc(apr_allocator_t *allocator, apr_size_t in_size) + return NULL; + } + #endif +- node->index = index; ++ node->index = (apr_uint32_t)index; + node->endp = (char *)node + size; + + have_node: +@@ -877,7 +877,7 @@ APR_DECLARE(void *) apr_palloc(apr_pool_t *pool, apr_size_t in_size) + free_index = (APR_ALIGN(active->endp - active->first_avail + 1, + BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; + +- active->free_index = free_index; ++ active->free_index = (apr_uint32_t)free_index; + node = active->next; + if (free_index >= node->free_index) + goto have_mem; +@@ -1289,7 +1289,7 @@ static int psprintf_flush(apr_vformatter_buff_t *vbuff) + free_index = (APR_ALIGN(active->endp - active->first_avail + 1, + BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; + +- active->free_index = free_index; ++ active->free_index = (apr_uint32_t)free_index; + node = active->next; + if (free_index < node->free_index) { + do { +@@ -1445,7 +1445,7 @@ APR_DECLARE(char *) apr_pvsprintf(apr_pool_t *pool, const char *fmt, va_list ap) + free_index = (APR_ALIGN(active->endp - active->first_avail + 1, + BOUNDARY_SIZE) - BOUNDARY_SIZE) >> BOUNDARY_INDEX; + +- active->free_index = free_index; ++ active->free_index = (apr_uint32_t)free_index; + node = active->next; + + if (free_index >= node->free_index) { +-- +2.39.2 + diff -Nru apr-1.7.0/debian/patches/apr_decode_base-64-32-16-stop-reading-before-not-inc.patch apr-1.7.0/debian/patches/apr_decode_base-64-32-16-stop-reading-before-not-inc.patch --- apr-1.7.0/debian/patches/apr_decode_base-64-32-16-stop-reading-before-not-inc.patch 1970-01-01 00:00:00.000000000 +0000 +++ apr-1.7.0/debian/patches/apr_decode_base-64-32-16-stop-reading-before-not-inc.patch 2023-03-01 14:21:21.000000000 +0000 @@ -0,0 +1,199 @@ +From: Yann Ylavic +Date: Fri, 27 Nov 2020 17:04:06 +0000 +Subject: apr_decode_base{64,32,16}: stop reading before (not including) NUL + byte. +Origin: https://github.com/apache/apr/commit/e70d77ecc4aa9e0dccac6e7e5ba74639f71f50cf + +git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883870 13f79535-47bb-0310-9956-ffa450edef68 +--- + encoding/apr_encode.c | 60 ++++++++++++++++++++++++++++++------------- + test/testencode.c | 24 ++++++++++++----- + 2 files changed, 59 insertions(+), 25 deletions(-) + +diff --git a/encoding/apr_encode.c b/encoding/apr_encode.c +index b3278c7fd3ab..bc2dc5437990 100644 +--- a/encoding/apr_encode.c ++++ b/encoding/apr_encode.c +@@ -394,11 +394,15 @@ APR_DECLARE(apr_status_t) apr_decode_base64(char *dest, const char *src, + apr_status_t status; + + bufin = (const unsigned char *)src; +- while (pr2six[*(bufin++)] < 64 && count) ++ while (count && pr2six[*bufin] < 64) { + count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2six[*(bufin++)] > 64 && count) ++ bufin++; ++ } ++ nprbytes = bufin - (const unsigned char *)src; ++ while (count && pr2six[*bufin] > 64) { + count--; ++ bufin++; ++ } + + status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : + count ? APR_BADCH : APR_SUCCESS; +@@ -469,11 +473,15 @@ APR_DECLARE(apr_status_t) apr_decode_base64_binary(unsigned char *dest, + apr_status_t status; + + bufin = (const unsigned char *)src; +- while (pr2six[*(bufin++)] < 64 && count) ++ while (count && pr2six[*bufin] < 64) { + count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2six[*(bufin++)] > 64 && count) ++ bufin++; ++ } ++ nprbytes = bufin - (const unsigned char *)src; ++ while (count && pr2six[*bufin] > 64) { + count--; ++ bufin++; ++ } + + status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : + count ? APR_BADCH : APR_SUCCESS; +@@ -842,11 +850,15 @@ APR_DECLARE(apr_status_t) apr_decode_base32(char *dest, const char *src, + } + + bufin = (const unsigned char *)src; +- while (pr2[*(bufin++)] < 32 && count) ++ while (count && pr2[*bufin] < 32) { + count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2[*(bufin++)] > 32 && count) ++ bufin++; ++ } ++ nprbytes = bufin - (const unsigned char *)src; ++ while (count && pr2[*bufin] > 32) { + count--; ++ bufin++; ++ } + + status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : + count ? APR_BADCH : APR_SUCCESS; +@@ -945,11 +957,15 @@ APR_DECLARE(apr_status_t) apr_decode_base32_binary(unsigned char *dest, + } + + bufin = (const unsigned char *)src; +- while (pr2[*(bufin++)] < 32 && count) ++ while (count && pr2[*bufin] < 32) { + count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2[*(bufin++)] > 32 && count) ++ bufin++; ++ } ++ nprbytes = bufin - (const unsigned char *)src; ++ while (count && pr2[*bufin] > 32) { + count--; ++ bufin++; ++ } + + status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : + count ? APR_BADCH : APR_SUCCESS; +@@ -1220,11 +1236,15 @@ APR_DECLARE(apr_status_t) apr_decode_base16(char *dest, + + count = slen; + bufin = (const unsigned char *)src; +- while (pr2two[*(bufin++)] != 16 && count) ++ while (count && pr2two[*bufin] != 16) { + count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2two[*(bufin++)] > 16 && count) ++ bufin++; ++ } ++ nprbytes = bufin - (const unsigned char *)src; ++ while (count && pr2two[*bufin] > 16) { + count--; ++ bufin++; ++ } + + status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : + count ? APR_BADCH : APR_SUCCESS; +@@ -1310,11 +1330,15 @@ APR_DECLARE(apr_status_t) apr_decode_base16_binary(unsigned char *dest, + + count = slen; + bufin = (const unsigned char *)src; +- while (pr2two[*(bufin++)] != 16 && count) ++ while (count && pr2two[*bufin] != 16) { + count--; +- nprbytes = (bufin - (const unsigned char *)src) - 1; +- while (pr2two[*(bufin++)] > 16 && count) ++ bufin++; ++ } ++ nprbytes = bufin - (const unsigned char *)src; ++ while (count && pr2two[*bufin] > 16) { + count--; ++ bufin++; ++ } + + status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : + count ? APR_BADCH : APR_SUCCESS; +diff --git a/test/testencode.c b/test/testencode.c +index 3680fa380f04..ba23aaf2872a 100644 +--- a/test/testencode.c ++++ b/test/testencode.c +@@ -134,37 +134,42 @@ static void test_decode_base64(abts_case * tc, void *data) + src = ""; + target = ""; + dest = apr_pdecode_base64(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); +- ABTS_STR_EQUAL(tc, dest, target); ++ ABTS_STR_EQUAL(tc, target, dest); + + src = "Zg=="; + target = "f"; + dest = apr_pdecode_base64(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); +- ABTS_STR_EQUAL(tc, dest, target); ++ ABTS_STR_EQUAL(tc, target, dest); ++ ++ src = "Zg="; ++ target = "f"; ++ dest = apr_pdecode_base64(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); ++ ABTS_STR_EQUAL(tc, target, dest); + + src = "Zg"; + target = "f"; + dest = apr_pdecode_base64(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); +- ABTS_STR_EQUAL(tc, dest, target); ++ ABTS_STR_EQUAL(tc, target, dest); + + src = "Zm8="; + target = "fo"; + dest = apr_pdecode_base64(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); +- ABTS_STR_EQUAL(tc, dest, target); ++ ABTS_STR_EQUAL(tc, target, dest); + + src = "Zm8"; + target = "fo"; + dest = apr_pdecode_base64(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); +- ABTS_STR_EQUAL(tc, dest, target); ++ ABTS_STR_EQUAL(tc, target, dest); + + src = "Zm9v"; + target = "foo"; + dest = apr_pdecode_base64(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); +- ABTS_STR_EQUAL(tc, dest, target); ++ ABTS_STR_EQUAL(tc, target, dest); + + src = "Zm9v"; + target = "foo"; + dest = apr_pdecode_base64(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); +- ABTS_STR_EQUAL(tc, dest, target); ++ ABTS_STR_EQUAL(tc, target, dest); + + apr_pool_destroy(pool); + } +@@ -191,6 +196,11 @@ static void test_decode_base64_binary(abts_case * tc, void *data) + ABTS_ASSERT(tc, "apr_pdecode_base64_binary target!=dest", memcmp(ufoobar, udest, 1) == 0); + ABTS_INT_EQUAL(tc, len, 1); + ++ src = "Zg="; ++ udest = apr_pdecode_base64_binary(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); ++ ABTS_ASSERT(tc, "apr_pdecode_base64_binary target!=dest", memcmp(ufoobar, udest, 1) == 0); ++ ABTS_INT_EQUAL(tc, len, 1); ++ + src = "Zg"; + udest = apr_pdecode_base64_binary(pool, src, APR_ENCODE_STRING, APR_ENCODE_NONE, &len); + ABTS_ASSERT(tc, "apr_pdecode_base64_binary target!=dest", memcmp(ufoobar, udest, 1) == 0); +-- +2.39.2 + diff -Nru apr-1.7.0/debian/patches/apr_encode_base32-fix-advertised-output-len-when-cal.patch apr-1.7.0/debian/patches/apr_encode_base32-fix-advertised-output-len-when-cal.patch --- apr-1.7.0/debian/patches/apr_encode_base32-fix-advertised-output-len-when-cal.patch 1970-01-01 00:00:00.000000000 +0000 +++ apr-1.7.0/debian/patches/apr_encode_base32-fix-advertised-output-len-when-cal.patch 2023-03-01 14:21:04.000000000 +0000 @@ -0,0 +1,27 @@ +From: Yann Ylavic +Date: Fri, 27 Nov 2020 16:54:50 +0000 +Subject: apr_encode_base32: fix advertised output *len when called with dst == + NULL. +Origin: https://github.com/apache/apr/commit/2b0eb50e43667ce8cebf0bb745a0eb7d493385c2 + +git-svn-id: https://svn.apache.org/repos/asf/apr/apr/trunk@1883868 13f79535-47bb-0310-9956-ffa450edef68 +--- + encoding/apr_encode.c | 2 +- + 1 file changed, 1 insertion(+), 1 deletion(-) + +diff --git a/encoding/apr_encode.c b/encoding/apr_encode.c +index e44ae11f0a9c..b3278c7fd3ab 100644 +--- a/encoding/apr_encode.c ++++ b/encoding/apr_encode.c +@@ -665,7 +665,7 @@ APR_DECLARE(apr_status_t) apr_encode_base32(char *dest, const char *src, + } + + if (len) { +- *len = ((slen + 2) / 3 * 4) + 1; ++ *len = ((slen + 4) / 5 * 8) + 1; + } + + return APR_SUCCESS; +-- +2.39.2 + diff -Nru apr-1.7.0/debian/patches/encoding-Better-check-inputs-of-apr_-encode-decode-_.patch apr-1.7.0/debian/patches/encoding-Better-check-inputs-of-apr_-encode-decode-_.patch --- apr-1.7.0/debian/patches/encoding-Better-check-inputs-of-apr_-encode-decode-_.patch 1970-01-01 00:00:00.000000000 +0000 +++ apr-1.7.0/debian/patches/encoding-Better-check-inputs-of-apr_-encode-decode-_.patch 2023-03-01 14:21:40.000000000 +0000 @@ -0,0 +1,2924 @@ +From: Yann Ylavic +Date: Tue, 18 Oct 2022 07:38:51 +0000 +Subject: encoding: Better check inputs of apr_{encode,decode}_* functions. +Origin: https://github.com/apache/apr/commit/f039abc0c1a70394f8c0595ab3bc8e9aec9da325 +Bug-Debian-Security: https://security-tracker.debian.org/tracker/CVE-2022-24963 + +Check that the given sources can be encoded without overflowing. + +Return APR_EINVAL if the given "slen" is negative, APR_NOTFOUND if "dest" is +not NULL and "src" is NULL, or APR_ENOSPC if "dest" is NULL and the source +length (based on "slen" or APR_ENCODE_STRING) is too big to encode. + +* include/private/apr_encode_private.h(): + Rename ENCODE_TO_ASCII() and ENCODE_TO_NATIVE() to respectively TO_ASCII() + and TO_ENCODE(), and make them return an unsigned char. + +* encoding/apr_escape.c(): + Use the new TO_ASCII() and TO_NATIVE(). + +* encoding/apr_encode.c(apr_encode_*, apr_decode_*): + Forbid negative "slen" but APR_ENCODE_STRING, and use apr_size_t arithmetics + to check for overflows when encoding. + When "dest" is NULL, "src" can be NULL too. + Better check for trailing '='s or base16's APR_ENCODE_COLON ':' separators. + Rename ENCODE_TO_ASCII and ENCODE_TO_NATIVE to their new names, and remove + casts to (unsigned char) now unnecessary. + +* include/apr_encode.h(): + Update dox about acceptable inputs and returned errors. + +* test/testencode.c(): + Tests for error conditions. + + +testencode: Follow up to r1902281: error tests for apr_decode_base16_binary. + + +testencode: Follow up to r1902281: Correct call convention for encdec_fn. + + +testencode: Follow up to r1902281: Correct call convention for encdec_fn (try 2). + + +testencode: Follow up to r1902281: Inline, no calling convention assumptions. + + +Merges r1902281, r1902282, r1902284, r1902285, r1902286 from trunk. + + +git-svn-id: https://svn.apache.org/repos/asf/apr/apr/branches/1.7.x@1904675 13f79535-47bb-0310-9956-ffa450edef68 +--- + encoding/apr_encode.c | 1398 ++++++++++++++------------ + encoding/apr_escape.c | 6 +- + include/apr_encode.h | 407 +++++--- + include/private/apr_encode_private.h | 21 +- + test/testencode.c | 198 ++++ + 5 files changed, 1224 insertions(+), 806 deletions(-) + +diff --git a/encoding/apr_encode.c b/encoding/apr_encode.c +index bc2dc5437990..c18f44285962 100644 +--- a/encoding/apr_encode.c ++++ b/encoding/apr_encode.c +@@ -211,19 +211,20 @@ static const char base16lower[] = "0123456789abcdef"; + 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 @@ APR_DECLARE(apr_status_t) apr_encode_base64(char *dest, const char *src, + 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 (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 < slen) { +- *bufout++ = base[ENCODE_TO_ASCII(((src[i]) >> 2) & 0x3F)]; +- if (i == (slen - 1)) { +- *bufout++ = base[ENCODE_TO_ASCII((((src[i]) & 0x3) << 4))]; ++ 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 @@ APR_DECLARE(apr_status_t) apr_encode_base64_binary(char *dest, const unsigned ch + 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_DECLARE(const char *)apr_pencode_base64(apr_pool_t * p, const char *src, + { + 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_DECLARE(const char *)apr_pencode_base64_binary(apr_pool_t * p, const unsigne + { + 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,157 +396,184 @@ APR_DECLARE(const char *)apr_pencode_base64_binary(apr_pool_t * p, const unsigne + 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 (count && pr2six[*bufin] < 64) { +- count--; +- bufin++; +- } +- nprbytes = bufin - (const unsigned char *)src; +- while (count && pr2six[*bufin] > 64) { ++ 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 (count && pr2six[*bufin] < 64) { +- count--; +- bufin++; +- } +- nprbytes = bufin - (const unsigned char *)src; +- while (count && pr2six[*bufin] > 64) { ++ 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, +@@ -535,14 +581,19 @@ APR_DECLARE(const char *)apr_pdecode_base64(apr_pool_t * p, const char *str, + { + 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; + } + } +@@ -555,15 +606,20 @@ APR_DECLARE(const unsigned char *)apr_pdecode_base64_binary(apr_pool_t * p, + { + 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; + } + } +@@ -574,19 +630,20 @@ APR_DECLARE(const unsigned char *)apr_pdecode_base64_binary(apr_pool_t * p, + 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; +@@ -595,24 +652,26 @@ APR_DECLARE(apr_status_t) apr_encode_base32(char *dest, const char *src, + 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++ = '='; +@@ -622,11 +681,11 @@ APR_DECLARE(apr_status_t) apr_encode_base32(char *dest, const char *src, + *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++ = '='; +@@ -634,13 +693,13 @@ APR_DECLARE(apr_status_t) apr_encode_base32(char *dest, const char *src, + *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++ = '='; +@@ -648,49 +707,51 @@ APR_DECLARE(apr_status_t) apr_encode_base32(char *dest, const char *src, + } + } + 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 + 4) / 5 * 8) + 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; +@@ -699,23 +760,25 @@ APR_DECLARE(apr_status_t) apr_encode_base32_binary(char *dest, const unsigned ch + 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 (i < slen) { ++ 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 < 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++ = '='; +@@ -726,9 +789,9 @@ APR_DECLARE(apr_status_t) apr_encode_base32_binary(char *dest, const unsigned ch + *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)) { +@@ -738,12 +801,12 @@ APR_DECLARE(apr_status_t) apr_encode_base32_binary(char *dest, const unsigned ch + *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++ = '='; +@@ -752,13 +815,13 @@ APR_DECLARE(apr_status_t) apr_encode_base32_binary(char *dest, const unsigned ch + } + } + 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)) { +@@ -767,20 +830,20 @@ APR_DECLARE(apr_status_t) apr_encode_base32_binary(char *dest, const unsigned ch + } + } + +- 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, +@@ -788,13 +851,19 @@ APR_DECLARE(const char *)apr_pencode_base32(apr_pool_t * p, const char *src, + { + 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; + } + } +@@ -807,13 +876,19 @@ APR_DECLARE(const char *)apr_pencode_base32_binary(apr_pool_t * p, const unsigne + { + 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; + } + } +@@ -824,24 +899,20 @@ APR_DECLARE(const char *)apr_pencode_base32_binary(apr_pool_t * p, const unsigne + 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; + } +@@ -850,105 +921,130 @@ APR_DECLARE(apr_status_t) apr_decode_base32(char *dest, const char *src, + } + + bufin = (const unsigned char *)src; +- while (count && pr2[*bufin] < 32) { +- count--; +- bufin++; +- } +- nprbytes = bufin - (const unsigned char *)src; +- while (count && pr2[*bufin] > 32) { ++ 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; ++ ++ if (dest) { ++ unsigned char *bufout; ++ ++ bufout = (unsigned char *)dest; ++ bufin = (const unsigned char *)src; ++ ++ 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; ++ } + +- status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : +- count ? APR_BADCH : APR_SUCCESS; +- +- 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; +- } ++ 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 (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]]); ++ dlen = bufout - (unsigned char *)dest; ++ dest[dlen] = '\0'; + } ++ } + +- if (len) { +- *len = bufout - (unsigned char *)dest; ++ 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; + } +- +- *(bufout++) = 0; +- +- return status; + } + + 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; + } +@@ -957,80 +1053,110 @@ APR_DECLARE(apr_status_t) apr_decode_base32_binary(unsigned char *dest, + } + + bufin = (const unsigned char *)src; +- while (count && pr2[*bufin] < 32) { +- count--; +- bufin++; +- } +- nprbytes = bufin - (const unsigned char *)src; +- while (count && pr2[*bufin] > 32) { ++ 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; ++ ++ if (dest) { ++ unsigned char *bufout; ++ ++ bufout = (unsigned char *)dest; ++ bufin = (const unsigned char *)src; ++ ++ 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; ++ } + +- status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : +- count ? APR_BADCH : APR_SUCCESS; +- +- 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; +- } ++ 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 (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]]); ++ dlen = bufout - dest; + } ++ } + +- if (len) { +- *len = bufout - dest; ++ 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; + } +- +- return status; + } + + 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, +@@ -1038,14 +1164,19 @@ APR_DECLARE(const char *)apr_pdecode_base32(apr_pool_t * p, const char *str, + { + 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; + } + } +@@ -1058,15 +1189,20 @@ APR_DECLARE(const unsigned char *)apr_pdecode_base32_binary(apr_pool_t * p, + { + 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; + } + } +@@ -1077,16 +1213,20 @@ APR_DECLARE(const unsigned char *)apr_pdecode_base32_binary(apr_pool_t * p, + 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_ssize_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; +@@ -1095,51 +1235,51 @@ APR_DECLARE(apr_status_t) apr_encode_base16(char *dest, + 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_ssize_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; +@@ -1148,33 +1288,35 @@ APR_DECLARE(apr_status_t) apr_encode_base16_binary(char *dest, + 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, +@@ -1182,13 +1324,19 @@ APR_DECLARE(const char *)apr_pencode_base16(apr_pool_t * p, + { + 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; + } + } +@@ -1202,13 +1350,19 @@ APR_DECLARE(const char *)apr_pencode_base16_binary(apr_pool_t * p, + { + 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; + } + } +@@ -1219,186 +1373,156 @@ APR_DECLARE(const char *)apr_pencode_base16_binary(apr_pool_t * p, + 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; +- +- 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); + } +- +- count = slen; +- bufin = (const unsigned char *)src; +- while (count && pr2two[*bufin] != 16) { +- count--; +- bufin++; +- } +- nprbytes = bufin - (const unsigned char *)src; +- while (count && pr2two[*bufin] > 16) { +- count--; +- bufin++; ++ else if (slen < 0 || (dest && !src)) { ++ return (src) ? APR_EINVAL : APR_NOTFOUND; + } + +- status = flags & APR_ENCODE_RELAXED ? APR_SUCCESS : +- count ? APR_BADCH : APR_SUCCESS; ++ if (src) { ++ const unsigned char *bufin; + +- 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)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; +- } ++ if (dest) { ++ unsigned char *bufout; + +- *(bufout++) = 0; ++ bufout = (unsigned char *)dest; ++ bufin = (const unsigned char *)src; + +- return status; +- } +- +- 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 (count && pr2two[*bufin] != 16) { +- count--; +- bufin++; +- } +- nprbytes = bufin - (const unsigned char *)src; +- while (count && pr2two[*bufin] > 16) { +- count--; +- bufin++; +- } ++ 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; +- } +- +- else { ++ if (dest) { ++ unsigned char *bufout; + +- count = 0; +- bufin = (const unsigned char *)src; ++ bufout = (unsigned char *)dest; ++ 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, +@@ -1406,14 +1530,19 @@ APR_DECLARE(const char *)apr_pdecode_base16(apr_pool_t * p, + { + 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; + } + } +@@ -1426,15 +1555,20 @@ APR_DECLARE(const unsigned char *)apr_pdecode_base16_binary(apr_pool_t * p, + { + 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; + } + } +diff --git a/encoding/apr_escape.c b/encoding/apr_escape.c +index b3bc82d359f4..6074d739e011 100644 +--- a/encoding/apr_escape.c ++++ b/encoding/apr_escape.c +@@ -131,7 +131,7 @@ static char x2c(const char *what) + 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 @@ APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str, + size--; + } + else { +- *d = ENCODE_TO_ASCII(val); ++ *d = TO_ASCII(val); + found = 1; + } + } +@@ -737,7 +737,7 @@ APR_DECLARE(apr_status_t) apr_unescape_entity(char *unescaped, const char *str, + *d = '&'; /* unknown */ + } + else { +- *d = ENCODE_TO_ASCII(((const unsigned char *) ents)[j]); ++ *d = TO_ASCII(ents[j]); + s += i; + slen -= i; + found = 1; +diff --git a/include/apr_encode.h b/include/apr_encode.h +index 20fc932f6f54..8bae61f7b299 100644 +--- a/include/apr_encode.h ++++ b/include/apr_encode.h +@@ -146,35 +146,44 @@ extern "C" { + + /** + * 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 @@ APR_DECLARE(apr_status_t) apr_encode_base64_binary(char *dest, const unsigned ch + * @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 @@ APR_DECLARE(const char *)apr_pencode_base64(apr_pool_t * p, const char *src, + * @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 @@ APR_DECLARE(apr_status_t) apr_decode_base64_binary(unsigned char *dest, + * 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 @@ APR_DECLARE(const char *)apr_pdecode_base64(apr_pool_t * p, const char *src, + * 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 @@ APR_DECLARE(const unsigned char *)apr_pdecode_base64_binary(apr_pool_t * p, + + /** + * 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 @@ APR_DECLARE(apr_status_t) apr_encode_base32_binary(char *dest, const unsigned ch + * @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 @@ APR_DECLARE(const char *)apr_pencode_base32(apr_pool_t * p, const char *src, + * @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 @@ APR_DECLARE(const char *)apr_pencode_base32_binary(apr_pool_t * p, const unsigne + + /** + * 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 @@ APR_DECLARE(apr_status_t) apr_decode_base32_binary(unsigned char *dest, + * 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 @@ APR_DECLARE(const char *)apr_pdecode_base32(apr_pool_t * p, const char *src, + * 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 @@ APR_DECLARE(const unsigned char *)apr_pdecode_base32_binary(apr_pool_t * p, + + /** + * 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 @@ APR_DECLARE(apr_status_t) apr_encode_base16_binary(char *dest, + * @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 @@ APR_DECLARE(const char *)apr_pencode_base16(apr_pool_t * p, const char *src, + * @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 @@ APR_DECLARE(const char *)apr_pencode_base16_binary(apr_pool_t * p, + + /** + * 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 @@ APR_DECLARE(apr_status_t) apr_decode_base16_binary(unsigned char *dest, + /** + * 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 @@ APR_DECLARE(const char *)apr_pdecode_base16(apr_pool_t * p, const char *src, + /** + * 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) +diff --git a/include/private/apr_encode_private.h b/include/private/apr_encode_private.h +index 8db2e016695e..93ce0a02d6a2 100644 +--- a/include/private/apr_encode_private.h ++++ b/include/private/apr_encode_private.h +@@ -34,7 +34,8 @@ extern "C" { + */ + + #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 @@ extern "C" { + 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 @@ extern "C" { + 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 +diff --git a/test/testencode.c b/test/testencode.c +index ba23aaf2872a..6d783109d5b8 100644 +--- a/test/testencode.c ++++ b/test/testencode.c +@@ -905,6 +905,202 @@ static void test_decode_base16_binary(abts_case * tc, void *data) + 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_suite *testencode(abts_suite * suite) + 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; + } +-- +2.39.1 + diff -Nru apr-1.7.0/debian/patches/series apr-1.7.0/debian/patches/series --- apr-1.7.0/debian/patches/series 2021-08-24 07:18:26.000000000 +0000 +++ apr-1.7.0/debian/patches/series 2023-03-01 14:22:18.000000000 +0000 @@ -13,3 +13,7 @@ python3-hashbang.patch generic-64bit-atomics.patch CVE-2021-35940.patch +Address-some-warnings-raised-by-MSVC-32-64.patch +apr_encode_base32-fix-advertised-output-len-when-cal.patch +apr_decode_base-64-32-16-stop-reading-before-not-inc.patch +encoding-Better-check-inputs-of-apr_-encode-decode-_.patch