I did it in principle with a different purpose, but maybe it will suit you.
// avp 2013 по мотивам http://tools.ietf.org/html/rfc3986#section-2.1 #include <stdio.h> #include <stdlib.h> #include <string.h> #include <ctype.h> /* Заменяет isspace() символы и % на %HH Input: ilen байт в char *input Result: байты в char *out максимальной длины osize их количество по адресу olen. Returns: количство "оттранслированных" байт из input */ size_t pct_encode (const char *input, size_t ilen, char *out, size_t osize, size_t *olen) { size_t i, l; for (l = i = 0; i < ilen && l < osize; i++) { int c = (unsigned char)input[i]; if (isspace(c) || iscntrl(c) || c == '%') { if (l + 2 < osize) { sprintf(out + l, "%%%02X", c); l += 3; } else // нет места break; } else out[l++] = c; } *olen = l; return i; } // вызывать только с VALID HEXCODE static inline int hex (int c) { if ('0' <= c && c <= '9') c -= '0'; else if ('A' <= c && c <= 'F') c -= ('A' - 10) ; else c -= ('a' - 10); return c; } /* Заменяет %HH в тексте на байты Input: ilen байт в char *input флаг ignerr - игнорировать ошибки формата %HH Result: байты в char *out максимальной длины osize их количество по адресу olen. Returns: количство "оттранслированных" байт из input */ size_t pct_decode (const char *input, size_t ilen, char *out, size_t osize, size_t *olen, int ignerr) { size_t i, l; for (l = i = 0; i < ilen && l < osize; i++) { int c1, c2; if (input[i] == '%') { if (i + 2 < ilen && isxdigit(c1 = input[i + 1]) && isxdigit(c2 = input[i + 2])) { out[l++] = hex(c1) * 16 + hex(c2); i += 2; } else if (ignerr) out[l++] = input[i]; else break; } else out[l++] = input[i]; } *olen = l; return i; }
pct_encode
functionpct_encode
replace if (isspace (c) || iscntrl (c) || c == '%') {if (isspace (c) || iscntrl (c) || c == '%' || c> 126) { - avp