]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
escape: hex decode with a lookup-table
authorDaniel Stenberg <daniel@haxx.se>
Tue, 31 Jan 2023 08:36:07 +0000 (09:36 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Tue, 31 Jan 2023 14:03:19 +0000 (15:03 +0100)
Makes the decoding 2.8 times faster in my tests.

Closes #10376

lib/escape.c

index 1e1d7179e6a0cf846179bcd6eff80ccaa19fdde1..93db06cbd822e914944d753457bc264198312947 100644 (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;
-
-      hex = strtoul(hexstr, &ptr, 16);
-
-      in = curlx_ultouc(hex); /* this long is never bigger than 255 anyway */
+      in = (unsigned char)(onehex2dec(string[1]) << 4) | onehex2dec(string[2]);
 
-      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;
 }