pion-net  4.0.9
common/src/PionAlgorithms.cpp
00001 // -----------------------------------------------------------------------
00002 // pion-common: a collection of common libraries used by the Pion Platform
00003 // -----------------------------------------------------------------------
00004 // Copyright (C) 2007-2011 Atomic Labs, Inc.  (http://www.atomiclabs.com)
00005 //
00006 // Distributed under the Boost Software License, Version 1.0.
00007 // See http://www.boost.org/LICENSE_1_0.txt
00008 //
00009 
00010 #include <cstdlib>
00011 #include <cstdio>
00012 #include <pion/PionAlgorithms.hpp>
00013 #include <boost/assert.hpp>
00014 
00015 namespace pion {        // begin namespace pion
00016 
00017 
00018 bool algo::base64_decode(const std::string &input, std::string &output)
00019 {
00020     static const char nop = -1; 
00021     static const char decoding_data[] = {
00022         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
00023         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
00024         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop, 62, nop,nop,nop, 63,
00025         52, 53, 54,  55,  56, 57, 58, 59,  60, 61,nop,nop, nop,nop,nop,nop,
00026         nop, 0,  1,   2,   3,  4,  5,  6,   7,  8,  9, 10,  11, 12, 13, 14,
00027         15, 16, 17,  18,  19, 20, 21, 22,  23, 24, 25,nop, nop,nop,nop,nop,
00028         nop,26, 27,  28,  29, 30, 31, 32,  33, 34, 35, 36,  37, 38, 39, 40,
00029         41, 42, 43,  44,  45, 46, 47, 48,  49, 50, 51,nop, nop,nop,nop,nop,
00030         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
00031         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
00032         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
00033         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
00034         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
00035         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
00036         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop,
00037         nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop, nop,nop,nop,nop
00038         };
00039 
00040     unsigned int input_length=input.size();
00041     const char * input_ptr = input.data();
00042 
00043     // allocate space for output string
00044     output.clear();
00045     output.reserve(((input_length+2)/3)*4);
00046 
00047     // for each 4-bytes sequence from the input, extract 4 6-bits sequences by droping first two bits
00048     // and regenerate into 3 8-bits sequence
00049 
00050     for (unsigned int i=0; i<input_length;i++) {
00051         char base64code0;
00052         char base64code1;
00053         char base64code2 = 0;   // initialized to 0 to suppress warnings
00054         char base64code3;
00055 
00056         base64code0 = decoding_data[static_cast<int>(input_ptr[i])];
00057         if(base64code0==nop)            // non base64 character
00058             return false;
00059         if(!(++i<input_length)) // we need at least two input bytes for first byte output
00060             return false;
00061         base64code1 = decoding_data[static_cast<int>(input_ptr[i])];
00062         if(base64code1==nop)            // non base64 character
00063             return false;
00064 
00065         output += ((base64code0 << 2) | ((base64code1 >> 4) & 0x3));
00066 
00067         if(++i<input_length) {
00068             char c = input_ptr[i];
00069             if(c =='=') { // padding , end of input
00070                 BOOST_ASSERT( (base64code1 & 0x0f)==0);
00071                 return true;
00072             }
00073             base64code2 = decoding_data[static_cast<int>(input_ptr[i])];
00074             if(base64code2==nop)            // non base64 character
00075                 return false;
00076 
00077             output += ((base64code1 << 4) & 0xf0) | ((base64code2 >> 2) & 0x0f);
00078         }
00079 
00080         if(++i<input_length) {
00081             char c = input_ptr[i];
00082             if(c =='=') { // padding , end of input
00083                 BOOST_ASSERT( (base64code2 & 0x03)==0);
00084                 return true;
00085             }
00086             base64code3 = decoding_data[static_cast<int>(input_ptr[i])];
00087             if(base64code3==nop)            // non base64 character
00088                 return false;
00089 
00090             output += (((base64code2 << 6) & 0xc0) | base64code3 );
00091         }
00092 
00093     }
00094 
00095     return true;
00096 }
00097 
00098 bool algo::base64_encode(const std::string &input, std::string &output)
00099 {
00100     static const char encoding_data[] = 
00101         "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
00102 
00103     unsigned int input_length=input.size();
00104     const char * input_ptr = input.data();
00105 
00106     // allocate space for output string
00107     output.clear();
00108     output.reserve(((input_length+2)/3)*4);
00109 
00110     // for each 3-bytes sequence from the input, extract 4 6-bits sequences and encode using 
00111     // encoding_data lookup table.
00112     // if input do not contains enough chars to complete 3-byte sequence,use pad char '=' 
00113     for (unsigned int i=0; i<input_length;i++) {
00114         int base64code0=0;
00115         int base64code1=0;
00116         int base64code2=0;
00117         int base64code3=0;
00118 
00119         base64code0 = (input_ptr[i] >> 2)  & 0x3f;  // 1-byte 6 bits
00120         output += encoding_data[base64code0];
00121         base64code1 = (input_ptr[i] << 4 ) & 0x3f;  // 1-byte 2 bits +
00122 
00123         if (++i < input_length) {
00124             base64code1 |= (input_ptr[i] >> 4) & 0x0f; // 2-byte 4 bits
00125             output += encoding_data[base64code1];
00126             base64code2 = (input_ptr[i] << 2) & 0x3f;  // 2-byte 4 bits + 
00127 
00128             if (++i < input_length) {
00129                 base64code2 |= (input_ptr[i] >> 6) & 0x03; // 3-byte 2 bits
00130                 base64code3  = input_ptr[i] & 0x3f;       // 3-byte 6 bits
00131                 output += encoding_data[base64code2];
00132                 output += encoding_data[base64code3];
00133             } else {
00134                 output += encoding_data[base64code2];
00135                 output += '=';
00136             }
00137         } else {
00138             output += encoding_data[base64code1];
00139             output += '=';
00140             output += '=';
00141         }
00142     }
00143 
00144     return true;
00145 }
00146 
00147 std::string algo::url_decode(const std::string& str)
00148 {
00149     char decode_buf[3];
00150     std::string result;
00151     result.reserve(str.size());
00152     
00153     for (std::string::size_type pos = 0; pos < str.size(); ++pos) {
00154         switch(str[pos]) {
00155         case '+':
00156             // convert to space character
00157             result += ' ';
00158             break;
00159         case '%':
00160             // decode hexidecimal value
00161             if (pos + 2 < str.size()) {
00162                 decode_buf[0] = str[++pos];
00163                 decode_buf[1] = str[++pos];
00164                 decode_buf[2] = '\0';
00165                 result += static_cast<char>( strtol(decode_buf, 0, 16) );
00166             } else {
00167                 // recover from error by not decoding character
00168                 result += '%';
00169             }
00170             break;
00171         default:
00172             // character does not need to be escaped
00173             result += str[pos];
00174         }
00175     };
00176     
00177     return result;
00178 }
00179     
00180 std::string algo::url_encode(const std::string& str)
00181 {
00182     char encode_buf[4];
00183     std::string result;
00184     encode_buf[0] = '%';
00185     result.reserve(str.size());
00186 
00187     // character selection for this algorithm is based on the following url:
00188     // http://www.blooberry.com/indexdot/html/topics/urlencoding.htm
00189     
00190     for (std::string::size_type pos = 0; pos < str.size(); ++pos) {
00191         switch(str[pos]) {
00192         default:
00193             if (str[pos] > 32 && str[pos] < 127) {
00194                 // character does not need to be escaped
00195                 result += str[pos];
00196                 break;
00197             }
00198             // else pass through to next case
00199         case ' ':   
00200         case '$': case '&': case '+': case ',': case '/': case ':':
00201         case ';': case '=': case '?': case '@': case '"': case '<':
00202         case '>': case '#': case '%': case '{': case '}': case '|':
00203         case '\\': case '^': case '~': case '[': case ']': case '`':
00204             // the character needs to be encoded
00205             sprintf(encode_buf+1, "%.2X", (unsigned char)(str[pos]));
00206             result += encode_buf;
00207             break;
00208         }
00209     };
00210     
00211     return result;
00212 }   
00213     
00214 }   // end namespace pion