From 55467ed90c19bc82506433f8f7d274b5bfb8d10f Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Mon, 12 Dec 2016 11:22:50 +0000 Subject: [PATCH] [Feature] Implement quoted printable decoding --- src/libutil/str_util.c | 89 +++++++++++++++++++++++++++++++++++++++++- src/libutil/str_util.h | 13 +++++- 2 files changed, 100 insertions(+), 2 deletions(-) diff --git a/src/libutil/str_util.c b/src/libutil/str_util.c index c12a9c562..5be41f784 100644 --- a/src/libutil/str_util.c +++ b/src/libutil/str_util.c @@ -1671,7 +1671,7 @@ rspamd_encode_hex (const guchar *in, gsize inlen) return out; } -gint +gssize rspamd_decode_hex_buf (const gchar *in, gsize inlen, guchar *out, gsize outlen) { @@ -1738,6 +1738,93 @@ rspamd_decode_hex (const gchar *in, gsize inlen) return NULL; } +gssize +rspamd_decode_qp_buf (const gchar *in, gsize inlen, + gchar *out, gsize outlen) +{ + gchar *o, *end, *pos, c; + const gchar *p; + guchar ret; + gsize remain, processed; + + p = in; + o = out; + end = out + outlen; + remain = inlen; + + while (remain > 0 && o < end) { + if (*p == '=') { + p ++; + remain --; + + if (remain == 0) { + if (end - o > 0) { + *o++ = *p; + break; + } + } +decode: + /* Decode character after '=' */ + c = *p++; + remain --; + + if (c >= '0' && c <= '9') { ret = c - '0'; } + else if (c >= 'A' && c <= 'F') { ret = c - 'A' + 10; } + else if (c >= 'a' && c <= 'f') { ret = c - 'a' + 10; } + else if (c == '\r' || c == '\n') { + /* Soft line break */ + while (remain > 0 && (*p == '\r' || *p == '\n')) { + remain --; + p ++; + } + + continue; + } + + if (remain > 0) { + c = *p++; + ret *= 16; + + if (c >= '0' && c <= '9') ret += c - '0'; + else if (c >= 'A' && c <= 'F') ret += c - 'A' + 10; + else if (c >= 'a' && c <= 'f') ret += c - 'a' + 10; + + if (end - o > 0) { + *o++ = (gchar)ret; + } + else { + return (-1); + } + + remain --; + } + } + else { + if (end - o >= remain) { + if ((pos = memccpy (o, p, '=', remain)) == NULL) { + /* All copied */ + o += remain; + break; + } + else { + processed = pos - o; + remain -= processed; + p += processed; + o = pos - 1; + /* Skip comparison, as we know that we have found match */ + goto decode; + } + } + else { + /* Buffer overflow */ + return (-1); + } + } + } + + return (o - out); +} + /* * GString ucl emitting functions diff --git a/src/libutil/str_util.h b/src/libutil/str_util.h index 9b9bbe0c1..37bd9fe82 100644 --- a/src/libutil/str_util.h +++ b/src/libutil/str_util.h @@ -180,7 +180,7 @@ gint rspamd_encode_hex_buf (const guchar *in, gsize inlen, gchar *out, * @param outlen output buf len * @return decoded len if in is valid hex and `outlen` is enough to encode `inlen` */ -gint rspamd_decode_hex_buf (const gchar *in, gsize inlen, +gssize rspamd_decode_hex_buf (const gchar *in, gsize inlen, guchar *out, gsize outlen); /** @@ -212,6 +212,17 @@ gchar * rspamd_encode_base64_fold (const guchar *in, gsize inlen, gint str_len, */ gsize rspamd_decode_url (gchar *dst, const gchar *src, gsize size); +/** + * Decode quoted-printable encoded buffer, input and output must not overlap + * @param in input + * @param inlen length of input + * @param out output + * @param outlen length of output + * @return real size of decoded output or (-1) if outlen is not enough + */ +gssize rspamd_decode_qp_buf (const gchar *in, gsize inlen, + gchar *out, gsize outlen); + #ifndef g_tolower # define g_tolower(x) (((x) >= 'A' && (x) <= 'Z') ? (x) - 'A' + 'a' : (x)) #endif -- 2.39.5