utility::string_t uri::decode(const utility::string_t &encoded) { std::string utf8raw; for(auto iter = encoded.begin(); iter != encoded.end(); ++iter) { if(*iter == _XPLATSTR('%')) { if(++iter == encoded.end()) { throw uri_exception("Invalid URI string, two hexadecimal digits must follow '%'"); } int decimal_value = hex_char_digit_to_decimal_char(static_cast<int>(*iter)) << 4; if(++iter == encoded.end()) { throw uri_exception("Invalid URI string, two hexadecimal digits must follow '%'"); } decimal_value += hex_char_digit_to_decimal_char(static_cast<int>(*iter)); utf8raw.push_back(static_cast<char>(decimal_value)); } else { // encoded string has to be ASCII. utf8raw.push_back(reinterpret_cast<const char &>(*iter)); } } return to_string_t(utf8raw); }
std::vector<unsigned char> _from_base64(const utility::string_t& input) { std::vector<unsigned char> result; if ( input.empty() ) return result; size_t padding = 0; // Validation { auto size = input.size(); if ( (size % 4) != 0 ) { throw std::runtime_error("length of base64 string is not an even multiple of 4"); } for (auto iter = input.begin(); iter != input.end(); ++iter,--size) { auto ch = *iter; if ( ch < 0 || _base64_dectbl[ch] == 255 ) { throw std::runtime_error("invalid character found in base64 string"); } if ( _base64_dectbl[ch] == 254 ) { padding++; // padding only at the end if ( size > 2 || (size == 2 && _base64_dectbl[*(iter+1)] != 254) ) { throw std::runtime_error("invalid padding character found in base64 string"); } } } } auto size = input.size(); const char_t* ptr = &input[0]; auto outsz = (size / 4)*3; outsz -= padding; result.resize(outsz); size_t idx = 0; for (; size > 4; ++idx ) { unsigned char target[3]; memset(target, 0, sizeof(target)); _triple_byte* record = reinterpret_cast<_triple_byte*>(target); unsigned char val0 = _base64_dectbl[ptr[0]]; unsigned char val1 = _base64_dectbl[ptr[1]]; unsigned char val2 = _base64_dectbl[ptr[2]]; unsigned char val3 = _base64_dectbl[ptr[3]]; record->_0 = val0; record->_1_1 = val1 >> 4; result[idx] = target[0]; record->_1_2 = val1 & 0xF; record->_2_1 = val2 >> 2; result[++idx] = target[1]; record->_2_2 = val2 & 0x3; record->_3 = val3 & 0x3F; result[++idx] = target[2]; ptr += 4; size -= 4; } // Handle the last four bytes separately, to avoid having the conditional statements // in all the iterations (a performance issue). { unsigned char target[3]; memset(target, 0, sizeof(target)); _triple_byte* record = reinterpret_cast<_triple_byte*>(target); unsigned char val0 = _base64_dectbl[ptr[0]]; unsigned char val1 = _base64_dectbl[ptr[1]]; unsigned char val2 = _base64_dectbl[ptr[2]]; unsigned char val3 = _base64_dectbl[ptr[3]]; record->_0 = val0; record->_1_1 = val1 >> 4; result[idx] = target[0]; record->_1_2 = val1 & 0xF; if ( val2 != 254 ) { record->_2_1 = val2 >> 2; result[++idx] = target[1]; } else { // There shouldn't be any information (ones) in the unused bits, if ( record->_1_2 != 0 )