| /* 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; |
| } |