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 
hex_to_bin(unsigned char c)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 
percent_decode_in_place(char * str,int strict)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