blob: b654c352ba6a8b56a0d73e24d6fe452ae7327d9f [file] [log] [blame]
#include "talk/base/urlencode.h"
static int HexPairValue(const char * code) {
int value = 0;
const char * pch = code;
for (;;) {
int digit = *pch++;
if (digit >= '0' && digit <= '9') {
value += digit - '0';
}
else if (digit >= 'A' && digit <= 'F') {
value += digit - 'A' + 10;
}
else if (digit >= 'a' && digit <= 'f') {
value += digit - 'a' + 10;
}
else {
return -1;
}
if (pch == code + 2)
return value;
value <<= 4;
}
}
int UrlDecode(const char *source, char *dest)
{
char * start = dest;
while (*source) {
switch (*source) {
case '+':
*(dest++) = ' ';
break;
case '%':
if (source[1] && source[2]) {
int value = HexPairValue(source + 1);
if (value >= 0) {
*(dest++) = value;
source += 2;
}
else {
*dest++ = '?';
}
}
else {
*dest++ = '?';
}
break;
default:
*dest++ = *source;
}
source++;
}
*dest = 0;
return dest - start;
}
int UrlEncode(const char *source, char *dest, unsigned max)
{
static const char *digits = "0123456789ABCDEF";
unsigned char ch;
unsigned len = 0;
char *start = dest;
while (len < max - 4 && *source)
{
ch = (unsigned char)*source;
if (*source == ' ') {
*dest++ = '+';
}
else if (isalnum(ch) || strchr("-_.!~*'()", ch)) {
*dest++ = *source;
}
else {
*dest++ = '%';
*dest++ = digits[(ch >> 4) & 0x0F];
*dest++ = digits[ ch & 0x0F];
}
source++;
}
*dest = 0;
return start - dest;
}
std::string
UrlDecodeString(const std::string & encoded) {
const char * sz_encoded = encoded.c_str();
size_t needed_length = encoded.length();
for (const char * pch = sz_encoded; *pch; pch++) {
if (*pch == '%')
needed_length += 2;
}
needed_length += 10;
char stackalloc[64];
char * buf = needed_length > sizeof(stackalloc)/sizeof(*stackalloc) ?
(char *)malloc(needed_length) : stackalloc;
UrlDecode(encoded.c_str(), buf);
std::string result(buf);
if (buf != stackalloc) {
free(buf);
}
return result;
}
std::string
UrlEncodeString(const std::string & decoded) {
const char * sz_decoded = decoded.c_str();
size_t needed_length = decoded.length() * 3 + 3;
char stackalloc[64];
char * buf = needed_length > sizeof(stackalloc)/sizeof(*stackalloc) ?
(char *)malloc(needed_length) : stackalloc;
UrlEncode(decoded.c_str(), buf, needed_length);
std::string result(buf);
if (buf != stackalloc) {
free(buf);
}
return result;
}