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 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 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133
|
#===========================================================================#
# caTools - R library #
# Copyright (C) 2005 Jarek Tuszynski #
# Distributed under GNU General Public License version 3 #
#===========================================================================#
#===============================================================================
# The Base64 encoding is designed to encode arbitrary binary information for
# transmission by electronic mail. It is defined by MIME (Multipurpose Internet
# Mail Extensions) specification RFC 1341, RFC 1421, RFC 2045 and others.
# Triplets of 8-bit octets are encoded as groups of four characters, each
# representing 6 bits of the source 24 bits. Only a 65-character subset
# ([A-Z,a-z,0-9,+,/,=]) present in all variants of ASCII and EBCDIC is used,
# enabling 6 bits to be represented per printable character
#===============================================================================
base64encode = function(x, size=NA, endian=.Platform$endian)
{
library(bitops) # needed for bitOr and bitAnd
if (typeof(x)!="raw") x = writeBin(x, raw(), size=size, endian=endian)
x = as.integer(x)
ndByte = length(x) # number of decoded bytes
nBlock = ceiling(ndByte / 3) # number of blocks/groups
neByte = 4 * nBlock # number of encoded bytes
# add padding if necessary, to make the length of x a multiple of 3
if (ndByte < 3*nBlock) x[(ndByte+1) : (3*nBlock)] = 0;
dim(x) = c(3, nBlock) # reshape the data
y = matrix(as.integer(0), 4, nBlock) # for the encoded data
#-------------------------------------------
# Split up every 3 bytes into 4 pieces
# x = aaaaaabb bbbbcccc ccdddddd
# to form
# y = 00aaaaaa 00bbbbbb 00cccccc 00dddddd
# than convert y to integers in 0-63 range
# This section is based on Matlab code by Peter Acklam
# http://home.online.no/~pjacklam/matlab/software/util/datautil/
#-------------------------------------------
y[1,] = bitShiftR(x[1,], 2) # 6 highest bits of x(1,:)
y[2,] = bitOr(bitShiftL(x[1,], 4), bitShiftR(x[2,], 4))
y[3,] = bitOr(bitShiftL(x[2,], 2), bitShiftR(x[3,], 6))
y[4,] = x[3,]
y = bitAnd(y, 63) # trim numbers to lower 6-bits
#----------------------------------
# Perform the following mapping
# 0 - 25 -> A-Z
# 26 - 51 -> a-z
# 52 - 61 -> 0-9
# 62 -> +
# 63 -> /
#----------------------------------
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
alpha = strsplit(alpha, NULL)[[1]] # convert string to array of characters
z = alpha[y+1] # rearrange characters
#-------------------------
# Add padding if necessary.
#-------------------------
npbytes = 3 * nBlock - ndByte # number of padding bytes needed
if (npbytes>0) z[(neByte-npbytes+1) : neByte] = '=' # '=' is used for padding
z = paste(z, collapse = "") # combine characters into a string
return (z)
}
#====================================================================
base64decode = function(z, what, size=NA, signed = TRUE, endian=.Platform$endian)
{
library(bitops) # needed for bitOr and bitAnd
if (!is.character(z))
stop("base64decode: Input argument 'z' is suppose to be a string")
if (length(z)==1) z = strsplit(z, NULL)[[1]] # convert string to array of characters
if (length(z)%%4!=0)
warning("In base64decode: Length of base64 data (z) not a multiple of 4.")
#-----------------------------------
# Now perform the following mapping
# A-Z -> 0 - 25
# a-z -> 26 - 51
# 0-9 -> 52 - 61
# + -> 62
# / -> 63
# = -> 64 - special padding character
# otherwise -1
#-----------------------------------
alpha = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/="
alpha = strsplit(alpha, NULL)[[1]] # convert string to array of characters
y = match(z, alpha, nomatch=-1)-1 # lookup number of each character
if (any(y == -1))
stop("base64decode: Input string is not in Base64 format")
if (any(y == 64)) y = y[y != 64] # remove padding
neByte = length(y); # number of encoded bytes
nBlock = ceiling(neByte/4); # number of blocks/groups
ndByte = 3 * nBlock # number of decoded bytes
# add padding if necessary
if (neByte < 4*nBlock) y[(neByte+1) : (4*nBlock)] = 0;
dim(y) = c(4, nBlock); # shape into a matrix
x = matrix(as.integer(0), 3, nBlock); # for the decoded data
#---------------------------------------------
# Rearrange every 4 bytes into 3 bytes
# y = 00aaaaaa 00bbbbbb 00cccccc 00dddddd
# to form
# x = aaaaaabb bbbbcccc ccdddddd
# This section is based on Matlab code by Peter Acklam
# http://home.online.no/~pjacklam/matlab/software/util/datautil/
#---------------------------------------------
x[1,] = bitOr(bitShiftL(y[1,], 2), bitShiftR(y[2,], 4))
x[2,] = bitOr(bitShiftL(y[2,], 4), bitShiftR(y[3,], 2))
x[3,] = bitOr(bitShiftL(y[3,], 6), y[4,])
x = bitAnd(x, 255) # trim numbers to lower 8-bits
# remove padding
if (neByte %% 4 == 2) x = x[1:(ndByte-2)]
if (neByte %% 4 == 3) x = x[1:(ndByte-1)]
# perform final conversion from 'raw' to type given by 'what'
r = as.raw(x)
TypeList = c("logical", "integer", "double", "complex", "character", "raw",
"numeric", "int")
if (!is.character(what) || length(what) != 1 || !(what %in% TypeList))
what <- typeof(what)
if (what=="raw") return(r)
if (is.na(size)) size = switch(match(what, TypeList), 4, 4, 8, 16, 2, 1, 8, 4)
n = length(r)
if (n%%size) stop("raw2bin: number of elements in 'r' is not multiple of 'size'")
x = readBin(r, what, n = n%/%size, size=size, signed=signed, endian=endian)
if (what=="character") x = paste(x, collapse = "") # convert arrays of characters to strings
return (x)
}
|