escape: hex decode with a lookup-table

Makes the decoding 2.8 times faster in my tests.

Closes #10376
This commit is contained in:
Daniel Stenberg 2023-01-31 09:36:07 +01:00
parent 1ca483a40c
commit f1f8acb3b9
No known key found for this signature in database
GPG Key ID: 5CC908FDB71E12C2

View File

@ -115,6 +115,16 @@ char *curl_easy_escape(struct Curl_easy *data, const char *string,
return Curl_dyn_ptr(&d);
}
static const unsigned char hextable[] = {
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, /* 0x30 - 0x3f */
0, 10, 11, 12, 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x40 - 0x4f */
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, /* 0x50 - 0x5f */
0, 10, 11, 12, 13, 14, 15 /* 0x60 - 0x66 */
};
/* the input is a single hex digit */
#define onehex2dec(x) hextable[x - '0']
/*
* Curl_urldecode() URL decodes the given string.
*
@ -137,54 +147,47 @@ CURLcode Curl_urldecode(const char *string, size_t length,
{
size_t alloc;
char *ns;
size_t strindex = 0;
unsigned long hex;
DEBUGASSERT(string);
DEBUGASSERT(ctrl >= REJECT_NADA); /* crash on TRUE/FALSE */
alloc = (length?length:strlen(string)) + 1;
ns = malloc(alloc);
alloc = (length?length:strlen(string));
ns = malloc(alloc + 1);
if(!ns)
return CURLE_OUT_OF_MEMORY;
while(--alloc > 0) {
/* store output string */
*ostring = ns;
while(alloc) {
unsigned char in = *string;
if(('%' == in) && (alloc > 2) &&
ISXDIGIT(string[1]) && ISXDIGIT(string[2])) {
/* this is two hexadecimal digits following a '%' */
char hexstr[3];
char *ptr;
hexstr[0] = string[1];
hexstr[1] = string[2];
hexstr[2] = 0;
in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]);
hex = strtoul(hexstr, &ptr, 16);
in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
string += 2;
alloc -= 2;
string += 3;
alloc -= 3;
}
else {
string++;
alloc--;
}
if(((ctrl == REJECT_CTRL) && (in < 0x20)) ||
((ctrl == REJECT_ZERO) && (in == 0))) {
free(ns);
Curl_safefree(*ostring);
return CURLE_URL_MALFORMAT;
}
ns[strindex++] = in;
string++;
*ns++ = in;
}
ns[strindex] = 0; /* terminate it */
*ns = 0; /* terminate it */
if(olen)
/* store output size */
*olen = strindex;
/* store output string */
*ostring = ns;
*olen = ns - *ostring;
return CURLE_OK;
}