[go: up one dir, main page]

File: base64.R

package info (click to toggle)
catools 1.10-1
  • links: PTS, VCS
  • area: main
  • in suites: squeeze
  • size: 356 kB
  • ctags: 74
  • sloc: ansic: 650; cpp: 640; makefile: 5
file content (133 lines) | stat: -rwxr-xr-x 6,259 bytes parent folder | download | duplicates (2)
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)
}