aboutsummaryrefslogtreecommitdiffhomepage
path: root/src/core/basetypes/MCDataDecoderUtils.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/core/basetypes/MCDataDecoderUtils.cpp')
-rw-r--r--src/core/basetypes/MCDataDecoderUtils.cpp192
1 files changed, 192 insertions, 0 deletions
diff --git a/src/core/basetypes/MCDataDecoderUtils.cpp b/src/core/basetypes/MCDataDecoderUtils.cpp
new file mode 100644
index 00000000..4ea739ce
--- /dev/null
+++ b/src/core/basetypes/MCDataDecoderUtils.cpp
@@ -0,0 +1,192 @@
+#include "MCDataDecoderUtils.h"
+
+#include <libetpan/libetpan.h>
+
+#include <string.h>
+#include <strings.h>
+
+namespace mailcore {
+
+static size_t uudecode(const char * text, size_t size, char * dst, size_t dst_buf_size)
+{
+ unsigned int count = 0;
+ const char *b = text; /* beg */
+ const char *s = b; /* src */
+ const char *e = b+size; /* end */
+ char *d = dst;
+ int out = (*s++ & 0x7f) - 0x20;
+
+ /* don't process lines without leading count character */
+ if (out < 0)
+ return size;
+
+ /* dummy check. user must allocate buffer with appropriate length */
+ if (dst_buf_size < out)
+ return size;
+
+ /* don't process begin and end lines */
+ if ((strncasecmp((const char *)b, "begin ", 6) == 0) ||
+ (strncasecmp((const char *)b, "end", 3) == 0))
+ return size;
+
+ while (s < e && count < out)
+ {
+ int v = 0;
+ int i;
+ for (i = 0; i < 4; i += 1) {
+ char c = *s++;
+ v = v << 6 | ((c - 0x20) & 0x3F);
+ }
+ for (i = 2; i >= 0; i -= 1) {
+ char c = (char) (v & 0xFF);
+ d[i] = c;
+ v = v >> 8;
+ }
+ d += 3;
+ count += 3;
+ }
+ return count;
+}
+
+static void decodedPartDeallocator(char * decoded, unsigned int decoded_length) {
+ mailmime_decoded_part_free(decoded);
+}
+
+Data * MCDecodeData(Data * encodedData, Encoding encoding, bool partialContent, Data ** pRemainingData)
+{
+ const char * text;
+ size_t text_length;
+
+ text = encodedData->bytes();
+ text_length = encodedData->length();
+
+ * pRemainingData = NULL;
+
+ switch (encoding) {
+ case Encoding7Bit:
+ case Encoding8Bit:
+ case EncodingBinary:
+ case EncodingOther:
+ default:
+ {
+ return encodedData;
+ }
+ case EncodingBase64:
+ case EncodingQuotedPrintable:
+ {
+ char * decoded;
+ size_t decoded_length;
+ size_t cur_token;
+ int mime_encoding;
+
+ switch (encoding) {
+ default: //disable warning
+ case EncodingBase64:
+ mime_encoding = MAILMIME_MECHANISM_BASE64;
+ break;
+ case EncodingQuotedPrintable:
+ mime_encoding = MAILMIME_MECHANISM_QUOTED_PRINTABLE;
+ break;
+ }
+
+ cur_token = 0;
+ if (partialContent) {
+ mailmime_part_parse_partial(text, text_length, &cur_token,
+ mime_encoding, &decoded, &decoded_length);
+ }
+ else {
+ mailmime_part_parse(text, text_length, &cur_token,
+ mime_encoding, &decoded, &decoded_length);
+ }
+
+ if (cur_token < text_length) {
+ * pRemainingData = Data::dataWithBytes(text + cur_token, (unsigned int)(text_length - cur_token));
+ }
+
+ Data * data = Data::data();
+ data->takeBytesOwnership(decoded, (unsigned int) decoded_length, decodedPartDeallocator);
+ return data;
+ }
+ case EncodingUUEncode:
+ {
+ Data * data;
+ const char * current_p;
+
+ data = Data::dataWithCapacity((unsigned int) text_length);
+
+ current_p = text;
+ while (1) {
+ /* In uuencoded files each data line usually have 45 bytes of decoded data.
+ Maximum possible length is limited by (0x7f-0x20) bytes.
+ So 256-bytes buffer is enough. */
+ char decoded_buf[256];
+ size_t decoded_length;
+ size_t length;
+ const char * p;
+ const char * p1;
+ const char * p2;
+ const char * end_line;
+
+ p1 = strchr(current_p, '\n');
+ p2 = strchr(current_p, '\r');
+ if (p1 == NULL) {
+ p = p2;
+ }
+ else if (p2 == NULL) {
+ p = p1;
+ }
+ else {
+ if (p1 - current_p < p2 - current_p) {
+ p = p1;
+ }
+ else {
+ p = p2;
+ }
+ }
+ end_line = p;
+ if (partialContent && (p1 == NULL || p2 == NULL) &&
+ ((end_line == NULL) || (end_line - text) == (text_length - 1))) {
+ // possibly partial content detected
+ * pRemainingData = Data::dataWithBytes(current_p, (unsigned int)(text_length - (current_p - text)));
+ break;
+ }
+ if (p != NULL) {
+ while ((size_t) (p - text) < text_length) {
+ if ((* p != '\r') && (* p != '\n')) {
+ break;
+ }
+ p ++;
+ }
+ }
+ if (p == NULL) {
+ length = text_length - (current_p - text);
+ }
+ else {
+ length = end_line - current_p;
+ }
+ if (length == 0) {
+ break;
+ }
+ decoded_length = uudecode(current_p, length, decoded_buf, sizeof(decoded_buf));
+ if (decoded_length != 0 && decoded_length < length) {
+ data->appendBytes(decoded_buf, (unsigned int) decoded_length);
+ }
+
+ if (p == NULL)
+ break;
+
+ current_p = p;
+ while ((size_t) (current_p - text) < text_length) {
+ if ((* current_p != '\r') && (* current_p != '\n')) {
+ break;
+ }
+ current_p ++;
+ }
+ }
+
+ return data;
+ }
+ }
+}
+
+}