From: Dmitry Volyntsev Date: Fri, 30 Mar 2018 12:46:38 +0000 (+0300) Subject: Added base64 encoding for byte strings. X-Git-Tag: 0.2.0~9 X-Git-Url: http://git.kaiwu.me/postgresql/log/contrib/postgres_fdw/static/gitweb.js?a=commitdiff_plain;h=61b5c2452457122f3c269c75f304cf116de95e7d;p=njs.git Added base64 encoding for byte strings. --- diff --git a/njs/njs_string.c b/njs/njs_string.c index 972cfab8..7842b4b8 100644 --- a/njs/njs_string.c +++ b/njs/njs_string.c @@ -79,6 +79,8 @@ typedef struct { } njs_string_replace_t; +static void njs_encode_base64_core(nxt_str_t *dst, const nxt_str_t *src, + const u_char *basis, nxt_uint_t padding); static nxt_noinline void njs_string_slice_prop(njs_string_prop_t *string, njs_slice_prop_t *slice, njs_value_t *args, nxt_uint_t nargs); static nxt_noinline void njs_string_slice_args(njs_slice_prop_t *slice, @@ -119,6 +121,9 @@ static njs_ret_t njs_string_decode(njs_vm_t *vm, njs_value_t *value, const uint32_t *reserve); +#define njs_base64_encoded_length(len) (((len + 2) / 3) * 4) + + njs_ret_t njs_string_create(njs_vm_t *vm, njs_value_t *value, u_char *start, uint32_t size, uint32_t length) @@ -275,6 +280,135 @@ njs_string_hex(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src) } +static void +njs_encode_base64(nxt_str_t *dst, const nxt_str_t *src) +{ + static u_char basis64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; + + njs_encode_base64_core(dst, src, basis64, 1); +} + + +static void +njs_encode_base64url(nxt_str_t *dst, const nxt_str_t *src) +{ + static u_char basis64[] = + "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; + + njs_encode_base64_core(dst, src, basis64, 0); +} + + +static void +njs_encode_base64_core(nxt_str_t *dst, const nxt_str_t *src, + const u_char *basis, nxt_bool_t padding) +{ + u_char *d, *s, c0, c1, c2; + size_t len; + + len = src->length; + s = src->start; + d = dst->start; + + while (len > 2) { + c0 = s[0]; + c1 = s[1]; + c2 = s[2]; + + *d++ = basis[c0 >> 2]; + *d++ = basis[((c0 & 0x03) << 4) | (c1 >> 4)]; + *d++ = basis[((c1 & 0x0f) << 2) | (c2 >> 6)]; + *d++ = basis[c2 & 0x3f]; + + s += 3; + len -= 3; + } + + if (len > 0) { + c0 = s[0]; + *d++ = basis[c0 >> 2]; + + if (len == 1) { + *d++ = basis[(c0 & 0x03) << 4]; + if (padding) { + *d++ = '='; + *d++ = '='; + } + + } else { + c1 = s[1]; + + *d++ = basis[((c0 & 0x03) << 4) | (c1 >> 4)]; + *d++ = basis[(c1 & 0x0f) << 2]; + + if (padding) { + *d++ = '='; + } + } + + } + + dst->length = d - dst->start; +} + + +nxt_noinline njs_ret_t +njs_string_base64(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src) +{ + nxt_str_t dst; + + if (nxt_slow_path(src->length == 0)) { + vm->retval = njs_string_empty; + return NXT_OK; + } + + dst.length = njs_base64_encoded_length(src->length); + + dst.start = njs_string_alloc(vm, &vm->retval, dst.length, dst.length); + if (nxt_slow_path(dst.start == NULL)) { + njs_memory_error(vm); + return NXT_ERROR; + } + + njs_encode_base64(&dst, src); + + return NXT_OK; +} + + +nxt_noinline njs_ret_t +njs_string_base64url(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src) +{ + size_t padding; + nxt_str_t dst; + + if (nxt_slow_path(src->length == 0)) { + vm->retval = njs_string_empty; + return NXT_OK; + } + + padding = src->length % 3; + + /* + * Calculating the padding length: 0 -> 0, 1 -> 2, 2 -> 1. + */ + padding = (4 >> padding) & 0x03; + + dst.length = njs_base64_encoded_length(src->length) - padding; + + dst.start = njs_string_alloc(vm, &vm->retval, dst.length, dst.length); + if (nxt_slow_path(dst.start == NULL)) { + njs_memory_error(vm); + return NXT_ERROR; + } + + njs_encode_base64url(&dst, src); + + return NXT_OK; +} + + void njs_string_copy(njs_value_t *dst, njs_value_t *src) { diff --git a/njs/njs_string.h b/njs/njs_string.h index 0735d331..6e9c82c0 100644 --- a/njs/njs_string.h +++ b/njs/njs_string.h @@ -124,6 +124,10 @@ njs_ret_t njs_string_new(njs_vm_t *vm, njs_value_t *value, const u_char *start, uint32_t size, uint32_t length); njs_ret_t njs_string_hex(njs_vm_t *vm, njs_value_t *value, const nxt_str_t *src); +njs_ret_t njs_string_base64(njs_vm_t *vm, njs_value_t *value, + const nxt_str_t *src); +njs_ret_t njs_string_base64url(njs_vm_t *vm, njs_value_t *value, + const nxt_str_t *src); void njs_string_copy(njs_value_t *dst, njs_value_t *src); njs_ret_t njs_string_validate(njs_vm_t *vm, njs_string_prop_t *string, njs_value_t *value);