void urldecode(char *str, char **decoded) {
  char dbuf[0xFFFF];
  char *src, *dst;
  int len;
  for (src = str, dst = dbuf, len = 0; *src && len < 0xFFFF;
       src++, dst++, len++) {
    switch (*src) {
    case '+':
      *dst = ' ';
      break;
    case '%':
      src++;
      if (*src == '%')
        *dst = '%';
      else
        *dst = (((src[0]) >= '0' && (src[0]) <= '9'
                     ? (src[0]) - '0'
                     : ((src[0]) >= 'A' && (src[0]) <= 'F'
                            ? (src[0]) - 'A' + 0xA
                            : ((src[0]) >= 'a' && (src[0]) <= 'f'
                                   ? (src[0]) - 'a' + 0xA
                                   : -1))))
                   << 4 |
               (((src[1]) >= '0' && (src[1]) <= '9'
                     ? (src[1]) - '0'
                     : ((src[1]) >= 'A' && (src[1]) <= 'F'
                            ? (src[1]) - 'A' + 0xA
                            : ((src[1]) >= 'a' && (src[1]) <= 'f'
                                   ? (src[1]) - 'a' + 0xA
                                   : -1))));
      src++;
      break;
    default:
      *dst = *src;
      break;
    }
  }
  *dst = '\0';
  *decoded = strndup(dbuf, len);
}


