blob: 9a9d80c4a3beea7bc7d534a539b5a4c83e68fcb5
1 | /* vi: set sw=4 ts=4: */ |
2 | /* |
3 | * Licensed under GPLv2 or later, see file LICENSE in this source tree. |
4 | */ |
5 | |
6 | //kbuild:lib-y += percent_decode.o |
7 | |
8 | #include "libbb.h" |
9 | |
10 | static unsigned hex_to_bin(unsigned char c) |
11 | { |
12 | unsigned v; |
13 | |
14 | v = c - '0'; |
15 | if (v <= 9) |
16 | return v; |
17 | /* c | 0x20: letters to lower case, non-letters |
18 | * to (potentially different) non-letters */ |
19 | v = (unsigned)(c | 0x20) - 'a'; |
20 | if (v <= 5) |
21 | return v + 10; |
22 | return ~0; |
23 | /* For testing: |
24 | void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); } |
25 | int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f'); |
26 | t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; } |
27 | */ |
28 | } |
29 | |
30 | char* FAST_FUNC percent_decode_in_place(char *str, int strict) |
31 | { |
32 | /* note that decoded string is always shorter than original */ |
33 | char *src = str; |
34 | char *dst = str; |
35 | char c; |
36 | |
37 | while ((c = *src++) != '\0') { |
38 | unsigned v; |
39 | |
40 | if (!strict && c == '+') { |
41 | *dst++ = ' '; |
42 | continue; |
43 | } |
44 | if (c != '%') { |
45 | *dst++ = c; |
46 | continue; |
47 | } |
48 | v = hex_to_bin(src[0]); |
49 | if (v > 15) { |
50 | bad_hex: |
51 | if (strict) |
52 | return NULL; |
53 | *dst++ = '%'; |
54 | continue; |
55 | } |
56 | v = (v * 16) | hex_to_bin(src[1]); |
57 | if (v > 255) |
58 | goto bad_hex; |
59 | if (strict && (v == '/' || v == '\0')) { |
60 | /* caller takes it as indication of invalid |
61 | * (dangerous wrt exploits) chars */ |
62 | return str + 1; |
63 | } |
64 | *dst++ = v; |
65 | src += 2; |
66 | } |
67 | *dst = '\0'; |
68 | return str; |
69 | } |
70 |