1#' Encode/decode data into/from base64 encoding.
2#'
3#' The function \code{base64_encode()} encodes a file or a raw vector into the
4#' base64 encoding. The function \code{base64_decode()} decodes data from the
5#' base64 encoding.
6#' @param x For \code{base64_encode()}, a raw vector. If not raw, it is assumed
7#'   to be a file or a connection to be read via \code{readBin()}. For
8#'   \code{base64_decode()}, a string.
9#' @param from If provided (and \code{x} is not provided), a connection or file
10#'   to be read via \code{readChar()}, and the result will be passed to the
11#'   argument \code{x}.
12#' @return \code{base64_encode()} returns a character string.
13#'   \code{base64_decode()} returns a raw vector.
14#' @useDynLib xfun, .registration = TRUE
15#' @export
16#' @examples xfun::base64_encode(as.raw(1:10))
17#' logo = xfun:::R_logo()
18#' xfun::base64_encode(logo)
19base64_encode = function(x) {
20  if (!is.raw(x)) x = read_bin(x)
21  .Call('base64_enc', x, PACKAGE = 'xfun')
22}
23
24#' @export
25#' @rdname base64_encode
26#' @examples xfun::base64_decode("AQIDBAUGBwgJCg==")
27base64_decode = function(x, from = NA) {
28  if (!is.na(from)) {
29    if (!missing(x)) stop("Please provide either 'x' or 'from', but not both.")
30    x = readChar(from, file.size(from), TRUE)
31  }
32  if (!is.character(x) || length(x) != 1) stop("'x' must be a single character string.")
33  .Call('base64_dec', x, PACKAGE = 'xfun')
34}
35
36# an R implementation of base64 encoding by Wush Wu moved from knitr (of
37# historic interest only): https://github.com/yihui/knitr/pull/324
38base64_encode_r = function(x) {
39  if (!is.raw(x)) x = read_bin(x)
40  chars = c(LETTERS, letters, 0:9, '+', '/')
41  n = length(s <- as.integer(x))
42  res = rep(NA, (n + 2) / 3 * 4)
43  i = 0L  # index of res vector
44  j = 1L  # index of base64_table
45  while (n > 2L) {
46    res[i <- i + 1L] = chars[s[j] %/% 4L + 1L]
47    res[i <- i + 1L] = chars[16 * (s[j] %% 4L) + s[j + 1L] %/% 16 + 1L]
48    res[i <- i + 1L] = chars[4L * (s[j + 1L] %% 16) + s[j + 2L] %/% 64L + 1L]
49    res[i <- i + 1L] = chars[s[j + 2L] %% 64L + 1L]
50    j = j + 3L
51    n = n - 3L
52  }
53  if (n) {
54    res[i <- i + 1L] = chars[s[j] %/% 4L + 1L]
55    if (n > 1L) {
56      res[i <- i + 1L] = chars[16 * (s[j] %% 4L) + s[j + 1L] %/% 16 + 1L]
57      res[i <- i + 1L] = chars[4L * (s[j + 1L] %% 16) + 1L]
58      res[i <- i + 1L] = '='
59    } else {
60      res[i <- i + 1L] = chars[16 * (s[j] %% 4L) + 1L]
61      res[i <- i + 1L] = '='
62      res[i <- i + 1L] = '='
63    }
64  }
65  paste(res[!is.na(res)], collapse = '')
66}
67
68#' Generate the Data URI for a file
69#'
70#' Encode the file in the base64 encoding, and add the media type. The data URI
71#' can be used to embed data in HTML documents, e.g., in the \code{src}
72#' attribute of the \verb{<img />} tag.
73#' @param x A file path.
74#' @return A string of the form \verb{data:<media type>;base64,<data>}.
75#' @export
76#' @examples
77#' logo = xfun:::R_logo()
78#' img = htmltools::img(src = xfun::base64_uri(logo), alt = 'R logo')
79#' if (interactive()) htmltools::browsable(img)
80base64_uri = function(x) {
81  paste0("data:", mime::guess_type(x), ";base64,", base64_encode(x))
82}
83