Bump to version 1.22.1
[platform/upstream/busybox.git] / libbb / percent_decode.c
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 }