COSA
An Object-Oriented Platform for Arduino Programming
Base64.cpp
Go to the documentation of this file.
1 
21 #include "Base64.hh"
22 
23 const char Base64::ENCODE[] __PROGMEM =
24  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
25 
26 const char Base64::DECODE[] __PROGMEM =
27  "|$$$}rstuvwxyz{$$$$$$$>?@ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ[\\]^_`"
28  "abcdefghijklmnopq";
29 
30 int
31 Base64::encode(char* dest, const void* src, size_t size)
32 {
33  const uint8_t* sp = (const uint8_t*) src;
34  char* dp = dest;
35  base64_t temp;
36  int res = 0;
37 
38  // Encode three bytes block
39  while (size > 2) {
40  temp.d[2] = *sp++;
41  temp.d[1] = *sp++;
42  temp.d[0] = *sp++;
43  size = size - 3;
44  *dp++ = encode(temp.c3);
45  *dp++ = encode(temp.c2);
46  *dp++ = encode(temp.c1);
47  *dp++ = encode(temp.c0);
48  res = res + 4;
49  }
50 
51  // Pad and encode any remaining bytes
52  if (size != 0) {
53  temp.d[2] = *sp++;
54  temp.d[1] = (size > 1 ? *sp : 0);
55  temp.d[0] = 0;
56  *dp++ = encode(temp.c3);
57  *dp++ = encode(temp.c2);
58  *dp++ = size > 1 ? encode(temp.c1) : PAD;
59  *dp++ = PAD;
60  res = res + 4;
61  }
62 
63  // Zero terminate string and return length
64  *dp = 0;
65  return (res);
66 }
67 
68 int
69 Base64::encode_P(char* dest, const void* src, size_t size)
70 {
71  const uint8_t* sp = (const uint8_t*) src;
72  char* dp = dest;
73  base64_t temp;
74  int res = 0;
75 
76  // Encode three byte blocks
77  while (size > 2) {
78  temp.d[2] = pgm_read_byte(sp++);
79  temp.d[1] = pgm_read_byte(sp++);
80  temp.d[0] = pgm_read_byte(sp++);
81  size = size - 3;
82  *dp++ = encode(temp.c3);
83  *dp++ = encode(temp.c2);
84  *dp++ = encode(temp.c1);
85  *dp++ = encode(temp.c0);
86  res = res + 4;
87  }
88 
89  // Pad and encode any remaining bytes
90  if (size != 0) {
91  temp.d[2] = pgm_read_byte(sp++);
92  temp.d[1] = size > 1 ? pgm_read_byte(sp) : 0;
93  temp.d[0] = 0;
94  *dp++ = encode(temp.c3);
95  *dp++ = encode(temp.c2);
96  *dp++ = size > 1 ? encode(temp.c1) : PAD;
97  *dp++ = PAD;
98  res = res + 4;
99  }
100 
101  // Zero terminate string and return length
102  *dp = 0;
103  return (res);
104 }
105 
106 int
107 Base64::encode(IOStream::Device* dest, const void* src, size_t size)
108 {
109  const uint8_t* sp = (const uint8_t*) src;
110  base64_t temp;
111  int res = 0;
112 
113  // Encode three byte blocks with line break every 64 characters
114  while (size > 2) {
115  temp.d[2] = *sp++;
116  temp.d[1] = *sp++;
117  temp.d[0] = *sp++;
118  size = size - 3;
119  dest->putchar(encode(temp.c3));
120  dest->putchar(encode(temp.c2));
121  dest->putchar(encode(temp.c1));
122  dest->putchar(encode(temp.c0));
123  res = res + 4;
124  if ((res & 0x3f) == 0) dest->puts((str_P) IOStream::CRLF);
125  }
126 
127  // Pad and encode any remaining bytes with possible line break
128  if (size != 0) {
129  temp.d[2] = *sp++;
130  temp.d[1] = size > 1 ? *sp : 0;
131  temp.d[0] = 0;
132  dest->putchar(encode(temp.c3));
133  dest->putchar(encode(temp.c2));
134  dest->putchar(size > 1 ? encode(temp.c1) : PAD);
135  dest->putchar(PAD);
136  res = res + 4;
137  if ((res & 0x3f) == 0) dest->puts((str_P) IOStream::CRLF);
138  }
139 
140  return (res);
141 }
142 
143 int
144 Base64::encode_P(IOStream::Device* dest, const void* src, size_t size)
145 {
146  const uint8_t* sp = (const uint8_t*) src;
147  base64_t temp;
148  int res = 0;
149 
150  // Encode three byte blocks with line break every 64 characters
151  while (size > 2) {
152  temp.d[2] = pgm_read_byte(sp++);
153  temp.d[1] = pgm_read_byte(sp++);
154  temp.d[0] = pgm_read_byte(sp++);
155  size = size - 3;
156  dest->putchar(encode(temp.c3));
157  dest->putchar(encode(temp.c2));
158  dest->putchar(encode(temp.c1));
159  dest->putchar(encode(temp.c0));
160  res = res + 4;
161  if ((res & 0x3f) == 0) dest->puts((str_P) IOStream::CRLF);
162  }
163 
164  // Pad and encode any remaining bytes with possible line break
165  if (size != 0) {
166  temp.d[2] = pgm_read_byte(sp++);
167  temp.d[1] = size > 1 ? pgm_read_byte(sp) : 0;
168  temp.d[0] = 0;
169  dest->putchar(encode(temp.c3));
170  dest->putchar(encode(temp.c2));
171  dest->putchar(size > 1 ? encode(temp.c1) : PAD);
172  dest->putchar(PAD);
173  res = res + 4;
174  if ((res & 0x3f) == 0) dest->puts((str_P) IOStream::CRLF);
175  }
176 
177  return (res);
178 }
179 
180 int
181 Base64::decode(void* dest, const char* src, size_t size)
182 {
183  // Check for illegal length (even 4 character blocks)
184  if (UNLIKELY((size & 0x3) != 0)) return (EINVAL);
185 
186  uint8_t* dp = (uint8_t*) dest;
187  const char* sp = src;
188  int res = 0;
189 
190  // Decode four character to three bytes
191  while (size != 0) {
192  base64_t temp;
193  temp.c3 = decode(*sp++);
194  temp.c2 = decode(*sp++);
195  temp.c1 = decode(*sp++);
196  temp.c0 = decode(*sp++);
197  size = size - 4;
198  *dp++ = temp.d[2];
199  *dp++ = temp.d[1];
200  *dp++ = temp.d[0];
201  res = res + 3;
202  }
203 
204  // Return number of bytes
205  return (res);
206 }
#define EINVAL
Definition: Errno.h:49
virtual int putchar(char c)
virtual int puts(const char *s)
static int decode(void *dest, const char *src, size_t size)
Definition: Base64.cpp:181
const class prog_str * str_P
Definition: Types.h:187
static const char CRLF[]
Definition: IOStream.hh:38
static int encode(char *dest, const void *src, size_t size)
Definition: Base64.cpp:31
static int encode_P(char *dest, const void *src, size_t size)
Definition: Base64.cpp:69
#define UNLIKELY(x)
Definition: Types.h:153
const char Base64::ENCODE[] __PROGMEM
Definition: Base64.cpp:23