percent_decode.c 1.4 KB

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