pion-net  4.0.9
PionAlgorithms.cpp
1 // -----------------------------------------------------------------------
2 // pion-common: a collection of common libraries used by the Pion Platform
3 // -----------------------------------------------------------------------
4 // Copyright (C) 2007-2011 Atomic Labs, Inc. (http://www.atomiclabs.com)
5 //
6 // Distributed under the Boost Software License, Version 1.0.
7 // See http://www.boost.org/LICENSE_1_0.txt
8 //
9 
10 #include <cstdlib>
11 #include <cstdio>
12 #include <pion/PionAlgorithms.hpp>
13 #include <boost/assert.hpp>
14 
15 namespace pion { // begin namespace pion
16 
17 
18 bool algo::base64_decode(const std::string &input, std::string &output)
19 {
20  static const char nop = -1;
21  static const char decoding_data[] = {
22  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
23  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
24  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop, 62, nop,nop,nop, 63,
25  52, 53, 54, 55, 56, 57, 58, 59, 60, 61,nop,nop, nop,nop,nop,nop,
26  nop, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
27  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,nop, nop,nop,nop,nop,
28  nop,26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
29  41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,nop, nop,nop,nop,nop,
30  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
31  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
32  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
33  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
34  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
35  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
36  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
37  nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop
38  };
39 
40  unsigned int input_length=input.size();
41  const char * input_ptr = input.data();
42 
43  // allocate space for output string
44  output.clear();
45  output.reserve(((input_length+2)/3)*4);
46 
47  // for each 4-bytes sequence from the input, extract 4 6-bits sequences by droping first two bits
48  // and regenerate into 3 8-bits sequence
49 
50  for (unsigned int i=0; i<input_length;i++) {
51  char base64code0;
52  char base64code1;
53  char base64code2 = 0; // initialized to 0 to suppress warnings
54  char base64code3;
55 
56  base64code0 = decoding_data[static_cast<int>(input_ptr[i])];
57  if(base64code0==nop) // non base64 character
58  return false;
59  if(!(++i<input_length)) // we need at least two input bytes for first byte output
60  return false;
61  base64code1 = decoding_data[static_cast<int>(input_ptr[i])];
62  if(base64code1==nop) // non base64 character
63  return false;
64 
65  output += ((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
66 
67  if(++i<input_length) {
68  char c = input_ptr[i];
69  if(c =='=') { // padding , end of input
70  BOOST_ASSERT( (base64code1 & 0x0f)==0);
71  return true;
72  }
73  base64code2 = decoding_data[static_cast<int>(input_ptr[i])];
74  if(base64code2==nop) // non base64 character
75  return false;
76 
77  output += ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f);
78  }
79 
80  if(++i<input_length) {
81  char c = input_ptr[i];
82  if(c =='=') { // padding , end of input
83  BOOST_ASSERT( (base64code2 & 0x03)==0);
84  return true;
85  }
86  base64code3 = decoding_data[static_cast<int>(input_ptr[i])];
87  if(base64code3==nop) // non base64 character
88  return false;
89 
90  output += (((base64code2 << 6) & 0xc0) | base64code3 );
91  }
92 
93  }
94 
95  return true;
96 }
97 
98 bool algo::base64_encode(const std::string &input, std::string &output)
99 {
100  static const char encoding_data[] =
101  "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
102 
103  unsigned int input_length=input.size();
104  const char * input_ptr = input.data();
105 
106  // allocate space for output string
107  output.clear();
108  output.reserve(((input_length+2)/3)*4);
109 
110  // for each 3-bytes sequence from the input, extract 4 6-bits sequences and encode using
111  // encoding_data lookup table.
112  // if input do not contains enough chars to complete 3-byte sequence,use pad char '='
113  for (unsigned int i=0; i<input_length;i++) {
114  int base64code0=0;
115  int base64code1=0;
116  int base64code2=0;
117  int base64code3=0;
118 
119  base64code0 = (input_ptr[i] >> 2) & 0x3f; // 1-byte 6 bits
120  output += encoding_data[base64code0];
121  base64code1 = (input_ptr[i] << 4 ) & 0x3f; // 1-byte 2 bits +
122 
123  if (++i < input_length) {
124  base64code1 |= (input_ptr[i] >> 4) & 0x0f; // 2-byte 4 bits
125  output += encoding_data[base64code1];
126  base64code2 = (input_ptr[i] << 2) & 0x3f; // 2-byte 4 bits +
127 
128  if (++i < input_length) {
129  base64code2 |= (input_ptr[i] >> 6) & 0x03; // 3-byte 2 bits
130  base64code3 = input_ptr[i] & 0x3f; // 3-byte 6 bits
131  output += encoding_data[base64code2];
132  output += encoding_data[base64code3];
133  } else {
134  output += encoding_data[base64code2];
135  output += '=';
136  }
137  } else {
138  output += encoding_data[base64code1];
139  output += '=';
140  output += '=';
141  }
142  }
143 
144  return true;
145 }
146 
147 std::string algo::url_decode(const std::string& str)
148 {
149  char decode_buf[3];
150  std::string result;
151  result.reserve(str.size());
152 
153  for (std::string::size_type pos = 0; pos < str.size(); ++pos) {
154  switch(str[pos]) {
155  case '+':
156  // convert to space character
157  result += ' ';
158  break;
159  case '%':
160  // decode hexidecimal value
161  if (pos + 2 < str.size()) {
162  decode_buf[0] = str[++pos];
163  decode_buf[1] = str[++pos];
164  decode_buf[2] = '\0';
165  result += static_cast<char>( strtol(decode_buf, 0, 16) );
166  } else {
167  // recover from error by not decoding character
168  result += '%';
169  }
170  break;
171  default:
172  // character does not need to be escaped
173  result += str[pos];
174  }
175  };
176 
177  return result;
178 }
179 
180 std::string algo::url_encode(const std::string& str)
181 {
182  char encode_buf[4];
183  std::string result;
184  encode_buf[0] = '%';
185  result.reserve(str.size());
186 
187  // character selection for this algorithm is based on the following url:
188  // http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
189 
190  for (std::string::size_type pos = 0; pos < str.size(); ++pos) {
191  switch(str[pos]) {
192  default:
193  if (str[pos] > 32 && str[pos] < 127) {
194  // character does not need to be escaped
195  result += str[pos];
196  break;
197  }
198  // else pass through to next case
199  case ' ':
200  case '$': case '&': case '+': case ',': case '/': case ':':
201  case ';': case '=': case '?': case '@': case '"': case '<':
202  case '>': case '#': case '%': case '{': case '}': case '|':
203  case '\\': case '^': case '~': case '[': case ']': case '`':
204  // the character needs to be encoded
205  sprintf(encode_buf+1, "%.2X", (unsigned char)(str[pos]));
206  result += encode_buf;
207  break;
208  }
209  };
210 
211  return result;
212 }
213 
214 } // end namespace pion
static bool base64_decode(std::string const &input, std::string &output)
static std::string url_encode(const std::string &str)
encodes strings so that they are safe for URLs (with%20spaces)
static bool base64_encode(std::string const &input, std::string &output)
static std::string url_decode(const std::string &str)
escapes URL-encoded strings (a%20value+with%20spaces)