x86 assembly (clang, -O0):
<urldecode>:
push   %rbp
mov    %rsp,%rbp
sub    $0x10050,%rsp
mov    %rdi,-0x8(%rbp)
mov    %rsi,-0x10(%rbp)
mov    -0x8(%rbp),%rax
mov    %rax,-0x10018(%rbp)
lea    -0x10010(%rbp),%rax
mov    %rax,-0x10020(%rbp)
movl   $0x0,-0x10024(%rbp)
mov    -0x10018(%rbp),%rax
movsbl (%rax),%ecx
xor    %eax,%eax
cmp    $0x0,%ecx
mov    %al,-0x10025(%rbp)
je     1174 <urldecode+0x64>
cmpl   $0xffff,-0x10024(%rbp)
setl   %al
mov    %al,-0x10025(%rbp)
mov    -0x10025(%rbp),%al
test   $0x1,%al
jne    1187 <urldecode+0x77>
jmp    1463 <urldecode+0x353>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
mov    %eax,-0x1002c(%rbp)
sub    $0x25,%eax
je     11c8 <urldecode+0xb8>
jmp    11a5 <urldecode+0x95>
mov    -0x1002c(%rbp),%eax
sub    $0x2b,%eax
jne    1414 <urldecode+0x304>
jmp    11b9 <urldecode+0xa9>
mov    -0x10020(%rbp),%rax
movb   $0x20,(%rax)
jmp    1426 <urldecode+0x316>
mov    -0x10018(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x10018(%rbp)
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x25,%eax
jne    11fc <urldecode+0xec>
mov    -0x10020(%rbp),%rax
movb   $0x25,(%rax)
jmp    13fd <urldecode+0x2ed>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x30,%eax
jl     123a <urldecode+0x12a>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x39,%eax
jg     123a <urldecode+0x12a>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
sub    $0x30,%eax
mov    %eax,-0x10030(%rbp)
jmp    12e4 <urldecode+0x1d4>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x41,%eax
jl     127b <urldecode+0x16b>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x46,%eax
jg     127b <urldecode+0x16b>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
sub    $0x41,%eax
add    $0xa,%eax
mov    %eax,-0x10034(%rbp)
jmp    12d8 <urldecode+0x1c8>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x61,%eax
jl     12bc <urldecode+0x1ac>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
cmp    $0x66,%eax
jg     12bc <urldecode+0x1ac>
mov    -0x10018(%rbp),%rax
movsbl (%rax),%eax
sub    $0x61,%eax
add    $0xa,%eax
mov    %eax,-0x10038(%rbp)
jmp    12cc <urldecode+0x1bc>
mov    $0xffffffff,%eax
mov    %eax,-0x10038(%rbp)
jmp    12cc <urldecode+0x1bc>
mov    -0x10038(%rbp),%eax
mov    %eax,-0x10034(%rbp)
mov    -0x10034(%rbp),%eax
mov    %eax,-0x10030(%rbp)
mov    -0x10030(%rbp),%eax
shl    $0x4,%eax
mov    %eax,-0x1003c(%rbp)
mov    -0x10018(%rbp),%rax
movsbl 0x1(%rax),%eax
cmp    $0x30,%eax
jl     1334 <urldecode+0x224>
mov    -0x10018(%rbp),%rax
movsbl 0x1(%rax),%eax
cmp    $0x39,%eax
jg     1334 <urldecode+0x224>
mov    -0x10018(%rbp),%rax
movsbl 0x1(%rax),%eax
sub    $0x30,%eax
mov    %eax,-0x10040(%rbp)
jmp    13e4 <urldecode+0x2d4>
mov    -0x10018(%rbp),%rax
movsbl 0x1(%rax),%eax
cmp    $0x41,%eax
jl     1378 <urldecode+0x268>
mov    -0x10018(%rbp),%rax
movsbl 0x1(%rax),%eax
cmp    $0x46,%eax
jg     1378 <urldecode+0x268>
mov    -0x10018(%rbp),%rax
movsbl 0x1(%rax),%eax
sub    $0x41,%eax
add    $0xa,%eax
mov    %eax,-0x10044(%rbp)
jmp    13d8 <urldecode+0x2c8>
mov    -0x10018(%rbp),%rax
movsbl 0x1(%rax),%eax
cmp    $0x61,%eax
jl     13bc <urldecode+0x2ac>
mov    -0x10018(%rbp),%rax
movsbl 0x1(%rax),%eax
cmp    $0x66,%eax
jg     13bc <urldecode+0x2ac>
mov    -0x10018(%rbp),%rax
movsbl 0x1(%rax),%eax
sub    $0x61,%eax
add    $0xa,%eax
mov    %eax,-0x10048(%rbp)
jmp    13cc <urldecode+0x2bc>
mov    $0xffffffff,%eax
mov    %eax,-0x10048(%rbp)
jmp    13cc <urldecode+0x2bc>
mov    -0x10048(%rbp),%eax
mov    %eax,-0x10044(%rbp)
mov    -0x10044(%rbp),%eax
mov    %eax,-0x10040(%rbp)
mov    -0x1003c(%rbp),%eax
mov    -0x10040(%rbp),%ecx
or     %ecx,%eax
mov    %al,%cl
mov    -0x10020(%rbp),%rax
mov    %cl,(%rax)
mov    -0x10018(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x10018(%rbp)
jmp    1426 <urldecode+0x316>
mov    -0x10018(%rbp),%rax
mov    (%rax),%cl
mov    -0x10020(%rbp),%rax
mov    %cl,(%rax)
jmp    142b <urldecode+0x31b>
mov    -0x10018(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x10018(%rbp)
mov    -0x10020(%rbp),%rax
add    $0x1,%rax
mov    %rax,-0x10020(%rbp)
mov    -0x10024(%rbp),%eax
add    $0x1,%eax
mov    %eax,-0x10024(%rbp)
jmp    1146 <urldecode+0x36>
mov    -0x10020(%rbp),%rax
movb   $0x0,(%rax)
lea    -0x10010(%rbp),%rdi
movslq -0x10024(%rbp),%rsi
call   1030 <strndup@plt>
mov    %rax,%rcx
mov    -0x10(%rbp),%rax
mov    %rcx,(%rax)
add    $0x10050,%rsp
pop    %rbp
ret

x86 assembly (clang, -O2):
<urldecode>:
push   %rbx
sub    $0x10000,%rsp
mov    %rsi,%rbx
mov    (%rdi),%dl
test   %dl,%dl
je     11f5 <urldecode+0xe5>
xor    %eax,%eax
mov    $0xff,%r8d
nopl   (%rax)
movsbl %dl,%ecx
cmp    $0x25,%ecx
je     1150 <urldecode+0x40>
cmp    $0x2b,%ecx
jne    1180 <urldecode+0x70>
movb   $0x20,(%rsp,%rax,1)
jmp    11d1 <urldecode+0xc1>
cs nopw 0x0(%rax,%rax,1)
movzbl 0x1(%rdi),%esi
mov    $0x25,%cl
cmp    $0x25,%sil
je     11ca <urldecode+0xba>
lea    -0x30(%rsi),%edx
cmp    $0xa,%dl
jb     1197 <urldecode+0x87>
lea    -0x41(%rsi),%ecx
cmp    $0x5,%cl
ja     1185 <urldecode+0x75>
add    $0xc9,%sil
mov    %esi,%edx
jmp    1197 <urldecode+0x87>
cs nopw 0x0(%rax,%rax,1)
xchg   %ax,%ax
mov    %dl,(%rsp,%rax,1)
jmp    11d1 <urldecode+0xc1>
lea    -0x61(%rsi),%ecx
add    $0xa9,%sil
cmp    $0x6,%cl
movzbl %sil,%edx
cmovae %r8d,%edx
shl    $0x4,%dl
movzbl 0x2(%rdi),%esi
lea    -0x30(%rsi),%ecx
cmp    $0xa,%cl
jb     11c8 <urldecode+0xb8>
lea    -0x41(%rsi),%ecx
cmp    $0x5,%cl
ja     11b6 <urldecode+0xa6>
add    $0xc9,%sil
mov    %esi,%ecx
jmp    11c8 <urldecode+0xb8>
lea    -0x61(%rsi),%ecx
add    $0xa9,%sil
cmp    $0x6,%cl
movzbl %sil,%ecx
cmovae %r8d,%ecx
or     %dl,%cl
mov    %cl,(%rsp,%rax,1)
add    $0x2,%rdi
movzbl 0x1(%rdi),%edx
lea    0x1(%rax),%rsi
test   %dl,%dl
je     11ef <urldecode+0xdf>
add    $0x1,%rdi
cmp    $0xfffe,%eax
mov    %rsi,%rax
jb     1130 <urldecode+0x20>
lea    (%rsp,%rsi,1),%rax
jmp    11fa <urldecode+0xea>
mov    %rsp,%rax
xor    %esi,%esi
movb   $0x0,(%rax)
mov    %rsp,%rdi
call   1030 <strndup@plt>
mov    %rax,(%rbx)
add    $0x10000,%rsp
pop    %rbx
ret

LLVM IR (-O0):
define void @urldecode(i8* %0, i8** %1) {
%3 = alloca i8*
%4 = alloca i8**
%5 = alloca [65535 x i8]
%6 = alloca i8*
%7 = alloca i8*
%8 = alloca i32
store i8* %0, i8** %3
store i8** %1, i8*** %4
%9 = load i8*, i8** %3
store i8* %9, i8** %6
%10 = getelementptr inbounds [65535 x i8], [65535 x i8]* %5, i64 0, i64 0
store i8* %10, i8** %7
store i32 0, i32* %8
br label %11
11: ; preds = %173, %2
%12 = load i8*, i8** %6
%13 = load i8, i8* %12
%14 = sext i8 %13 to i32
%15 = icmp ne i32 %14, 0
br i1 %15, label %16, label %19
16: ; preds = %11
%17 = load i32, i32* %8
%18 = icmp slt i32 %17, 65535
br label %19
19: ; preds = %16, %11
%20 = phi i1 [ false, %11 ], [ %18, %16 ]
br i1 %20, label %21, label %180
21: ; preds = %19
%22 = load i8*, i8** %6
%23 = load i8, i8* %22
%24 = sext i8 %23 to i32
switch i32 %24, label %168 [
i32 43, label %25
i32 37, label %27
]
25: ; preds = %21
%26 = load i8*, i8** %7
store i8 32, i8* %26
br label %172
27: ; preds = %21
%28 = load i8*, i8** %6
%29 = getelementptr inbounds i8, i8* %28, i32 1
store i8* %29, i8** %6
%30 = load i8*, i8** %6
%31 = load i8, i8* %30
%32 = sext i8 %31 to i32
%33 = icmp eq i32 %32, 37
br i1 %33, label %34, label %36
34: ; preds = %27
%35 = load i8*, i8** %7
store i8 37, i8* %35
br label %165
36: ; preds = %27
%37 = load i8*, i8** %6
%38 = getelementptr inbounds i8, i8* %37, i64 0
%39 = load i8, i8* %38
%40 = sext i8 %39 to i32
%41 = icmp sge i32 %40, 48
br i1 %41, label %42, label %54
42: ; preds = %36
%43 = load i8*, i8** %6
%44 = getelementptr inbounds i8, i8* %43, i64 0
%45 = load i8, i8* %44
%46 = sext i8 %45 to i32
%47 = icmp sle i32 %46, 57
br i1 %47, label %48, label %54
48: ; preds = %42
%49 = load i8*, i8** %6
%50 = getelementptr inbounds i8, i8* %49, i64 0
%51 = load i8, i8* %50
%52 = sext i8 %51 to i32
%53 = sub nsw i32 %52, 48
br label %97
54: ; preds = %42, %36
%55 = load i8*, i8** %6
%56 = getelementptr inbounds i8, i8* %55, i64 0
%57 = load i8, i8* %56
%58 = sext i8 %57 to i32
%59 = icmp sge i32 %58, 65
br i1 %59, label %60, label %73
60: ; preds = %54
%61 = load i8*, i8** %6
%62 = getelementptr inbounds i8, i8* %61, i64 0
%63 = load i8, i8* %62
%64 = sext i8 %63 to i32
%65 = icmp sle i32 %64, 70
br i1 %65, label %66, label %73
66: ; preds = %60
%67 = load i8*, i8** %6
%68 = getelementptr inbounds i8, i8* %67, i64 0
%69 = load i8, i8* %68
%70 = sext i8 %69 to i32
%71 = sub nsw i32 %70, 65
%72 = add nsw i32 %71, 10
br label %95
73: ; preds = %60, %54
%74 = load i8*, i8** %6
%75 = getelementptr inbounds i8, i8* %74, i64 0
%76 = load i8, i8* %75
%77 = sext i8 %76 to i32
%78 = icmp sge i32 %77, 97
br i1 %78, label %79, label %92
79: ; preds = %73
%80 = load i8*, i8** %6
%81 = getelementptr inbounds i8, i8* %80, i64 0
%82 = load i8, i8* %81
%83 = sext i8 %82 to i32
%84 = icmp sle i32 %83, 102
br i1 %84, label %85, label %92
85: ; preds = %79
%86 = load i8*, i8** %6
%87 = getelementptr inbounds i8, i8* %86, i64 0
%88 = load i8, i8* %87
%89 = sext i8 %88 to i32
%90 = sub nsw i32 %89, 97
%91 = add nsw i32 %90, 10
br label %93
92: ; preds = %79, %73
br label %93
93: ; preds = %92, %85
%94 = phi i32 [ %91, %85 ], [ -1, %92 ]
br label %95
95: ; preds = %93, %66
%96 = phi i32 [ %72, %66 ], [ %94, %93 ]
br label %97
97: ; preds = %95, %48
%98 = phi i32 [ %53, %48 ], [ %96, %95 ]
%99 = shl i32 %98, 4
%100 = load i8*, i8** %6
%101 = getelementptr inbounds i8, i8* %100, i64 1
%102 = load i8, i8* %101
%103 = sext i8 %102 to i32
%104 = icmp sge i32 %103, 48
br i1 %104, label %105, label %117
105: ; preds = %97
%106 = load i8*, i8** %6
%107 = getelementptr inbounds i8, i8* %106, i64 1
%108 = load i8, i8* %107
%109 = sext i8 %108 to i32
%110 = icmp sle i32 %109, 57
br i1 %110, label %111, label %117
111: ; preds = %105
%112 = load i8*, i8** %6
%113 = getelementptr inbounds i8, i8* %112, i64 1
%114 = load i8, i8* %113
%115 = sext i8 %114 to i32
%116 = sub nsw i32 %115, 48
br label %160
117: ; preds = %105, %97
%118 = load i8*, i8** %6
%119 = getelementptr inbounds i8, i8* %118, i64 1
%120 = load i8, i8* %119
%121 = sext i8 %120 to i32
%122 = icmp sge i32 %121, 65
br i1 %122, label %123, label %136
123: ; preds = %117
%124 = load i8*, i8** %6
%125 = getelementptr inbounds i8, i8* %124, i64 1
%126 = load i8, i8* %125
%127 = sext i8 %126 to i32
%128 = icmp sle i32 %127, 70
br i1 %128, label %129, label %136
129: ; preds = %123
%130 = load i8*, i8** %6
%131 = getelementptr inbounds i8, i8* %130, i64 1
%132 = load i8, i8* %131
%133 = sext i8 %132 to i32
%134 = sub nsw i32 %133, 65
%135 = add nsw i32 %134, 10
br label %158
136: ; preds = %123, %117
%137 = load i8*, i8** %6
%138 = getelementptr inbounds i8, i8* %137, i64 1
%139 = load i8, i8* %138
%140 = sext i8 %139 to i32
%141 = icmp sge i32 %140, 97
br i1 %141, label %142, label %155
142: ; preds = %136
%143 = load i8*, i8** %6
%144 = getelementptr inbounds i8, i8* %143, i64 1
%145 = load i8, i8* %144
%146 = sext i8 %145 to i32
%147 = icmp sle i32 %146, 102
br i1 %147, label %148, label %155
148: ; preds = %142
%149 = load i8*, i8** %6
%150 = getelementptr inbounds i8, i8* %149, i64 1
%151 = load i8, i8* %150
%152 = sext i8 %151 to i32
%153 = sub nsw i32 %152, 97
%154 = add nsw i32 %153, 10
br label %156
155: ; preds = %142, %136
br label %156
156: ; preds = %155, %148
%157 = phi i32 [ %154, %148 ], [ -1, %155 ]
br label %158
158: ; preds = %156, %129
%159 = phi i32 [ %135, %129 ], [ %157, %156 ]
br label %160
160: ; preds = %158, %111
%161 = phi i32 [ %116, %111 ], [ %159, %158 ]
%162 = or i32 %99, %161
%163 = trunc i32 %162 to i8
%164 = load i8*, i8** %7
store i8 %163, i8* %164
br label %165
165: ; preds = %160, %34
%166 = load i8*, i8** %6
%167 = getelementptr inbounds i8, i8* %166, i32 1
store i8* %167, i8** %6
br label %172
168: ; preds = %21
%169 = load i8*, i8** %6
%170 = load i8, i8* %169
%171 = load i8*, i8** %7
store i8 %170, i8* %171
br label %172
172: ; preds = %168, %165, %25
br label %173
173: ; preds = %172
%174 = load i8*, i8** %6
%175 = getelementptr inbounds i8, i8* %174, i32 1
store i8* %175, i8** %6
%176 = load i8*, i8** %7
%177 = getelementptr inbounds i8, i8* %176, i32 1
store i8* %177, i8** %7
%178 = load i32, i32* %8
%179 = add nsw i32 %178, 1
store i32 %179, i32* %8
br label %11
180: ; preds = %19
%181 = load i8*, i8** %7
store i8 0, i8* %181
%182 = getelementptr inbounds [65535 x i8], [65535 x i8]* %5, i64 0, i64 0
%183 = load i32, i32* %8
%184 = sext i32 %183 to i64
%185 = call i8* @strndup(i8* %182, i64 %184)
%186 = load i8**, i8*** %4
store i8* %185, i8** %186
ret void
}

LLVM IR (-O2):
define void @urldecode(i8* nocapture %0, i8** nocapture writeonly %1) {
%3 = alloca [65535 x i8]
%4 = getelementptr inbounds [65535 x i8], [65535 x i8]* %3, i64 0, i64 0
%5 = load i8, i8* %0
%6 = icmp eq i8 %5, 0
br i1 %6, label %66, label %7
7: ; preds = %2, %55
%8 = phi i8 [ %60, %55 ], [ %5, %2 ]
%9 = phi i32 [ %59, %55 ], [ 0, %2 ]
%10 = phi i8* [ %58, %55 ], [ %4, %2 ]
%11 = phi i8* [ %57, %55 ], [ %0, %2 ]
%12 = sext i8 %8 to i32
switch i32 %12, label %54 [
i32 43, label %13
i32 37, label %14
]
13: ; preds = %7
store i8 32, i8* %10
br label %55
14: ; preds = %7
%15 = getelementptr inbounds i8, i8* %11, i64 1
%16 = load i8, i8* %15
%17 = icmp eq i8 %16, 37
br i1 %17, label %51, label %18
18: ; preds = %14
%19 = add i8 %16, -48
%20 = icmp ult i8 %19, 10
br i1 %20, label %31, label %21
21: ; preds = %18
%22 = add i8 %16, -65
%23 = icmp ult i8 %22, 6
br i1 %23, label %24, label %26
24: ; preds = %21
%25 = add nsw i8 %16, -55
br label %31
26: ; preds = %21
%27 = add i8 %16, -97
%28 = icmp ult i8 %27, 6
%29 = add i8 %16, -87
%30 = select i1 %28, i8 %29, i8 -1
br label %31
31: ; preds = %18, %26, %24
%32 = phi i8 [ %25, %24 ], [ %30, %26 ], [ %19, %18 ]
%33 = shl i8 %32, 4
%34 = getelementptr inbounds i8, i8* %11, i64 2
%35 = load i8, i8* %34
%36 = add i8 %35, -48
%37 = icmp ult i8 %36, 10
br i1 %37, label %48, label %38
38: ; preds = %31
%39 = add i8 %35, -65
%40 = icmp ult i8 %39, 6
br i1 %40, label %41, label %43
41: ; preds = %38
%42 = add nsw i8 %35, -55
br label %48
43: ; preds = %38
%44 = add i8 %35, -97
%45 = icmp ult i8 %44, 6
%46 = add i8 %35, -87
%47 = select i1 %45, i8 %46, i8 -1
br label %48
48: ; preds = %31, %43, %41
%49 = phi i8 [ %42, %41 ], [ %47, %43 ], [ %36, %31 ]
%50 = or i8 %49, %33
br label %51
51: ; preds = %14, %48
%52 = phi i8 [ %50, %48 ], [ 37, %14 ]
store i8 %52, i8* %10
%53 = getelementptr inbounds i8, i8* %11, i64 2
br label %55
54: ; preds = %7
store i8 %8, i8* %10
br label %55
55: ; preds = %13, %51, %54
%56 = phi i8* [ %11, %54 ], [ %53, %51 ], [ %11, %13 ]
%57 = getelementptr inbounds i8, i8* %56, i64 1
%58 = getelementptr inbounds i8, i8* %10, i64 1
%59 = add nuw nsw i32 %9, 1
%60 = load i8, i8* %57
%61 = icmp ne i8 %60, 0
%62 = icmp ult i32 %9, 65534
%63 = select i1 %61, i1 %62, i1 false
br i1 %63, label %7, label %64
64: ; preds = %55
%65 = zext i32 %59 to i64
br label %66
66: ; preds = %64, %2
%67 = phi i8* [ %4, %2 ], [ %58, %64 ]
%68 = phi i64 [ 0, %2 ], [ %65, %64 ]
store i8 0, i8* %67
%69 = call i8* @strndup(i8* %4, i64 %68)
store i8* %69, i8** %1
ret void
}