| /* vi: set sw=4 ts=4: */ | |
| /* | |
| * Licensed under GPLv2 or later, see file LICENSE in this source tree. | |
| */ | |
| //kbuild:lib-y += percent_decode.o | |
| #include "libbb.h" | |
| static unsigned hex_to_bin(unsigned char c) | |
| { | |
| unsigned v; | |
| v = c - '0'; | |
| if (v <= 9) | |
| return v; | |
| /* c | 0x20: letters to lower case, non-letters | |
| * to (potentially different) non-letters */ | |
| v = (unsigned)(c | 0x20) - 'a'; | |
| if (v <= 5) | |
| return v + 10; | |
| return ~0; | |
| /* For testing: | |
| void t(char c) { printf("'%c'(%u) %u\n", c, c, hex_to_bin(c)); } | |
| int main() { t(0x10); t(0x20); t('0'); t('9'); t('A'); t('F'); t('a'); t('f'); | |
| t('0'-1); t('9'+1); t('A'-1); t('F'+1); t('a'-1); t('f'+1); return 0; } | |
| */ | |
| } | |
| char* FAST_FUNC percent_decode_in_place(char *str, int strict) | |
| { | |
| /* note that decoded string is always shorter than original */ | |
| char *src = str; | |
| char *dst = str; | |
| char c; | |
| while ((c = *src++) != '\0') { | |
| unsigned v; | |
| if (!strict && c == '+') { | |
| *dst++ = ' '; | |
| continue; | |
| } | |
| if (c != '%') { | |
| *dst++ = c; | |
| continue; | |
| } | |
| v = hex_to_bin(src[0]); | |
| if (v > 15) { | |
| bad_hex: | |
| if (strict) | |
| return NULL; | |
| *dst++ = '%'; | |
| continue; | |
| } | |
| v = (v * 16) | hex_to_bin(src[1]); | |
| if (v > 255) | |
| goto bad_hex; | |
| if (strict && (v == '/' || v == '\0')) { | |
| /* caller takes it as indication of invalid | |
| * (dangerous wrt exploits) chars */ | |
| return str + 1; | |
| } | |
| *dst++ = v; | |
| src += 2; | |
| } | |
| *dst = '\0'; | |
| return str; | |
| } |