# 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