base64url/0000755000176200001440000000000013276256704012075 5ustar liggesusersbase64url/inst/0000755000176200001440000000000013117715153013042 5ustar liggesusersbase64url/inst/doc/0000755000176200001440000000000013276254703013614 5ustar liggesusersbase64url/inst/doc/Benchmarks.Rmd0000644000176200001440000000510313250515635016330 0ustar liggesusers--- title: "Benchmark" author: "Michel Lang" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Benchmark} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r,include=FALSE,cache=FALSE} do.eval = requireNamespace("microbenchmark", quietly = TRUE) ``` This small benchmark compares the performance of the base64 encoding/decoding in package `base64url` with the implementations in the packages [`base64enc`](https://cran.r-project.org/package=base64enc) and [`openssl`](https://cran.r-project.org/package=openssl). ## Encoding of a single string ```{r, eval=do.eval} library(base64url) library(base64enc) library(openssl) library(microbenchmark) x = "plain text" microbenchmark( base64url = base64_urlencode(x), base64enc = base64encode(charToRaw(x)), openssl = base64_encode(x) ) ``` ## Decoding of a single string ```{r, eval = do.eval} x = "N0JBLlRaUTp1bi5KOW4xWStNWEJoLHRQaDZ3" microbenchmark( base64url = base64_urldecode(x), base64enc = rawToChar(base64decode(x)), openssl = rawToChar(base64_decode(x)) ) ``` ## Encoding and decoding of character vectors Here, the task has changed from encoding/decoding a single string to processing multiple strings stored inside a character vector. First, we create a small utility function which returns `n` random strings with a random number of characters (between 1 and 32) each. ```{r, eval = do.eval} rand = function(n, min = 1, max = 32) { chars = c(letters, LETTERS, as.character(0:9), c(".", ":", ",", "+", "-", "*", "/")) replicate(n, paste0(sample(chars, sample(min:max, 1), replace = TRUE), collapse = "")) } set.seed(1) rand(10) ``` Only `base64url` is vectorized for string input, the alternative implementations need wrappers to process character vectors: ```{r, eval = do.eval} base64enc_encode = function(x) { vapply(x, function(x) base64encode(charToRaw(x)), NA_character_, USE.NAMES = FALSE) } openssl_encode = function(x) { vapply(x, function(x) base64_encode(x), NA_character_, USE.NAMES = FALSE) } base64enc_decode = function(x) { vapply(x, function(x) rawToChar(base64decode(x)), NA_character_, USE.NAMES = FALSE) } openssl_decode = function(x) { vapply(x, function(x) rawToChar(base64_decode(x)), NA_character_, USE.NAMES = FALSE) } ``` The following benchmark measures the runtime to encode 1000 random strings and then decode them again: ```{r, eval = do.eval} set.seed(1) x = rand(1000) microbenchmark( base64url = base64_urldecode(base64_urlencode(x)), base64enc = base64enc_decode(base64enc_encode(x)), openssl = openssl_decode(openssl_encode(x)) ) ``` base64url/inst/doc/Benchmarks.html0000644000176200001440000004067213276254703016570 0ustar liggesusers Benchmark

Benchmark

Michel Lang

2018-05-14

This small benchmark compares the performance of the base64 encoding/decoding in package base64url with the implementations in the packages base64enc and openssl.

Encoding of a single string

library(base64url)
library(base64enc)
library(openssl)
library(microbenchmark)

x = "plain text"
microbenchmark(
  base64url = base64_urlencode(x),
  base64enc = base64encode(charToRaw(x)),
  openssl = base64_encode(x)
)
## Unit: nanoseconds
##       expr   min      lq     mean  median      uq    max neval
##  base64url   408   461.5   853.52   698.0   782.5  20430   100
##  base64enc  1199  1367.0  3114.89  1865.0  1983.5 139937   100
##    openssl 13188 13536.0 15256.11 13749.5 14081.5 135871   100

Decoding of a single string

x = "N0JBLlRaUTp1bi5KOW4xWStNWEJoLHRQaDZ3"
microbenchmark(
  base64url = base64_urldecode(x),
  base64enc = rawToChar(base64decode(x)),
  openssl = rawToChar(base64_decode(x))
)
## Unit: nanoseconds
##       expr   min      lq     mean  median    uq    max neval
##  base64url   423   485.0  1104.57   655.5   923  40442   100
##  base64enc  1504  1681.5  2879.92  2225.5  2546  76432   100
##    openssl 19066 19643.0 21264.27 19915.5 20281 119636   100

Encoding and decoding of character vectors

Here, the task has changed from encoding/decoding a single string to processing multiple strings stored inside a character vector. First, we create a small utility function which returns n random strings with a random number of characters (between 1 and 32) each.

rand = function(n, min = 1, max = 32) {
  chars = c(letters, LETTERS, as.character(0:9), c(".", ":", ",", "+", "-", "*", "/"))
  replicate(n, paste0(sample(chars, sample(min:max, 1), replace = TRUE), collapse = ""))
}
set.seed(1)
rand(10)
##  [1] "zN.n9+TRe"                     "mVA1IX/"                      
##  [3] "1,oSisAaA8xHP"                 "m5U2hXC4S2MK2bGY"             
##  [5] "G7EqegvJTC.uFwSrH0f8x5x"       "G97A1-DXBw0"                  
##  [7] "XiqjqeS"                       "13FC3PTys/RoiG:P*YyDkaXhES/IH"
##  [9] "0FJopP"                        "fcS,PMK*JVPqrYFmZh7"

Only base64url is vectorized for string input, the alternative implementations need wrappers to process character vectors:

base64enc_encode = function(x) {
  vapply(x, function(x) base64encode(charToRaw(x)), NA_character_, USE.NAMES = FALSE)
}

openssl_encode = function(x) {
  vapply(x, function(x) base64_encode(x), NA_character_, USE.NAMES = FALSE)
}

base64enc_decode = function(x) {
  vapply(x, function(x) rawToChar(base64decode(x)), NA_character_, USE.NAMES = FALSE)
}

openssl_decode = function(x) {
  vapply(x, function(x) rawToChar(base64_decode(x)), NA_character_, USE.NAMES = FALSE)
}

The following benchmark measures the runtime to encode 1000 random strings and then decode them again:

set.seed(1)
x = rand(1000)
microbenchmark(
  base64url = base64_urldecode(base64_urlencode(x)),
  base64enc = base64enc_decode(base64enc_encode(x)),
  openssl = openssl_decode(openssl_encode(x))
)
## Unit: microseconds
##       expr       min         lq      mean     median        uq       max
##  base64url   214.031   222.0655   270.415   260.3725   311.967   441.127
##  base64enc  3613.444  3974.8940  4228.395  4058.2495  4157.485 11094.540
##    openssl 34166.572 35453.3810 36002.175 35794.9835 36349.533 42507.878
##  neval
##    100
##    100
##    100
base64url/inst/doc/Benchmarks.R0000644000176200001440000000345013276254702016015 0ustar liggesusers## ----include=FALSE,cache=FALSE------------------------------------------- do.eval = requireNamespace("microbenchmark", quietly = TRUE) ## ---- eval=do.eval------------------------------------------------------- library(base64url) library(base64enc) library(openssl) library(microbenchmark) x = "plain text" microbenchmark( base64url = base64_urlencode(x), base64enc = base64encode(charToRaw(x)), openssl = base64_encode(x) ) ## ---- eval = do.eval----------------------------------------------------- x = "N0JBLlRaUTp1bi5KOW4xWStNWEJoLHRQaDZ3" microbenchmark( base64url = base64_urldecode(x), base64enc = rawToChar(base64decode(x)), openssl = rawToChar(base64_decode(x)) ) ## ---- eval = do.eval----------------------------------------------------- rand = function(n, min = 1, max = 32) { chars = c(letters, LETTERS, as.character(0:9), c(".", ":", ",", "+", "-", "*", "/")) replicate(n, paste0(sample(chars, sample(min:max, 1), replace = TRUE), collapse = "")) } set.seed(1) rand(10) ## ---- eval = do.eval----------------------------------------------------- base64enc_encode = function(x) { vapply(x, function(x) base64encode(charToRaw(x)), NA_character_, USE.NAMES = FALSE) } openssl_encode = function(x) { vapply(x, function(x) base64_encode(x), NA_character_, USE.NAMES = FALSE) } base64enc_decode = function(x) { vapply(x, function(x) rawToChar(base64decode(x)), NA_character_, USE.NAMES = FALSE) } openssl_decode = function(x) { vapply(x, function(x) rawToChar(base64_decode(x)), NA_character_, USE.NAMES = FALSE) } ## ---- eval = do.eval----------------------------------------------------- set.seed(1) x = rand(1000) microbenchmark( base64url = base64_urldecode(base64_urlencode(x)), base64enc = base64enc_decode(base64enc_encode(x)), openssl = openssl_decode(openssl_encode(x)) ) base64url/tests/0000755000176200001440000000000013250475371013232 5ustar liggesusersbase64url/tests/testthat.R0000644000176200001440000000007613250475371015220 0ustar liggesuserslibrary(testthat) library(base64url) test_check("base64url") base64url/tests/testthat/0000755000176200001440000000000013276256704015077 5ustar liggesusersbase64url/tests/testthat/test_base32.R0000644000176200001440000000323113250515635017330 0ustar liggesuserscontext("base32") test_that("encode and decode on random strings", { for (i in 1:10) { plain = rand(1000) enc = base32_encode(plain, use.padding = TRUE) expect_character(enc, any.missing = FALSE, len = length(plain), pattern = "^[A-Z234567=]+$") unenc = base32_decode(enc, use.padding = TRUE) expect_character(unenc, any.missing = FALSE, len = length(plain), min.chars = 1L) expect_equal(plain, unenc) } }) test_that("unexpected input", { expect_identical(base32_encode("", use.padding = TRUE), "") expect_identical(base32_decode("", use.padding = TRUE), "") expect_identical(base32_encode(NA_character_, use.padding = TRUE), NA_character_) expect_identical(base32_decode(NA_character_, use.padding = TRUE), NA_character_) expect_identical(base32_encode(character(0), use.padding = TRUE), character(0)) expect_identical(base32_decode(character(0), use.padding = TRUE), character(0)) expect_error(base32_encode(NA, use.padding = TRUE), "character vector") expect_error(base32_decode(NA, use.padding = TRUE), "character vector") expect_identical(base32_encode("", use.padding = FALSE), "") expect_identical(base32_decode("", use.padding = FALSE), "") expect_identical(base32_encode(NA_character_, use.padding = FALSE), NA_character_) expect_identical(base32_decode(NA_character_, use.padding = FALSE), NA_character_) expect_identical(base32_encode(character(0), use.padding = FALSE), character(0)) expect_identical(base32_decode(character(0), use.padding = FALSE), character(0)) expect_error(base32_encode(NA, use.padding = FALSE), "character vector") expect_error(base32_decode(NA, use.padding = FALSE), "character vector") }) base64url/tests/testthat/helper.R0000644000176200001440000000054013274032514016465 0ustar liggesuserslibrary(testthat) library(checkmate) rand = function(n, min = 5L, max = 50L, only.ascii = FALSE) { chars = c(letters, LETTERS, c("=", "+", "-", "_", "/", "&", "=", "?", ":", ".", "%")) if (!isTRUE(only.ascii)) chars = c(chars, "ö", "`", "\n", "♏") replicate(n, paste0(sample(chars, sample(min:max, 1L), replace = TRUE), collapse = "")) } base64url/tests/testthat/test_base64.R0000644000176200001440000000700213274541441017335 0ustar liggesuserscontext("base64url") requireNamespace("base64enc", quietly = TRUE) is_utf8 = function() { grepl("utf-?8", Sys.getlocale("LC_CTYPE"), ignore.case = TRUE) } convert_to_url = function(x) { x = gsub("/", "_", x, fixed = TRUE) x = gsub("+", "-", x, fixed = TRUE) gsub("=+$", "", x) } convert_to_rfc = function(x) { x = gsub("_", "/", x, fixed = TRUE) x = gsub("-", "+", x, fixed = TRUE) pad = nchar(x) %% 4 paste0(x, strrep("=", ifelse(pad == 0L, 0L, 4L - pad))) } base64enc_rfc = function(x) { vapply(x, function(x) base64enc::base64encode(charToRaw(x)), NA_character_, USE.NAMES = FALSE) } base64dec_rfc = function(x) { vapply(x, function(x) rawToChar(base64enc::base64decode(x)), NA_character_, USE.NAMES = FALSE) } base64enc_openssl = function(x) { vapply(x, function(x) openssl::base64_encode(x), NA_character_, USE.NAMES = FALSE) } base64dec_openssl = function(x) { vapply(x, function(x) rawToChar(openssl::base64_decode(x)), NA_character_, USE.NAMES = FALSE) } test_that("encode and decode on random strings", { for (i in 1:10) { plain = rand(1000) enc = base64_urlencode(plain) expect_character(enc, any.missing = FALSE, len = length(plain), pattern = "^[[:alnum:]_-]+$") unenc = base64_urldecode(enc) expect_character(unenc, any.missing = FALSE, len = length(plain), min.chars = 1L) expect_equal(plain, unenc) } }) test_that("comparison with base64enc", { for (i in 1:10) { # base64enc seems to have problems with the encoding :/ # rfc <-> rfc is not working! plain = rand(1000, only.ascii = testOS("windows") || !is_utf8()) enc_rfc = base64enc_rfc(plain) enc_url = base64_urlencode(plain) # do we get plain back? expect_equal(plain, base64_urldecode(enc_url), label = "url <-> url works") expect_equal(plain, base64dec_rfc(enc_rfc), label = "rfc <-> rfc works") # do we get the same encoding as rfc? expect_equal(enc_url, convert_to_url(enc_rfc)) expect_equal(enc_rfc, convert_to_rfc(enc_url)) # do we get the same decodings after conversion? expect_equal(plain, base64_urldecode(convert_to_url(enc_rfc))) expect_equal(plain, base64dec_rfc(convert_to_rfc(enc_url))) } }) test_that("comparison with openssl", { for (i in 1:10) { # openssl seems to have problems with the encoding on windows :/ # openssl <-> openssl is not working! plain = rand(1000, only.ascii = testOS("windows") || !is_utf8()) enc_openssl = base64enc_openssl(plain) enc_url = base64_urlencode(plain) # do we get plain back? expect_equal(plain, base64_urldecode(enc_url), label = "url <-> url works") expect_equal(plain, base64dec_openssl(enc_openssl), label = "openssl <-> openssl works") # do we get the same encoding as openssl? expect_equal(enc_url, convert_to_url(enc_openssl)) expect_equal(enc_openssl, convert_to_rfc(enc_url)) # do we get the same decodings after conversion? expect_equal(plain, base64_urldecode(convert_to_url(enc_openssl))) expect_equal(plain, base64dec_openssl(convert_to_rfc(enc_url))) } }) test_that("unexpected input", { expect_identical(base64_urlencode(""), "") expect_identical(base64_urldecode(""), "") expect_identical(base64_urlencode(NA_character_), NA_character_) expect_identical(base64_urldecode(NA_character_), NA_character_) expect_identical(base64_urlencode(character(0)), character(0)) expect_identical(base64_urldecode(character(0)), character(0)) expect_error(base64_urlencode(NA), "character vector") expect_error(base64_urldecode(NA), "character vector") }) base64url/src/0000755000176200001440000000000013276254703012661 5ustar liggesusersbase64url/src/base64.c0000644000176200001440000001453313276254703014117 0ustar liggesusers/* Original source code taken from * https://svn.apache.org/repos/asf/apr/apr/trunk/encoding/apr_base64.c * * Changes by Michel Lang : * - Replaced char 62 ('+') with '-' * - Replaced char 63 ('/') with '_' * - Removed padding with '=' at the end of the string * - Changed return type to void for Base64decode and Base64encode * - Added wrappers for R * */ /* * base64.c: base64 encoding and decoding functions * * ==================================================================== * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * ==================================================================== */ #include #include #include static const unsigned char pr2six[256] = { 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 62, 64, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 64, 64, 64, 64, 64, 64, 64, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 64, 64, 64, 64, 63, 64, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64, 64 }; static const char basis_64[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_"; static int Base64decode_len(const char *bufcoded) { int nbytesdecoded; register const unsigned char *bufin; register int nprbytes; bufin = (const unsigned char *) bufcoded; while (pr2six[*(bufin++)] <= 63); nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; nbytesdecoded = ((nprbytes + 3) / 4) * 3; return nbytesdecoded + 1; } static int Base64encode_len(int len) { return ((len + 2) / 3 * 4) + 1; } static void Base64decode(char *bufplain, const char *bufcoded) { register const unsigned char *bufin; register unsigned char *bufout; register int nprbytes; bufin = (const unsigned char *) bufcoded; while (pr2six[*(bufin++)] <= 63); nprbytes = (bufin - (const unsigned char *) bufcoded) - 1; bufout = (unsigned char *) bufplain; bufin = (const unsigned char *) bufcoded; while (nprbytes > 4) { *(bufout++) = (unsigned char) (pr2six[*bufin] << 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; } if (nprbytes > 1) *(bufout++) = (unsigned char) (pr2six[*bufin] << 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]]); *(bufout++) = '\0'; } static void Base64encode(char *encoded, const char *string, int len) { int i; char *p = encoded; for (i = 0; i < len - 2; i += 3) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2) | ((int) (string[i + 2] & 0xC0) >> 6)]; *p++ = basis_64[string[i + 2] & 0x3F]; } if (i < len) { *p++ = basis_64[(string[i] >> 2) & 0x3F]; if (i == (len - 1)) { *p++ = basis_64[((string[i] & 0x3) << 4)]; } else { *p++ = basis_64[((string[i] & 0x3) << 4) | ((int) (string[i + 1] & 0xF0) >> 4)]; *p++ = basis_64[((string[i + 1] & 0xF) << 2)]; } } *p++ = '\0'; } SEXP b64e(SEXP strings) { if (!isString(strings)) error("Argument must be a character vector"); const R_xlen_t n = xlength(strings); SEXP result = PROTECT(allocVector(STRSXP, n)); for (R_xlen_t i = 0; i < n; i++) { if (STRING_ELT(strings, i) == NA_STRING) { SET_STRING_ELT(result, i, NA_STRING); } else { const char *plain = translateCharUTF8(STRING_ELT(strings, i)); char *encoded = malloc(sizeof(char) * Base64encode_len(strlen(plain))); Base64encode(encoded, plain, strlen(plain)); SET_STRING_ELT(result, i, mkCharCE(encoded, CE_ANY)); free(encoded); } } UNPROTECT(1); return result; } SEXP b64d(SEXP strings) { if (!isString(strings)) error("Argument must be a character vector"); const R_xlen_t n = xlength(strings); SEXP result = PROTECT(allocVector(STRSXP, n)); for (R_xlen_t i = 0; i < n; i++) { if (STRING_ELT(strings, i) == NA_STRING) { SET_STRING_ELT(result, i, NA_STRING); } else { const char *encoded = translateCharUTF8(STRING_ELT(strings, i)); char *plain = malloc(sizeof(char) * Base64decode_len(encoded)); Base64decode(plain, encoded); SET_STRING_ELT(result, i, mkCharCE(plain, CE_UTF8)); free(plain); } } UNPROTECT(1); return result; } base64url/src/init.c0000644000176200001440000000105713276254703013773 0ustar liggesusers#include #include #include // for NULL #include /* .Call calls */ extern SEXP b32d(SEXP); extern SEXP b32e(SEXP); extern SEXP b64d(SEXP); extern SEXP b64e(SEXP); static const R_CallMethodDef CallEntries[] = { {"b32d", (DL_FUNC) &b32d, 1}, {"b32e", (DL_FUNC) &b32e, 1}, {"b64d", (DL_FUNC) &b64d, 1}, {"b64e", (DL_FUNC) &b64e, 1}, {NULL, NULL, 0} }; void R_init_base64url(DllInfo *dll) { R_registerRoutines(dll, NULL, CallEntries, NULL, NULL); R_useDynamicSymbols(dll, FALSE); } base64url/src/base32.c0000644000176200001440000002606313276254703014113 0ustar liggesusers/* base32.c -- Encode binary data using printable characters. Copyright (C) 1999, 2000, 2001, 2004, 2005, 2006, 2010 Free Software Foundation, Inc. This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */ /* Adapted from base64.{h,c} by Ondřej Surý. base64.{h,c} was written * by Simon Josefsson. Partially adapted from GNU MailUtils * (mailbox/filter_trans.c, as of 2004-11-28). Improved by review * from Paul Eggert, Bruno Haible, and Stepan Kasal. * * Interface for R package by Michel Lang. */ #include #include #include #include #include static inline unsigned char to_uchar(char ch) { return ch; } static const char b32str[32] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ234567"; void base32_encode(const char *in, size_t inlen, char *out) { while (inlen) { *out++ = b32str[(to_uchar(in[0]) >> 3) & 0x1f]; *out++ = b32str[((to_uchar(in[0]) << 2) + (--inlen ? to_uchar(in[1]) >> 6 : 0)) & 0x1f]; *out++ = (inlen ? b32str[(to_uchar(in[1]) >> 1) & 0x1f] : '='); *out++ = (inlen ? b32str[((to_uchar(in[1]) << 4) + (--inlen ? to_uchar(in[2]) >> 4 : 0)) & 0x1f] : '='); *out++ = (inlen ? b32str[((to_uchar(in[2]) << 1) + (--inlen ? to_uchar(in[3]) >> 7 : 0)) & 0x1f] : '='); *out++ = (inlen ? b32str[(to_uchar(in[3]) >> 2) & 0x1f] : '='); *out++ = (inlen ? b32str[((to_uchar(in[3]) << 3) + (--inlen ? to_uchar(in[4]) >> 5 : 0)) & 0x1f] : '='); *out++ = inlen ? b32str[to_uchar(in[4]) & 0x1f] : '='; if (inlen) inlen--; if (inlen) in += 5; } *out++ = '\0'; } #define B32(_) \ ((_) == 'A' ? 0 \ : (_) == 'B' ? 1 \ : (_) == 'C' ? 2 \ : (_) == 'D' ? 3 \ : (_) == 'E' ? 4 \ : (_) == 'F' ? 5 \ : (_) == 'G' ? 6 \ : (_) == 'H' ? 7 \ : (_) == 'I' ? 8 \ : (_) == 'J' ? 9 \ : (_) == 'K' ? 10 \ : (_) == 'L' ? 11 \ : (_) == 'M' ? 12 \ : (_) == 'N' ? 13 \ : (_) == 'O' ? 14 \ : (_) == 'P' ? 15 \ : (_) == 'Q' ? 16 \ : (_) == 'R' ? 17 \ : (_) == 'S' ? 18 \ : (_) == 'T' ? 19 \ : (_) == 'U' ? 20 \ : (_) == 'V' ? 21 \ : (_) == 'W' ? 22 \ : (_) == 'X' ? 23 \ : (_) == 'Y' ? 24 \ : (_) == 'Z' ? 25 \ : (_) == '2' ? 26 \ : (_) == '3' ? 27 \ : (_) == '4' ? 28 \ : (_) == '5' ? 29 \ : (_) == '6' ? 30 \ : (_) == '7' ? 31 \ : -1) static const signed char b32[0x100] = { B32 (0), B32 (1), B32 (2), B32 (3), B32 (4), B32 (5), B32 (6), B32 (7), B32 (8), B32 (9), B32 (10), B32 (11), B32 (12), B32 (13), B32 (14), B32 (15), B32 (16), B32 (17), B32 (18), B32 (19), B32 (20), B32 (21), B32 (22), B32 (23), B32 (24), B32 (25), B32 (26), B32 (27), B32 (28), B32 (29), B32 (30), B32 (31), B32 (32), B32 (33), B32 (34), B32 (35), B32 (36), B32 (37), B32 (38), B32 (39), B32 (40), B32 (41), B32 (42), B32 (43), B32 (44), B32 (45), B32 (46), B32 (47), B32 (48), B32 (49), B32 (50), B32 (51), B32 (52), B32 (53), B32 (54), B32 (55), B32 (56), B32 (57), B32 (58), B32 (59), B32 (60), B32 (61), B32 (62), B32 (63), B32 (64), B32 (65), B32 (66), B32 (67), B32 (68), B32 (69), B32 (70), B32 (71), B32 (72), B32 (73), B32 (74), B32 (75), B32 (76), B32 (77), B32 (78), B32 (79), B32 (80), B32 (81), B32 (82), B32 (83), B32 (84), B32 (85), B32 (86), B32 (87), B32 (88), B32 (89), B32 (90), B32 (91), B32 (92), B32 (93), B32 (94), B32 (95), B32 (96), B32 (97), B32 (98), B32 (99), B32 (100), B32 (101), B32 (102), B32 (103), B32 (104), B32 (105), B32 (106), B32 (107), B32 (108), B32 (109), B32 (110), B32 (111), B32 (112), B32 (113), B32 (114), B32 (115), B32 (116), B32 (117), B32 (118), B32 (119), B32 (120), B32 (121), B32 (122), B32 (123), B32 (124), B32 (125), B32 (126), B32 (127), B32 (128), B32 (129), B32 (130), B32 (131), B32 (132), B32 (133), B32 (134), B32 (135), B32 (136), B32 (137), B32 (138), B32 (139), B32 (140), B32 (141), B32 (142), B32 (143), B32 (144), B32 (145), B32 (146), B32 (147), B32 (148), B32 (149), B32 (150), B32 (151), B32 (152), B32 (153), B32 (154), B32 (155), B32 (156), B32 (157), B32 (158), B32 (159), B32 (160), B32 (161), B32 (162), B32 (163), B32 (164), B32 (165), B32 (166), B32 (167), B32 (168), B32 (169), B32 (170), B32 (171), B32 (172), B32 (173), B32 (174), B32 (175), B32 (176), B32 (177), B32 (178), B32 (179), B32 (180), B32 (181), B32 (182), B32 (183), B32 (184), B32 (185), B32 (186), B32 (187), B32 (188), B32 (189), B32 (190), B32 (191), B32 (192), B32 (193), B32 (194), B32 (195), B32 (196), B32 (197), B32 (198), B32 (199), B32 (200), B32 (201), B32 (202), B32 (203), B32 (204), B32 (205), B32 (206), B32 (207), B32 (208), B32 (209), B32 (210), B32 (211), B32 (212), B32 (213), B32 (214), B32 (215), B32 (216), B32 (217), B32 (218), B32 (219), B32 (220), B32 (221), B32 (222), B32 (223), B32 (224), B32 (225), B32 (226), B32 (227), B32 (228), B32 (229), B32 (230), B32 (231), B32 (232), B32 (233), B32 (234), B32 (235), B32 (236), B32 (237), B32 (238), B32 (239), B32 (240), B32 (241), B32 (242), B32 (243), B32 (244), B32 (245), B32 (246), B32 (247), B32 (248), B32 (249), B32 (250), B32 (251), B32 (252), B32 (253), B32 (254), B32 (255) }; #if UCHAR_MAX == 255 #define uchar_in_range(c) true #else #define uchar_in_range(c) ((c) <= 255) #endif static bool isbase32(char ch) { return uchar_in_range(to_uchar(ch)) && 0 <= b32[to_uchar(ch)]; } static bool base32_decode(const char *in, size_t inlen, char *out, size_t *outlen) { size_t outleft = *outlen; while (inlen >= 2) { if (!isbase32(in[0]) || !isbase32(in[1])) break; if (outleft) { *out++ = ((b32[to_uchar(in[0])] << 3) | (b32[to_uchar(in[1])] >> 2)); outleft--; } if (inlen == 2) break; if (in[2] == '=') { if (inlen != 8) break; if ((in[3] != '=') || (in[4] != '=') || (in[5] != '=') || (in[6] != '=') || (in[7] != '=')) break; } else { if (!isbase32(in[2]) || !isbase32(in[3])) break; if (outleft) { *out++ = ((b32[to_uchar(in[1])] << 6) | ((b32[to_uchar(in[2])] << 1) & 0x3E) | (b32[to_uchar(in[3])] >> 4)); outleft--; } if (inlen == 4) break; if (in[4] == '=') { if (inlen != 8) break; if ((in[5] != '=') || (in[6] != '=') || (in[7] != '=')) break; } else { if (!isbase32 (in[3]) || !isbase32(in[4])) break; if (outleft) { *out++ = ((b32[to_uchar(in[3])] << 4) | (b32[to_uchar(in[4])] >> 1)); outleft--; } if (inlen == 5) break; if (in[5] == '=') { if (inlen != 8) break; if ((in[6] != '=') || (in[7] != '=')) break; } else { if (!isbase32 (in[5]) || !isbase32 (in[6])) break; if (outleft) { *out++ = ((b32[to_uchar(in[4])] << 7) | (b32[to_uchar(in[5])] << 2) | (b32[to_uchar(in[6])] >> 3)); outleft--; } if (inlen == 7) break; if (in[7] == '=') { if (inlen != 8) break; } else { if (!isbase32 (in[7])) break; if (outleft) { *out++ = ((b32[to_uchar(in[6])] << 5) | (b32[ to_uchar(in[7])])); outleft--; } } } } } in += 8; inlen -= 8; } *out++ = '\0'; return (inlen == 0); } SEXP b32e(SEXP strings) { if (!isString(strings)) error("Argument must be a character vector"); const R_xlen_t n = xlength(strings); SEXP result = PROTECT(allocVector(STRSXP, n)); for (R_xlen_t i = 0; i < n; i++) { if (STRING_ELT(strings, i) == NA_STRING) { SET_STRING_ELT(result, i, NA_STRING); } else { const char *plain = translateCharUTF8(STRING_ELT(strings, i)); R_len_t n_in = strlen(plain); R_len_t n_out = 1 + ((n_in + 4) / 5) * 8; if (n_in > n_out) { UNPROTECT(1); error("Input is too long"); } char *encoded = malloc(n_out); if (encoded == NULL) { free(encoded); UNPROTECT(1); error("Failed to allocate memory"); } base32_encode(plain, n_in, encoded); SET_STRING_ELT(result, i, mkCharCE(encoded, CE_ANY)); free(encoded); } } UNPROTECT(1); return result; } SEXP b32d(SEXP strings) { if (!isString(strings)) error("Argument must be a character vector"); const R_xlen_t n = xlength(strings); SEXP result = PROTECT(allocVector(STRSXP, n)); for (R_xlen_t i = 0; i < n; i++) { if (STRING_ELT(strings, i) == NA_STRING) { SET_STRING_ELT(result, i, NA_STRING); } else { const char *encoded = translateCharUTF8(STRING_ELT(strings, i)); R_len_t n_in = strlen(encoded); if (n_in == 0) { SET_STRING_ELT(result, i, mkChar("")); } else { size_t n_out = 5 * (n_in / 8) + 4; char *plain = malloc(n_out); if (plain == NULL) { free(plain); UNPROTECT(1); error("Failed to allocate memory"); } if (!base32_decode(encoded, n_in, plain, &n_out) || (n_out == 0 && n_in > 0)) { free(plain); UNPROTECT(1); error("Error decoding string from base32"); } SET_STRING_ELT(result, i, mkCharCE(plain, CE_UTF8)); free(plain); } } } UNPROTECT(1); return result; } base64url/NAMESPACE0000644000176200001440000000036413107542550013305 0ustar liggesusers# Generated by roxygen2: do not edit by hand export(base32_decode) export(base32_encode) export(base64_urldecode) export(base64_urlencode) useDynLib(base64url,b32d) useDynLib(base64url,b32e) useDynLib(base64url,b64d) useDynLib(base64url,b64e) base64url/NEWS.md0000644000176200001440000000101713274542374013171 0ustar liggesusers# base64url 1.4 * Disabled tests which compared encodings of non-ascii strings to encodings in packages `base64enc` and `openssl` on some systems. # base64url 1.3 * Fixed decoding on windows for input encoded in native encoding. # base64url 1.2 * Native routines are now registered. * Vignette builds without `microbenchmark` installed. * Update to new backports. # base64url 1.1 * Added `base32_encode()` and `base32_decode()`. * Changed license to GPL-3. * Fixed vignette title. # base64url 1.0 * Initial release. base64url/R/0000755000176200001440000000000013274540254012270 5ustar liggesusersbase64url/R/base32.R0000644000176200001440000000260713274540254013477 0ustar liggesusers#' @title Encode to base32 or Decode from base32 #' #' @description #' Simple RFC4648 base32 encoder/decoder. Pads with \dQuote{=}. #' #' @param x [\code{character(1)}]\cr #' Character vector to encode or decode. #' @param use.padding [\code{logical(1)}]\cr #' If \code{TRUE}, \code{base32_encode} returns a string whose length is a multiple of 8, #' padded with trailing \dQuote{=} if required. #' \code{base32_decode} expects such a string unless this is set to \code{FALSE} (default). #' The internal algorithm currently works with padding, thus it is faster to set this to \code{TRUE}. #' @return [\code{character}] of the same length as input \code{x}. #' @references Implementation based on base32 encoder/decoder in the GNU lib: \url{https://www.gnu.org/software/gnulib/}. #' @useDynLib base64url b32e #' @export #' @examples #' x = "plain text" #' encoded = base32_encode(x) #' decoded = base32_decode(encoded) #' print(encoded) #' print(decoded) base32_encode = function(x, use.padding = FALSE) { res = .Call(b32e, enc2utf8(x)) if (isTRUE(use.padding)) return(res) sub("=+$", "", res) } #' @rdname base32_encode #' @useDynLib base64url b32d #' @export base32_decode = function(x, use.padding = FALSE) { if (!isTRUE(use.padding)) { i = which(!is.na(x) & nzchar(x)) if (length(i)) x[i] = paste0(x[i], strrep("=", 7L - ((nchar(x[i]) - 1L) %% 8L))) } .Call(b32d, x) } base64url/R/base64.R0000644000176200001440000000216513250515635013502 0ustar liggesusers#' @title Encode to base64 or Decode from base64 #' #' @description #' In contrast to RFC3548, the 62nd character (\sQuote{+}) is replaced with \sQuote{-}, the 63rd character (\sQuote{/}) is replaced with \sQuote{_}. #' Furthermore, the encoder does not fill the string with trailing \sQuote{=}. #' The resulting encoded strings comply to the regular expression pattern \dQuote{[A-Za-z0-9_-]} and thus are safe to use in URLs #' or for file names. #' #' @param x [\code{character(1)}]\cr #' Character vector to encode or decode. #' #' @return [\code{character}] of the same length as input \code{x}. #' @references Implementation based on base64 encoder/decoder in the Apache Portable Runtime (APR): \url{https://svn.apache.org/repos/asf/apr/apr/trunk/encoding/apr_base64.c} #' @useDynLib base64url b64e #' @export #' @examples #' x = "plain text" #' encoded = base64_urlencode(x) #' decoded = base64_urldecode(encoded) #' print(encoded) #' print(decoded) base64_urlencode = function(x) { .Call(b64e, enc2utf8(x)) } #' @rdname base64_urlencode #' @useDynLib base64url b64d #' @export base64_urldecode = function(x) { .Call(b64d, x) } base64url/R/zzz.R0000644000176200001440000000012013250451706013236 0ustar liggesusers.onLoad = function(libname, pkgname) { backports::import(pkgname, "strrep") } base64url/vignettes/0000755000176200001440000000000013276254703014102 5ustar liggesusersbase64url/vignettes/Benchmarks.Rmd0000644000176200001440000000510313250515635016616 0ustar liggesusers--- title: "Benchmark" author: "Michel Lang" date: "`r Sys.Date()`" output: rmarkdown::html_vignette vignette: > %\VignetteIndexEntry{Benchmark} %\VignetteEngine{knitr::rmarkdown} %\VignetteEncoding{UTF-8} --- ```{r,include=FALSE,cache=FALSE} do.eval = requireNamespace("microbenchmark", quietly = TRUE) ``` This small benchmark compares the performance of the base64 encoding/decoding in package `base64url` with the implementations in the packages [`base64enc`](https://cran.r-project.org/package=base64enc) and [`openssl`](https://cran.r-project.org/package=openssl). ## Encoding of a single string ```{r, eval=do.eval} library(base64url) library(base64enc) library(openssl) library(microbenchmark) x = "plain text" microbenchmark( base64url = base64_urlencode(x), base64enc = base64encode(charToRaw(x)), openssl = base64_encode(x) ) ``` ## Decoding of a single string ```{r, eval = do.eval} x = "N0JBLlRaUTp1bi5KOW4xWStNWEJoLHRQaDZ3" microbenchmark( base64url = base64_urldecode(x), base64enc = rawToChar(base64decode(x)), openssl = rawToChar(base64_decode(x)) ) ``` ## Encoding and decoding of character vectors Here, the task has changed from encoding/decoding a single string to processing multiple strings stored inside a character vector. First, we create a small utility function which returns `n` random strings with a random number of characters (between 1 and 32) each. ```{r, eval = do.eval} rand = function(n, min = 1, max = 32) { chars = c(letters, LETTERS, as.character(0:9), c(".", ":", ",", "+", "-", "*", "/")) replicate(n, paste0(sample(chars, sample(min:max, 1), replace = TRUE), collapse = "")) } set.seed(1) rand(10) ``` Only `base64url` is vectorized for string input, the alternative implementations need wrappers to process character vectors: ```{r, eval = do.eval} base64enc_encode = function(x) { vapply(x, function(x) base64encode(charToRaw(x)), NA_character_, USE.NAMES = FALSE) } openssl_encode = function(x) { vapply(x, function(x) base64_encode(x), NA_character_, USE.NAMES = FALSE) } base64enc_decode = function(x) { vapply(x, function(x) rawToChar(base64decode(x)), NA_character_, USE.NAMES = FALSE) } openssl_decode = function(x) { vapply(x, function(x) rawToChar(base64_decode(x)), NA_character_, USE.NAMES = FALSE) } ``` The following benchmark measures the runtime to encode 1000 random strings and then decode them again: ```{r, eval = do.eval} set.seed(1) x = rand(1000) microbenchmark( base64url = base64_urldecode(base64_urlencode(x)), base64enc = base64enc_decode(base64enc_encode(x)), openssl = openssl_decode(openssl_encode(x)) ) ``` base64url/README.md0000644000176200001440000000271113050560115013335 0ustar liggesusers# base64url [![CRAN_Status_Badge](http://www.r-pkg.org/badges/version/base64url)](https://cran.r-project.org/package=base64url) [![Build Status](https://travis-ci.org/mllg/base64url.svg?branch=master)](https://travis-ci.org/mllg/base64url) [![Build status](https://ci.appveyor.com/api/projects/status/5329u3dk9vanak0p/branch/master?svg=true)](https://ci.appveyor.com/project/mllg/base64url/branch/master) [![Coverage Status](https://coveralls.io/repos/github/mllg/base64url/badge.svg?branch=master)](https://coveralls.io/github/mllg/base64url?branch=master) In contrast to base64 RFC3548, the 62nd character (`'+'`) is replaced with `'-'`, the 63rd character (`'/'`) is replaced with `'_'`. Furthermore, the encoder does not fill the string with trailing `'='`. The resulting encoded strings comply to the regular expression pattern `'[A-Za-z0-9_-]'` and thus are safe to use in URLs or for file names. For a small benchmark, see the [vignette](https://cran.r-project.org/package=base64url/vignettes/Benchmarks.html). As of version 1.1, this package also ships with a simple base32 encoder/decoder suited to mangle file names on case insensitive file systems. ## Installation For the stable release, just install the latest version from [CRAN](https://cran.r-project.org/package=base64url): ```{R} install.packages("base64url") ``` For the development version, use [devtools](https://cran.r-project.org/package=devtools): ```{R} devtools::install_github("mllg/base64url") ``` base64url/MD50000644000176200001440000000207013276256704012404 0ustar liggesuserse355c9b8a74fab1f617fce3a9bec3a15 *DESCRIPTION 335b7504e8adcce63098535682e25a70 *NAMESPACE b147fa3663f670544c1fc96629d28c35 *NEWS.md a77070d468abfe4b9fb0a5b06e808b68 *R/base32.R 70f61389e5460a5ed43bf3518f94e698 *R/base64.R fd5a1b9c4c9d8dd8341730b115e2e223 *R/zzz.R 16598200d896ab87200bdd82659cce2e *README.md d1923a9bbcf5e350a05ec142b87b4888 *build/vignette.rds 398ae3d85788dd220714ce1a4040ecad *inst/doc/Benchmarks.R 1cf1683e35aed4221cbe354532f237a2 *inst/doc/Benchmarks.Rmd a8df367d1d980742b08565e1802a8bf1 *inst/doc/Benchmarks.html e2e6da0556cca19b1dc57b7d399fe5b1 *man/base32_encode.Rd af0c6709af82452c6aa3198e3173060d *man/base64_urlencode.Rd 22a9d873171d8bff0b74008e6c48dbc9 *src/base32.c 524e0e81ff1053c24afbc59bb303f0a7 *src/base64.c 12187d1e3b809360057f7f46bfc5332b *src/init.c c62047c9d0508b07ad001a6c12e60507 *tests/testthat.R 019194c2e00257695eca1a1deabd8176 *tests/testthat/helper.R 46fd84e71926e7f95bcaa6a27b0bfbb0 *tests/testthat/test_base32.R 8c1f82519156b8043a73b8608b69f3cb *tests/testthat/test_base64.R 1cf1683e35aed4221cbe354532f237a2 *vignettes/Benchmarks.Rmd base64url/build/0000755000176200001440000000000013276254703013171 5ustar liggesusersbase64url/build/vignette.rds0000644000176200001440000000030613276254703015527 0ustar liggesusersb```b`f@&0`b fd`a|NyEzA)hpY4 ~$m%9h<ȦA Zּb4]R RR@g;<E T [fN*ސ89 d Bw(,/׃ @?{49'ݣ\)%ziE@ wbase64url/DESCRIPTION0000644000176200001440000000270013276256704013602 0ustar liggesusersPackage: base64url Type: Package Title: Fast and URL-Safe Base64 Encoder and Decoder Version: 1.4 Authors@R: c( person("Michel", "Lang", NULL, "michellang@gmail.com", role = c("cre", "aut"), comment = c(ORCID = "0000-0001-9754-0393")), person(NULL, "Apache Foundation", NULL, NULL, role = c("ctb", "cph")), person(NULL, "Free Software Foundation", NULL, NULL, role = c("ctb", "cph")) ) Description: In contrast to RFC3548, the 62nd character ("+") is replaced with "-", the 63rd character ("/") is replaced with "_". Furthermore, the encoder does not fill the string with trailing "=". The resulting encoded strings comply to the regular expression pattern "[A-Za-z0-9_-]" and thus are safe to use in URLs or for file names. The package also comes with a simple base32 encoder/decoder suited for case insensitive file systems. URL: https://github.com/mllg/base64url BugReports: https://github.com/mllg/base64url/issues NeedsCompilation: yes License: GPL-3 Encoding: UTF-8 Imports: backports (>= 1.1.0) Suggests: base64enc, checkmate, knitr, microbenchmark, openssl, rmarkdown, testthat RoxygenNote: 6.0.1 VignetteBuilder: knitr Packaged: 2018-05-14 09:41:23 UTC; lang Author: Michel Lang [cre, aut] (), Apache Foundation [ctb, cph], Free Software Foundation [ctb, cph] Maintainer: Michel Lang Repository: CRAN Date/Publication: 2018-05-14 09:58:28 UTC base64url/man/0000755000176200001440000000000013050560115012630 5ustar liggesusersbase64url/man/base64_urlencode.Rd0000644000176200001440000000211213050560115016237 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/base64.R \name{base64_urlencode} \alias{base64_urlencode} \alias{base64_urldecode} \title{Encode to base64 or Decode from base64} \usage{ base64_urlencode(x) base64_urldecode(x) } \arguments{ \item{x}{[\code{character(1)}]\cr Character vector to encode or decode.} } \value{ [\code{character}] of the same length as input \code{x}. } \description{ In contrast to RFC3548, the 62nd character (\sQuote{+}) is replaced with \sQuote{-}, the 63rd character (\sQuote{/}) is replaced with \sQuote{_}. Furthermore, the encoder does not fill the string with trailing \sQuote{=}. The resulting encoded strings comply to the regular expression pattern \dQuote{[A-Za-z0-9_-]} and thus are safe to use in URLs or for file names. } \examples{ x = "plain text" encoded = base64_urlencode(x) decoded = base64_urldecode(encoded) print(encoded) print(decoded) } \references{ Implementation based on base64 encoder/decoder in the Apache Portable Runtime (APR): \url{https://svn.apache.org/repos/asf/apr/apr/trunk/encoding/apr_base64.c} } base64url/man/base32_encode.Rd0000644000176200001440000000214313050560115015513 0ustar liggesusers% Generated by roxygen2: do not edit by hand % Please edit documentation in R/base32.R \name{base32_encode} \alias{base32_encode} \alias{base32_decode} \title{Encode to base32 or Decode from base32} \usage{ base32_encode(x, use.padding = FALSE) base32_decode(x, use.padding = FALSE) } \arguments{ \item{x}{[\code{character(1)}]\cr Character vector to encode or decode.} \item{use.padding}{[\code{logical(1)}]\cr If \code{TRUE}, \code{base32_encode} returns a string whose length is a multiple of 8, padded with trailing \dQuote{=} if required. \code{base32_decode} expects such a string unless this is set to \code{FALSE} (default). The internal algorithm currently works with padding, thus it is faster to set this to \code{TRUE}.} } \value{ [\code{character}] of the same length as input \code{x}. } \description{ Simple RFC4648 base32 encoder/decoder. Pads with \dQuote{=}. } \examples{ x = "plain text" encoded = base32_encode(x) decoded = base32_decode(encoded) print(encoded) print(decoded) } \references{ Implementation based on base32 encoder/decoder in the GNU lib: \url{https://www.gnu.org/software/gnulib/}. }