base64enc/0000755000175000017500000000000012152654731013342 5ustar sebastiansebastianbase64enc/NAMESPACE0000644000175000017500000000014612077376145014570 0ustar sebastiansebastianuseDynLib(base64enc, B64_encode, B64_decode, C_URIencode) export(base64encode, base64decode, dataURI) base64enc/NEWS0000644000175000017500000000032412077376145014046 0ustar sebastiansebastian0.1-1 2012-11-05 o fix a bug in base64decode where output is a file name o add base64decode(file=...) as a (non-leaking) shorthand for base64decode(file(...)) 0.1-0 2012-09-07 o initial CRAN release base64enc/DESCRIPTION0000644000175000017500000000066712077376146015070 0ustar sebastiansebastianPackage: base64enc Version: 0.1-1 Title: Tools for base64 encoding Author: Simon Urbanek Maintainer: Simon Urbanek Depends: R (>= 2.9.0) Enhances: png Description: This package provides tools for handling base64 encoding. It is more flexible than the orphaned base64 package. License: GPL-2 | GPL-3 URL: http://www.rforge.net/base64enc Packaged: 2013-01-22 02:41:42 UTC; svnuser base64enc/man/0000755000175000017500000000000012077376146014124 5ustar sebastiansebastianbase64enc/man/dataURI.Rd0000644000175000017500000000260012077376145015701 0ustar sebastiansebastian\name{dataURI} \alias{dataURI} \title{ Create a data URI string } \description{ \code{dataURI} creates URI with the \code{data:} scheme by encoding the payload either using base64 ot URI encoding. } \usage{ dataURI(data, mime = "", encoding = "base64", file) } \arguments{ \item{data}{raw vector, connection or character vector to use as payload. Character vectors of more than one element are collapsed using \code{"\n"} before encoding.} \item{mime}{MIME-type of the data (per standard "" is interpreted as "text/plain;charset=US-ASCII" without including it in the URI)} \item{encoding}{data encoding to use. Must be either \code{"base64"} or \code{NULL}} \item{file}{filename (string) to open as payload. \code{file} and \code{data} are mutually exclusive} } %\details{ %} \value{ string of the form \code{data:[mime][;base64],} } \references{ \href{http://tools.ietf.org/html/rfc2397}{RFC 2397 The "data" URL scheme} } \author{ Simon Urbanek } %\note{ %} \examples{ dataURI(as.raw(1:10)) # default is base64 dataURI(as.raw(1:10), encoding=NULL) # URI if (require("png", quietly=TRUE)) { # let's say you have an image - e.g. from dev.capture(TRUE) img <- matrix(1:16/16, 4) dataURI(writePNG(img), "image/png") # or straight from a file dataURI(file=system.file("img", "Rlogo.png", package="png"), mime="image/png") } } \keyword{manip} base64enc/man/base64.Rd0000644000175000017500000000432612077376145015503 0ustar sebastiansebastian\name{base64} \alias{base64} \alias{base64encode} \alias{base64decode} \title{ Encode/decode data into/from base64 encoding } \description{ \code{base64encode} encodes a data into base64 encoding. The source can be a file, binary connection or a raw vector. \code{base64decode} decodes a base64-encoded string into binary data. The source can be a string or a connection, the output is either a raw vector (\code{output=NULL}) or a binary connection. } \usage{ base64encode(what, linewidth, newline) base64decode(what, output = NULL, file) } \arguments{ \item{what}{data to be encoded/decoded. For \code{base64encode} it can be a raw vector, text connection or file name. For \code{base64decode} it can be a string or a binary connection.} \item{linewidth}{if set, the output is split into lines with at most \code{linewidth} characters per line. Zero or \code{NA} denotes no limit and values 1 .. 3 are silently treated as 4 since that is the shortest valid line.} \item{newline}{only applicable if \code{linewidth} is set; if set (string), the result will be a single string with all lines joined using the \code{newline} string} \item{output}{if \code{NULL} then the output will be a raw vector with the decoded data, otherwise it must be either a filename (string) or a binary connection.} \item{file}{file name (string) for data to use as input instead of \code{what}. It is essentially just a shorthand for \code{base64decode(file(name))}. Only one of \code{what} and \code{file} can be specified.} } %\details{ %} \value{ \code{base64encode}: A character vector. If \code{linewith > 0} and \code{newline} is not set then it will consist of as many elements as there are lines. Otherwise it is a single string. \code{base64decode}: If \code{output = NULL} then a raw vector with the decoded content, otherwise the number of bytes written into the connection. } %\references{ %} \author{ Simon Urbanek } %\note{ %} %\seealso{ %} \examples{ base64encode(1:100) base64encode(1:100, 70) base64encode(1:100, 70, "\n") x <- charToRaw("the decoded content, otherwise the number of bytes") y <- base64decode(base64encode(x)) stopifnot(identical(x, y)) } \keyword{manip} base64enc/src/0000755000175000017500000000000012077376146014140 5ustar sebastiansebastianbase64enc/src/base64.c0000644000175000017500000001223012077376146015366 0ustar sebastiansebastian/* base64.c - encoding/decoding of base64 (C)Copyright 2011,12 Simon Urbanek Licensed under a choice of GPLv2 or GPLv3 */ /* int for now but it should be something like R_xlen_t -- must be signed, though! */ #define blen_t int /* -- base64 encode/decode -- */ static char *base64encode(const unsigned char *src, blen_t len, char *dst); static int base64decode(const char *src, void *dst, blen_t max_len); static const char *b64tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; #define SRC(i) ((i < len) ? src[i] : 0) /* guarded access to src[] */ /* dst must be at least (len + 2) / 3 * 4 + 1 bytes long and will be NUL terminated when done */ static char *base64encode(const unsigned char *src, blen_t len, char *dst) { while (len >= 3) { /* no need to worry about padding - faster */ *(dst++) = b64tab[src[0] >> 2]; *(dst++) = b64tab[((src[0] & 0x03) << 4) | ((src[1] & 0xf0) >> 4)]; *(dst++) = b64tab[((src[1] & 0x0f) << 2) | ((src[2] & 0xc0) >> 6)]; *(dst++) = b64tab[src[2] & 0x3f]; src += 3; len -= 3; } if (len > 0) { /* last chunk - may need padding and guarding against OOB */ *(dst++) = b64tab[src[0] >> 2]; *(dst++) = b64tab[((src[0] & 0x03) << 4) | ((SRC(1) & 0xf0) >> 4)]; *(dst++) = (len > 1) ? b64tab[((src[1] & 0x0f) << 2) | ((SRC(2) & 0xc0) >> 6)] : '='; *(dst++) = (len > 2) ? b64tab[src[2] & 0x3f] : '='; } *dst = 0; return dst; } #undef SRC static unsigned int val(const char **src) { while (1) { char c = **src; if (c) src[0]++; else return 0x10000; if (c >= 'A' && c <= 'Z') return c - 'A'; if (c >= 'a' && c <= 'z') return c - 'a' + 26; if (c >= '0' && c <= '9') return c - '0' + 52; if (c == '+') return 62; if (c == '/') return 63; if (c == '=') return 0x10000; /* we loop as to skip any blanks, newlines etc. */ } } /* returns the decoded length or -1 if max_len was not enough */ static int base64decode(const char *src, void *dst, blen_t max_len) { unsigned char *t = (unsigned char*) dst, *end = t + max_len; while (*src && t < end) { unsigned int v = val(&src); if (v > 64) break; *t = v << 2; v = val(&src); *t |= v >> 4; if (v < 64) { if (++t == end) return -1; *t = v << 4; v = val(&src); *t |= v >> 2; if (v < 64) { if (++t == end) return -1; *t = v << 6; v = val(&src); *t |= v & 0x3f; if (v < 64) t++; } } } return (blen_t) (t - (unsigned char*) dst); } static char stb[8192]; #include #include SEXP B64_encode(SEXP what, SEXP linewidth, SEXP newline) { const char *nl = 0; char *buf = stb; const unsigned char *src = (const unsigned char*) RAW(what); blen_t buflen = sizeof(stb), slice; int lwd = 0, len = LENGTH(what), step; if (len == 0) return allocVector(STRSXP, 0); if (TYPEOF(newline) == STRSXP && LENGTH(newline) > 0) nl = CHAR(STRING_ELT(newline, 0)); if (TYPEOF(linewidth) == INTSXP || TYPEOF(linewidth) == REALSXP) lwd = asInteger(linewidth); if (lwd <= 0) lwd = 0; else if (lwd < 4) lwd = 4; /* there must be at least 4 chars per line */ lwd -= lwd & 3; step = lwd / 4 * 3; /* make sure we get big enough buffer for what we need to do */ if (lwd == 0 || nl) { blen_t nll = nl ? strlen(nl) : 0; slice = (blen_t) len * 4 / 3 + 4; if (lwd && nll) slice += (slice / lwd + 1) * nll; if (slice > buflen) { buf = R_alloc(256, (slice >> 8) + 1); /* making sure we can use at least 73 bits where possible */ buflen = slice; } if (lwd == 0 || len <= step) { /* easy, jsut call encode and out */ base64encode(src, len, buf); return mkString(buf); } /* one string but with NLs */ { char *dst = buf; while (len) { int amt = (len > step) ? step : len; dst = base64encode(src, amt, dst); src += amt; len -= amt; if (len) { strcpy(dst, nl); dst += nll; } } return mkString(buf); } } else { /* lwd and no nl = vector result */ int i = 0; SEXP res = PROTECT(allocVector(STRSXP, len / step + 1)); slice = lwd + 1; if (slice > buflen) { buf = R_alloc(4, (slice >> 2) + 1); buflen = slice; } while(len) { int amt = (len > step) ? step : len; base64encode(src, amt, buf); src += amt; SET_STRING_ELT(res, i++, mkChar(buf)); len -= amt; } if (i < LENGTH(res)) SETLENGTH(res, i); UNPROTECT(1); return res; } } SEXP B64_decode(SEXP what) { /* we need to allocate enough space to decode. FIXME: For now, we assume it's full of payload; we will over-allocate if there is junk behind it */ blen_t tl = 0; SEXP res; int ns = LENGTH(what), i; unsigned char *dst; if (TYPEOF(what) != STRSXP) Rf_error("I can only decode base64 strings"); for (i = 0; i < ns; i++) tl += strlen(CHAR(STRING_ELT(what, i))); tl = (tl / 4) * 3 + 4; res = allocVector(RAWSXP, tl); dst = (unsigned char*) RAW(res); for (i = 0; i < ns; i++) { blen_t al = base64decode(CHAR(STRING_ELT(what, i)), dst, tl); if (al < 0) /* this should never happen as we allocated enough space ... */ Rf_error("decoding error - insufficient buffer space"); tl -= al; dst += al; } SETLENGTH(res, dst - ((unsigned char*) RAW(res))); return res; } base64enc/src/uriencode.c0000644000175000017500000000410312077376146016257 0ustar sebastiansebastian#include #include static const char *plain = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_.~"; static const char *hex = "0123456789ABCDEF"; /* flexible and fast for long strings. Since short string are, well, short, the overhead of building a table should play no role */ SEXP C_URIencode(SEXP what, SEXP resrv) { SEXP res; char tab[256]; const unsigned char *c = (const unsigned char*) plain; if (TYPEOF(what) != STRSXP && TYPEOF(what) != RAWSXP) Rf_error("input must be a raw or character vector"); memset(tab, 0, sizeof(tab)); while (*c) tab[*(c++)] = 1; if (TYPEOF(resrv) == STRSXP) { int n = LENGTH(resrv), i; for (i = 0; i < n; i++) { c = (const unsigned char*) CHAR(STRING_ELT(resrv, i)); while (*c) tab[*(c++)] = 1; } } if (TYPEOF(what) == RAWSXP) { int len = 0; const unsigned char *cend = (c = (const unsigned char*) RAW(what)) + LENGTH(what); char *enc, *ce; while (c < cend) len += tab[*(c++)] ? 1 : 3; ce = enc = (char*) R_alloc(1, len + 1); c = (const unsigned char*) RAW(what); while (c < cend) if (tab[*c]) *(ce++) = *(c++); else { *(ce++) = '%'; *(ce++) = hex[*c >> 4]; *(ce++) = hex[*(c++) & 0x0F]; } *ce = 0; return mkString(enc); } else { int i, n = LENGTH(what), maxlen = 0; char *enc, *ce; res = allocVector(STRSXP, n); if (n == 0) return res; PROTECT(res); /* find the longest encoded string to allocate buffer */ for (i = 0; i < n; i++) { /* FIXME: we should tanslate to UTF8 */ int len = 0; c = (const unsigned char*) CHAR(STRING_ELT(what, i)); while (*c) len += tab[*(c++)] ? 1 : 3; if (len > maxlen) maxlen = len; } enc = (char*) R_alloc(1, maxlen + 1); for (i = 0; i < n; i++) { c = (const unsigned char*) CHAR(STRING_ELT(what, i)); ce = enc; while (*c) if (tab[*c]) *(ce++) = *(c++); else { *(ce++) = '%'; *(ce++) = hex[*c >> 4]; *(ce++) = hex[*(c++) & 0x0F]; } *ce = 0; SET_STRING_ELT(res, i, mkChar(enc)); } UNPROTECT(1); return res; } } base64enc/R/0000755000175000017500000000000012077376146013552 5ustar sebastiansebastianbase64enc/R/base64.R0000644000175000017500000000342612077376145014765 0ustar sebastiansebastianbase64encode <- function(what, linewidth, newline) { linewidth <- if (missing(linewidth) || !is.numeric(linewidth) || length(linewidth) < 1L) 0L else as.integer(linewidth[1L]) if (is.na(linewidth)) linewidth <- 0L else if (linewidth > 0L && linewidth < 4L) linewidth <- 4L if (missing(newline)) newline <- NULL fi <- NULL if (is.character(what)) { what <- file(what, "rb") on.exit(close(what)) } if (inherits(what, "connection")) { slice <- 65536L ## default slice size if (linewidth > 0L) { ## we have to make sure the slices span whole lines if (linewidth %% 4L > 0) linewidth <- linewidth - linewidth %% 4L bw <- as.integer(linewidth / 4L) * 3L if (slice %% bw > 0L) slice <- slice + (bw - (slice %% bw)) } l <- list() while (length(r <- readBin(what, raw(0), slice))) l <- c(l, .Call(B64_encode, r, linewidth, newline)) if (linewidth > 0L && is.null(newline)) unlist(l) else paste(unlist(l), collapse = if (is.null(newline)) "" else newline) } else .Call(B64_encode, as.raw(what), linewidth, newline) } base64decode <- function(what, output=NULL, file) { if (!missing(file) && !missing(what)) stop("'what' and 'file' are mutually exclusive") if (!missing(file)) { what <- file(file, "r") on.exit(close(what)) } if (is.character(output)) { output <- file(output, "wb") on.exit(close(output)) } else if (!inherits(output, "connection") && !is.null(output)) stop("output must be a filename, connection or NULL") r <- if (inherits(what, "connection")) { ## FIXME: we may want to use chunking ... .Call(B64_decode, readLines(what, warn=FALSE)) } else .Call(B64_decode, what) if (inherits(output, "connection")) { writeBin(r, output) invisible(length(r)) } else r } base64enc/R/URI.R0000644000175000017500000000026312077376145014334 0ustar sebastiansebastianURIencode <- function(what, reserved=NULL) .Call(C_URIencode, what, if (is.logical(reserved)) { if (isTRUE(reserved == FALSE)) ";/?:@=&" else "" } else as.character(reserved)) base64enc/R/dataURI.R0000644000175000017500000000154712077376145015174 0ustar sebastiansebastiandataURI <- function(data, mime="", encoding="base64", file) { if (!is.null(encoding) && !isTRUE(encoding == "base64")) stop('encoding must be either NULL or "base64"') prefix <- paste("data:", as.character(mime)[1], if (!is.null(encoding)) ";base64", ",", sep ='') if (!missing(file)) { if (!missing(data)) stop("data and file are mutually exclusive") data <- con <- file(file, "rb") on.exit(close(con)) } if (inherits(data, "connection")) { if (isTRUE(summary(data)$text == "binary")) { l <- list() while (length(r <- readBin(data, raw(0), 1048576L))) l <- c(l, r) data <- unlist(l) } else data <- readLines(data) } if (!is.raw(data)) data <- paste(as.character(data), collapse='\n') paste(prefix, if (is.null(encoding)) .Call(C_URIencode, data, NULL) else .Call(B64_encode, data, 0L, NULL), sep='') }