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