gmime r1300 - trunk/gmime



Author: fejj
Date: Thu May 29 03:36:20 2008
New Revision: 1300
URL: http://svn.gnome.org/viewvc/gmime?rev=1300&view=rev

Log:
oops, these didn't get added somehow

Added:
   trunk/gmime/gmime-encodings.c
   trunk/gmime/gmime-encodings.h

Added: trunk/gmime/gmime-encodings.c
==============================================================================
--- (empty file)
+++ trunk/gmime/gmime-encodings.c	Thu May 29 03:36:20 2008
@@ -0,0 +1,1095 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*  GMime
+ *  Copyright (C) 2000-2008 Jeffrey Stedfast
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <ctype.h>
+
+#include "gmime-table-private.h"
+#include "gmime-encodings.h"
+
+
+#ifdef ENABLE_WARNINGS
+#define w(x) x
+#else
+#define w(x)
+#endif /* ENABLE_WARNINGS */
+
+#define d(x)
+
+
+/**
+ * SECTION: gmime-encodings
+ * @title: gmime-encodings
+ * @short_description: MIME encoding functions
+ * @see_also:
+ *
+ * Utility functions to encode or decode MIME
+ * Content-Transfer-Encodings.
+ **/
+
+
+#define GMIME_UUENCODE_CHAR(c) ((c) ? (c) + ' ' : '`')
+#define	GMIME_UUDECODE_CHAR(c) (((c) - ' ') & 077)
+
+static char base64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
+
+static unsigned char gmime_base64_rank[256] = {
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
+	 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255,  0,255,255,
+	255,  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14,
+	 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
+	255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
+	 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+	255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
+};
+
+static unsigned char gmime_uu_rank[256] = {
+	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+	 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+	 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+	  0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
+	 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+};
+
+static unsigned char tohex[16] = {
+	'0', '1', '2', '3', '4', '5', '6', '7',
+	'8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
+};
+
+
+/**
+ * g_mime_content_encoding_from_string:
+ * @str: string representing a Content-Transfer-Encoding value
+ *
+ * Gets the appropriate #GMimeContentEncoding enumeration value based
+ * on the input string.
+ *
+ * Returns the #GMimeContentEncoding specified by @str or
+ * #GMIME_CONTENT_ENCODING_DEFAULT on error.
+ **/
+GMimeContentEncoding
+g_mime_content_encoding_from_string (const char *str)
+{
+	if (!g_ascii_strcasecmp (str, "7bit"))
+		return GMIME_CONTENT_ENCODING_7BIT;
+	else if (!g_ascii_strcasecmp (str, "8bit"))
+		return GMIME_CONTENT_ENCODING_8BIT;
+	else if (!g_ascii_strcasecmp (str, "binary"))
+		return GMIME_CONTENT_ENCODING_BINARY;
+	else if (!g_ascii_strcasecmp (str, "base64"))
+		return GMIME_CONTENT_ENCODING_BASE64;
+	else if (!g_ascii_strcasecmp (str, "quoted-printable"))
+		return GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE;
+	else if (!g_ascii_strcasecmp (str, "uuencode"))
+		return GMIME_CONTENT_ENCODING_UUENCODE;
+	else if (!g_ascii_strcasecmp (str, "x-uuencode"))
+		return GMIME_CONTENT_ENCODING_UUENCODE;
+	else
+		return GMIME_CONTENT_ENCODING_DEFAULT;
+}
+
+
+/**
+ * g_mime_content_encoding_to_string:
+ * @encoding: a #GMimeContentEncoding
+ *
+ * Gets the string value of the content encoding.
+ *
+ * Returns the encoding type as a string or %NULL on error. Available
+ * values for the encoding are: #GMIME_CONTENT_ENCODING_DEFAULT,
+ * #GMIME_CONTENT_ENCODING_7BIT, #GMIME_CONTENT_ENCODING_8BIT,
+ * #GMIME_CONTENT_ENCODING_BINARY, #GMIME_CONTENT_ENCODING_BASE64,
+ * #GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE and
+ * #GMIME_CONTENT_ENCODING_UUENCODE.
+ **/
+const char *
+g_mime_content_encoding_to_string (GMimeContentEncoding encoding)
+{
+	switch (encoding) {
+        case GMIME_CONTENT_ENCODING_7BIT:
+		return "7bit";
+        case GMIME_CONTENT_ENCODING_8BIT:
+		return "8bit";
+	case GMIME_CONTENT_ENCODING_BINARY:
+		return "binary";
+        case GMIME_CONTENT_ENCODING_BASE64:
+		return "base64";
+        case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
+		return "quoted-printable";
+	case GMIME_CONTENT_ENCODING_UUENCODE:
+		return "x-uuencode";
+	default:
+		/* I guess this is a good default... */
+		return NULL;
+	}
+}
+
+
+/**
+ * g_mime_encoding_init_encode:
+ * @state: a #GMimeEncoding to initialize
+ * @encoding: a #GMimeContentEncoding to use
+ *
+ * Initializes a #GMimeEncoding state machine for encoding to
+ * @encoding.
+ **/
+void
+g_mime_encoding_init_encode (GMimeEncoding *state, GMimeContentEncoding encoding)
+{
+	state->encoding = encoding;
+	state->encode = TRUE;
+	
+	g_mime_encoding_reset (state);
+}
+
+
+/**
+ * g_mime_encoding_init_decode:
+ * @state: a #GMimeEncoding to initialize
+ * @encoding: a #GMimeContentEncoding to use
+ *
+ * Initializes a #GMimeEncoding state machine for decoding from
+ * @encoding.
+ **/
+void
+g_mime_encoding_init_decode (GMimeEncoding *state, GMimeContentEncoding encoding)
+{
+	state->encoding = encoding;
+	state->encode = FALSE;
+	
+	g_mime_encoding_reset (state);
+}
+
+
+/**
+ * g_mime_encoding_reset:
+ * @state: a #GMimeEncoding to reset
+ *
+ * Resets the state of the #GMimeEncoding.
+ **/
+void
+g_mime_encoding_reset (GMimeEncoding *state)
+{
+	if (state->encode) {
+		if (state->encoding == GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE)
+			state->state = -1;
+		else
+			state->state = 0;
+	} else {
+		state->state = 0;
+	}
+	
+	state->save = 0;
+}
+
+
+/**
+ * g_mime_encoding_outlen:
+ * @state: a #GMimeEncoding
+ * @inlen: an input length
+ *
+ * Given the input length, @inlen, calculate the needed output length
+ * to perform an encoding or decoding step.
+ *
+ * Returns the maximum number of bytes needed to encode or decode a
+ * buffer of @inlen bytes.
+ **/
+size_t
+g_mime_encoding_outlen (GMimeEncoding *state, size_t inlen)
+{
+	switch (state->encoding) {
+	case GMIME_CONTENT_ENCODING_BASE64:
+		if (state->encode)
+			return GMIME_BASE64_ENCODE_LEN (inlen);
+		else
+			return inlen + 3;
+	case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
+		if (state->encode)
+			return GMIME_QP_ENCODE_LEN (inlen);
+		else
+			return inlen + 2;
+	case GMIME_CONTENT_ENCODING_UUENCODE:
+		if (state->encode)
+			return GMIME_UUENCODE_LEN (inlen);
+		else
+			return inlen + 3;
+	default:
+		return inlen;
+	}
+}
+
+
+/**
+ * g_mime_encoding_step:
+ * @state: a #GMimeEncoding
+ * @inbuf: an input buffer to encode or decode
+ * @inlen: input buffer length
+ * @outbuf: an output buffer
+ *
+ * Incrementally encodes or decodes (depending on @state) an input
+ * stream by 'stepping' through a block of input at a time.
+ *
+ * You should make sure @outbuf is large enough by calling
+ * g_mime_encoding_outlen() to find out how large @outbuf might need
+ * to be.
+ *
+ * Returns the number of bytes written to @outbuf.
+ **/
+size_t
+g_mime_encoding_step (GMimeEncoding *state, const char *inbuf, size_t inlen, char *outbuf)
+{
+	const unsigned char *inptr = (const unsigned char *) inbuf;
+	unsigned char *outptr = (unsigned char *) outbuf;
+	
+	switch (state->encoding) {
+	case GMIME_CONTENT_ENCODING_BASE64:
+		if (state->encode)
+			return g_mime_encoding_base64_encode_step (inptr, inlen, outptr, &state->state, &state->save);
+		else
+			return g_mime_encoding_base64_decode_step (inptr, inlen, outptr, &state->state, &state->save);
+	case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
+		if (state->encode)
+			return g_mime_encoding_quoted_encode_step (inptr, inlen, outptr, &state->state, &state->save);
+		else
+			return g_mime_encoding_quoted_decode_step (inptr, inlen, outptr, &state->state, &state->save);
+	case GMIME_CONTENT_ENCODING_UUENCODE:
+		if (state->encode)
+			return g_mime_encoding_uuencode_step (inptr, inlen, outptr, state->uubuf, &state->state, &state->save);
+		else
+			return g_mime_encoding_uudecode_step (inptr, inlen, outptr, &state->state, &state->save);
+	default:
+		memcpy (outbuf, inbuf, inlen);
+		return inlen;
+	}
+}
+
+
+/**
+ * g_mime_encoding_flush:
+ * @state: a #GMimeEncoding
+ * @inbuf: an input buffer to encode or decode
+ * @inlen: input buffer length
+ * @outbuf: an output buffer
+ *
+ * Completes the incremental encode or decode of the input stream (see
+ * g_mime_encoding_step() for details).
+ *
+ * Returns the number of bytes written to @outbuf.
+ **/
+size_t
+g_mime_encoding_flush (GMimeEncoding *state, const char *inbuf, size_t inlen, char *outbuf)
+{
+	const unsigned char *inptr = (const unsigned char *) inbuf;
+	unsigned char *outptr = (unsigned char *) outbuf;
+	
+	switch (state->encoding) {
+	case GMIME_CONTENT_ENCODING_BASE64:
+		if (state->encode)
+			return g_mime_encoding_base64_encode_close (inptr, inlen, outptr, &state->state, &state->save);
+		else
+			return g_mime_encoding_base64_decode_step (inptr, inlen, outptr, &state->state, &state->save);
+	case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
+		if (state->encode)
+			return g_mime_encoding_quoted_encode_close (inptr, inlen, outptr, &state->state, &state->save);
+		else
+			return g_mime_encoding_quoted_decode_step (inptr, inlen, outptr, &state->state, &state->save);
+	case GMIME_CONTENT_ENCODING_UUENCODE:
+		if (state->encode)
+			return g_mime_encoding_uuencode_close (inptr, inlen, outptr, state->uubuf, &state->state, &state->save);
+		else
+			return g_mime_encoding_uudecode_step (inptr, inlen, outptr, &state->state, &state->save);
+	default:
+		memcpy (outbuf, inbuf, inlen);
+		return inlen;
+	}
+}
+
+
+/**
+ * g_mime_encoding_base64_encode_close:
+ * @inbuf: input buffer
+ * @inlen: input buffer length
+ * @outbuf: output buffer
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been encoded
+ *
+ * Base64 encodes the input stream to the output stream. Call this
+ * when finished encoding data with g_mime_encoding_base64_encode_step()
+ * to flush off the last little bit.
+ *
+ * Returns the number of bytes encoded.
+ **/
+size_t
+g_mime_encoding_base64_encode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
+{
+	unsigned char *outptr = outbuf;
+	int c1, c2;
+	
+	if (inlen > 0)
+		outptr += g_mime_encoding_base64_encode_step (inbuf, inlen, outptr, state, save);
+	
+	c1 = ((unsigned char *)save)[1];
+	c2 = ((unsigned char *)save)[2];
+	
+	switch (((unsigned char *)save)[0]) {
+	case 2:
+		outptr[2] = base64_alphabet [(c2 & 0x0f) << 2];
+		goto skip;
+	case 1:
+		outptr[2] = '=';
+	skip:
+		outptr[0] = base64_alphabet [c1 >> 2];
+		outptr[1] = base64_alphabet [c2 >> 4 | ((c1 & 0x3) << 4)];
+		outptr[3] = '=';
+		outptr += 4;
+		break;
+	}
+	
+	*outptr++ = '\n';
+	
+	*save = 0;
+	*state = 0;
+	
+	return (outptr - outbuf);
+}
+
+
+/**
+ * g_mime_encoding_base64_encode_step:
+ * @inbuf: input buffer
+ * @inlen: input buffer length
+ * @outbuf: output buffer
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been encoded
+ *
+ * Base64 encodes a chunk of data. Performs an 'encode step', only
+ * encodes blocks of 3 characters to the output at a time, saves
+ * left-over state in state and save (initialise to 0 on first
+ * invocation).
+ *
+ * Returns the number of bytes encoded.
+ **/
+size_t
+g_mime_encoding_base64_encode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
+{
+	const register unsigned char *inptr;
+	register unsigned char *outptr;
+	
+	if (inlen == 0)
+		return 0;
+	
+	outptr = outbuf;
+	inptr = inbuf;
+	
+	if (inlen + ((unsigned char *)save)[0] > 2) {
+		const unsigned char *inend = inbuf + inlen - 2;
+		register int c1 = 0, c2 = 0, c3 = 0;
+		register int already;
+		
+		already = *state;
+		
+		switch (((char *)save)[0]) {
+		case 1:	c1 = ((unsigned char *)save)[1]; goto skip1;
+		case 2:	c1 = ((unsigned char *)save)[1];
+			c2 = ((unsigned char *)save)[2]; goto skip2;
+		}
+		
+		/* yes, we jump into the loop, no i'm not going to change it, its beautiful! */
+		while (inptr < inend) {
+			c1 = *inptr++;
+		skip1:
+			c2 = *inptr++;
+		skip2:
+			c3 = *inptr++;
+			*outptr++ = base64_alphabet [c1 >> 2];
+			*outptr++ = base64_alphabet [(c2 >> 4) | ((c1 & 0x3) << 4)];
+			*outptr++ = base64_alphabet [((c2 & 0x0f) << 2) | (c3 >> 6)];
+			*outptr++ = base64_alphabet [c3 & 0x3f];
+			/* this is a bit ugly ... */
+			if ((++already) >= 19) {
+				*outptr++ = '\n';
+				already = 0;
+			}
+		}
+		
+		((unsigned char *)save)[0] = 0;
+		inlen = 2 - (inptr - inend);
+		*state = already;
+	}
+	
+	d(printf ("state = %d, inlen = %d\n", (int)((char *)save)[0], inlen));
+	
+	if (inlen > 0) {
+		register char *saveout;
+		
+		/* points to the slot for the next char to save */
+		saveout = & (((char *)save)[1]) + ((char *)save)[0];
+		
+		/* inlen can only be 0 1 or 2 */
+		switch (inlen) {
+		case 2:	*saveout++ = *inptr++;
+		case 1:	*saveout++ = *inptr++;
+		}
+		((char *)save)[0] += inlen;
+	}
+	
+	d(printf ("mode = %d\nc1 = %c\nc2 = %c\n",
+		  (int)((char *)save)[0],
+		  (int)((char *)save)[1],
+		  (int)((char *)save)[2]));
+	
+	return (outptr - outbuf);
+}
+
+
+/**
+ * g_mime_encoding_base64_decode_step:
+ * @inbuf: input buffer
+ * @inlen: input buffer length
+ * @outbuf: output buffer
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been decoded
+ *
+ * Decodes a chunk of base64 encoded data.
+ *
+ * Returns the number of bytes decoded (which have been dumped in
+ * @outbuf).
+ **/
+size_t
+g_mime_encoding_base64_decode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
+{
+	const register unsigned char *inptr;
+	register unsigned char *outptr;
+	const unsigned char *inend;
+	register guint32 saved;
+	unsigned char c;
+	int i;
+	
+	inend = inbuf + inlen;
+	outptr = outbuf;
+	
+	/* convert 4 base64 bytes to 3 normal bytes */
+	saved = *save;
+	i = *state;
+	inptr = inbuf;
+	while (inptr < inend) {
+		c = gmime_base64_rank[*inptr++];
+		if (c != 0xff) {
+			saved = (saved << 6) | c;
+			i++;
+			if (i == 4) {
+				*outptr++ = saved >> 16;
+				*outptr++ = saved >> 8;
+				*outptr++ = saved;
+				i = 0;
+			}
+		}
+	}
+	
+	*save = saved;
+	*state = i;
+	
+	/* quick scan back for '=' on the end somewhere */
+	/* fortunately we can drop 1 output char for each trailing = (upto 2) */
+	i = 2;
+	while (inptr > inbuf && i) {
+		inptr--;
+		if (gmime_base64_rank[*inptr] != 0xff) {
+			if (*inptr == '=' && outptr > outbuf)
+				outptr--;
+			i--;
+		}
+	}
+	
+	/* if i != 0 then there is a truncation error! */
+	return (outptr - outbuf);
+}
+
+
+/**
+ * g_mime_encoding_uuencode_close:
+ * @inbuf: input buffer
+ * @inlen: input buffer length
+ * @outbuf: output buffer
+ * @uubuf: temporary buffer of 60 bytes
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been encoded
+ *
+ * Uuencodes a chunk of data. Call this when finished encoding data
+ * with g_mime_encoding_uuencode_step() to flush off the last little bit.
+ *
+ * Returns the number of bytes encoded.
+ **/
+size_t
+g_mime_encoding_uuencode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, unsigned char *uubuf, int *state, guint32 *save)
+{
+	register unsigned char *outptr, *bufptr;
+	register guint32 saved;
+	int uulen, uufill, i;
+	
+	outptr = outbuf;
+	
+	if (inlen > 0)
+		outptr += g_mime_encoding_uuencode_step (inbuf, inlen, outbuf, uubuf, state, save);
+	
+	uufill = 0;
+	
+	saved = *save;
+	i = *state & 0xff;
+	uulen = (*state >> 8) & 0xff;
+	
+	bufptr = uubuf + ((uulen / 3) * 4);
+	
+	if (i > 0) {
+		while (i < 3) {
+			saved <<= 8;
+			uufill++;
+			i++;
+		}
+		
+		if (i == 3) {
+			/* convert 3 normal bytes into 4 uuencoded bytes */
+			unsigned char b0, b1, b2;
+			
+			b0 = (saved >> 16) & 0xff;
+			b1 = (saved >> 8) & 0xff;
+			b2 = saved & 0xff;
+			
+			*bufptr++ = GMIME_UUENCODE_CHAR ((b0 >> 2) & 0x3f);
+			*bufptr++ = GMIME_UUENCODE_CHAR (((b0 << 4) | ((b1 >> 4) & 0xf)) & 0x3f);
+			*bufptr++ = GMIME_UUENCODE_CHAR (((b1 << 2) | ((b2 >> 6) & 0x3)) & 0x3f);
+			*bufptr++ = GMIME_UUENCODE_CHAR (b2 & 0x3f);
+			
+			uulen += 3;
+			saved = 0;
+			i = 0;
+		}
+	}
+	
+	if (uulen > 0) {
+		int cplen = ((uulen / 3) * 4);
+		
+		*outptr++ = GMIME_UUENCODE_CHAR ((uulen - uufill) & 0xff);
+		memcpy (outptr, uubuf, cplen);
+		outptr += cplen;
+		*outptr++ = '\n';
+		uulen = 0;
+	}
+	
+	*outptr++ = GMIME_UUENCODE_CHAR (uulen & 0xff);
+	*outptr++ = '\n';
+	
+	*save = 0;
+	*state = 0;
+	
+	return (outptr - outbuf);
+}
+
+
+/**
+ * g_mime_encoding_uuencode_step:
+ * @inbuf: input buffer
+ * @inlen: input buffer length
+ * @outbuf: output stream
+ * @uubuf: temporary buffer of 60 bytes
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been encoded
+ *
+ * Uuencodes a chunk of data. Performs an 'encode step', only encodes
+ * blocks of 45 characters to the output at a time, saves left-over
+ * state in @uubuf, @state and @save (initialize to 0 on first
+ * invocation).
+ *
+ * Returns the number of bytes encoded.
+ **/
+size_t
+g_mime_encoding_uuencode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, unsigned char *uubuf, int *state, guint32 *save)
+{
+	register unsigned char *outptr, *bufptr;
+	const register unsigned char *inptr;
+	const unsigned char *inend;
+	unsigned char b0, b1, b2;
+	guint32 saved;
+	int uulen, i;
+	
+	if (inlen == 0)
+		return 0;
+	
+	inend = inbuf + inlen;
+	outptr = outbuf;
+	inptr = inbuf;
+	
+	saved = *save;
+	i = *state & 0xff;
+	uulen = (*state >> 8) & 0xff;
+	
+	if ((inlen + uulen) < 45) {
+		/* not enough input to write a full uuencoded line */
+		bufptr = uubuf + ((uulen / 3) * 4);
+	} else {
+		bufptr = outptr + 1;
+		
+		if (uulen > 0) {
+			/* copy the previous call's tmpbuf to outbuf */
+			memcpy (bufptr, uubuf, ((uulen / 3) * 4));
+			bufptr += ((uulen / 3) * 4);
+		}
+	}
+	
+	if (i == 2) {
+		b0 = (saved >> 8) & 0xff;
+		b1 = saved & 0xff;
+		saved = 0;
+		i = 0;
+		
+		goto skip2;
+	} else if (i == 1) {
+		if ((inptr + 2) < inend) {
+			b0 = saved & 0xff;
+			saved = 0;
+			i = 0;
+			
+			goto skip1;
+		}
+		
+		while (inptr < inend) {
+			saved = (saved << 8) | *inptr++;
+			i++;
+		}
+	}
+	
+	while (inptr < inend) {
+		while (uulen < 45 && (inptr + 3) <= inend) {
+			b0 = *inptr++;
+		skip1:
+			b1 = *inptr++;
+		skip2:
+			b2 = *inptr++;
+			
+			/* convert 3 normal bytes into 4 uuencoded bytes */
+			*bufptr++ = GMIME_UUENCODE_CHAR ((b0 >> 2) & 0x3f);
+			*bufptr++ = GMIME_UUENCODE_CHAR (((b0 << 4) | ((b1 >> 4) & 0xf)) & 0x3f);
+			*bufptr++ = GMIME_UUENCODE_CHAR (((b1 << 2) | ((b2 >> 6) & 0x3)) & 0x3f);
+			*bufptr++ = GMIME_UUENCODE_CHAR (b2 & 0x3f);
+			
+			uulen += 3;
+		}
+		
+		if (uulen >= 45) {
+			/* output the uu line length */
+			*outptr = GMIME_UUENCODE_CHAR (uulen & 0xff);
+			outptr += ((45 / 3) * 4) + 1;
+			
+			*outptr++ = '\n';
+			uulen = 0;
+			
+			if ((inptr + 45) <= inend) {
+				/* we have enough input to output another full line */
+				bufptr = outptr + 1;
+			} else {
+				bufptr = uubuf;
+			}
+		} else {
+			/* not enough input to continue... */
+			for (i = 0, saved = 0; inptr < inend; i++)
+				saved = (saved << 8) | *inptr++;
+		}
+	}
+	
+	*save = saved;
+	*state = ((uulen & 0xff) << 8) | (i & 0xff);
+	
+	return (outptr - outbuf);
+}
+
+
+/**
+ * g_mime_encoding_uudecode_step:
+ * @inbuf: input buffer
+ * @inlen: input buffer length
+ * @outbuf: output buffer
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been decoded
+ *
+ * Uudecodes a chunk of data. Performs a 'decode step' on a chunk of
+ * uuencoded data. Assumes the "begin mode filename" line has
+ * been stripped off.
+ *
+ * Returns the number of bytes decoded.
+ **/
+size_t
+g_mime_encoding_uudecode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
+{
+	const register unsigned char *inptr;
+	register unsigned char *outptr;
+	const unsigned char *inend;
+	unsigned char ch;
+	register guint32 saved;
+	gboolean last_was_eoln;
+	int uulen, i;
+	
+	if (*state & GMIME_UUDECODE_STATE_END)
+		return 0;
+	
+	saved = *save;
+	i = *state & 0xff;
+	uulen = (*state >> 8) & 0xff;
+	if (uulen == 0)
+		last_was_eoln = TRUE;
+	else
+		last_was_eoln = FALSE;
+	
+	inend = inbuf + inlen;
+	outptr = outbuf;
+	inptr = inbuf;
+	
+	while (inptr < inend) {
+		if (*inptr == '\n') {
+			last_was_eoln = TRUE;
+			
+			inptr++;
+			continue;
+		} else if (!uulen || last_was_eoln) {
+			/* first octet on a line is the uulen octet */
+			uulen = gmime_uu_rank[*inptr];
+			last_was_eoln = FALSE;
+			if (uulen == 0) {
+				*state |= GMIME_UUDECODE_STATE_END;
+				break;
+			}
+			
+			inptr++;
+			continue;
+		}
+		
+		ch = *inptr++;
+		
+		if (uulen > 0) {
+			/* save the byte */
+			saved = (saved << 8) | ch;
+			i++;
+			if (i == 4) {
+				/* convert 4 uuencoded bytes to 3 normal bytes */
+				unsigned char b0, b1, b2, b3;
+				
+				b0 = saved >> 24;
+				b1 = saved >> 16 & 0xff;
+				b2 = saved >> 8 & 0xff;
+				b3 = saved & 0xff;
+				
+				if (uulen >= 3) {
+					*outptr++ = gmime_uu_rank[b0] << 2 | gmime_uu_rank[b1] >> 4;
+					*outptr++ = gmime_uu_rank[b1] << 4 | gmime_uu_rank[b2] >> 2;
+				        *outptr++ = gmime_uu_rank[b2] << 6 | gmime_uu_rank[b3];
+				} else {
+					if (uulen >= 1) {
+						*outptr++ = gmime_uu_rank[b0] << 2 | gmime_uu_rank[b1] >> 4;
+					}
+					if (uulen >= 2) {
+						*outptr++ = gmime_uu_rank[b1] << 4 | gmime_uu_rank[b2] >> 2;
+					}
+				}
+				
+				i = 0;
+				saved = 0;
+				uulen -= 3;
+			}
+		} else {
+			break;
+		}
+	}
+	
+	*save = saved;
+	*state = (*state & GMIME_UUDECODE_STATE_MASK) | ((uulen & 0xff) << 8) | (i & 0xff);
+	
+	return (outptr - outbuf);
+}
+
+
+/**
+ * g_mime_encoding_quoted_encode_close:
+ * @inbuf: input buffer
+ * @inlen: input buffer length
+ * @outbuf: output buffer
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been encoded
+ *
+ * Quoted-printable encodes a block of text. Call this when finished
+ * encoding data with g_mime_encoding_quoted_encode_step() to flush off
+ * the last little bit.
+ *
+ * Returns the number of bytes encoded.
+ **/
+size_t
+g_mime_encoding_quoted_encode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
+{
+	register unsigned char *outptr = outbuf;
+	int last;
+	
+	if (inlen > 0)
+		outptr += g_mime_encoding_quoted_encode_step (inbuf, inlen, outptr, state, save);
+	
+	last = *state;
+	if (last != -1) {
+		/* space/tab must be encoded if its the last character on
+		   the line */
+		if (is_qpsafe (last) && !is_blank (last)) {
+			*outptr++ = last;
+		} else {
+			*outptr++ = '=';
+			*outptr++ = tohex[(last >> 4) & 0xf];
+			*outptr++ = tohex[last & 0xf];
+		}
+	}
+	
+	*outptr++ = '\n';
+	
+	*save = 0;
+	*state = -1;
+	
+	return (outptr - outbuf);
+}
+
+
+/**
+ * g_mime_encoding_quoted_encode_step:
+ * @inbuf: input buffer
+ * @inlen: input buffer length
+ * @outbuf: output buffer
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been encoded
+ *
+ * Quoted-printable encodes a block of text. Performs an 'encode
+ * step', saves left-over state in state and save (initialise to -1 on
+ * first invocation).
+ *
+ * Returns the number of bytes encoded.
+ **/
+size_t
+g_mime_encoding_quoted_encode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
+{
+	const register unsigned char *inptr = inbuf;
+	const unsigned char *inend = inbuf + inlen;
+	register unsigned char *outptr = outbuf;
+	register guint32 sofar = *save;  /* keeps track of how many chars on a line */
+	register int last = *state;  /* keeps track if last char to end was a space cr etc */
+	unsigned char c;
+	
+	while (inptr < inend) {
+		c = *inptr++;
+		if (c == '\r') {
+			if (last != -1) {
+				*outptr++ = '=';
+				*outptr++ = tohex[(last >> 4) & 0xf];
+				*outptr++ = tohex[last & 0xf];
+				sofar += 3;
+			}
+			last = c;
+		} else if (c == '\n') {
+			if (last != -1 && last != '\r') {
+				*outptr++ = '=';
+				*outptr++ = tohex[(last >> 4) & 0xf];
+				*outptr++ = tohex[last & 0xf];
+			}
+			*outptr++ = '\n';
+			sofar = 0;
+			last = -1;
+		} else {
+			if (last != -1) {
+				if (is_qpsafe (last)) {
+					*outptr++ = last;
+					sofar++;
+				} else {
+					*outptr++ = '=';
+					*outptr++ = tohex[(last >> 4) & 0xf];
+					*outptr++ = tohex[last & 0xf];
+					sofar += 3;
+				}
+			}
+			
+			if (is_qpsafe (c)) {
+				if (sofar > 74) {
+					*outptr++ = '=';
+					*outptr++ = '\n';
+					sofar = 0;
+				}
+				
+				/* delay output of space char */
+				if (is_blank (c)) {
+					last = c;
+				} else {
+					*outptr++ = c;
+					sofar++;
+					last = -1;
+				}
+			} else {
+				if (sofar > 72) {
+					*outptr++ = '=';
+					*outptr++ = '\n';
+					sofar = 3;
+				} else
+					sofar += 3;
+				
+				*outptr++ = '=';
+				*outptr++ = tohex[(c >> 4) & 0xf];
+				*outptr++ = tohex[c & 0xf];
+				last = -1;
+			}
+		}
+	}
+	
+	*save = sofar;
+	*state = last;
+	
+	return (outptr - outbuf);
+}
+
+
+/**
+ * g_mime_encoding_quoted_decode_step:
+ * @inbuf: input buffer
+ * @inlen: input buffer length
+ * @outbuf: output buffer
+ * @state: holds the number of bits that are stored in @save
+ * @save: leftover bits that have not yet been decoded
+ *
+ * Decodes a block of quoted-printable encoded data. Performs a
+ * 'decode step' on a chunk of QP encoded data.
+ *
+ * Returns the number of bytes decoded.
+ **/
+size_t
+g_mime_encoding_quoted_decode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
+{
+	/* FIXME: this does not strip trailing spaces from lines (as
+	 * it should, rfc 2045, section 6.7) Should it also
+	 * canonicalise the end of line to CR LF??
+	 *
+	 * Note: Trailing rubbish (at the end of input), like = or =x
+	 * or =\r will be lost.
+	 */
+	const register unsigned char *inptr = inbuf;
+	const unsigned char *inend = inbuf + inlen;
+	register unsigned char *outptr = outbuf;
+	guint32 isave = *save;
+	int istate = *state;
+	unsigned char c;
+	
+	d(printf ("quoted-printable, decoding text '%.*s'\n", inlen, inbuf));
+	
+	while (inptr < inend) {
+		switch (istate) {
+		case 0:
+			while (inptr < inend) {
+				c = *inptr++;
+				/* FIXME: use a specials table to avoid 3 comparisons for the common case */
+				if (c == '=') { 
+					istate = 1;
+					break;
+				}
+#ifdef CANONICALISE_EOL
+				/*else if (c=='\r') {
+					state = 3;
+				} else if (c=='\n') {
+					*outptr++ = '\r';
+					*outptr++ = c;
+					} */
+#endif
+				else {
+					*outptr++ = c;
+				}
+			}
+			break;
+		case 1:
+			c = *inptr++;
+			if (c == '\n') {
+				/* soft break ... unix end of line */
+				istate = 0;
+			} else {
+				isave = c;
+				istate = 2;
+			}
+			break;
+		case 2:
+			c = *inptr++;
+			if (isxdigit (c) && isxdigit (isave)) {
+				c = toupper ((int) c);
+				isave = toupper ((int) isave);
+				*outptr++ = (((isave >= 'A' ? isave - 'A' + 10 : isave - '0') & 0x0f) << 4)
+					| ((c >= 'A' ? c - 'A' + 10 : c - '0') & 0x0f);
+			} else if (c == '\n' && isave == '\r') {
+				/* soft break ... canonical end of line */
+			} else {
+				/* just output the data */
+				*outptr++ = '=';
+				*outptr++ = isave;
+				*outptr++ = c;
+			}
+			istate = 0;
+			break;
+#ifdef CANONICALISE_EOL
+		case 3:
+			/* convert \n -> to \r\n, leaves \r\n alone */
+			c = *inptr++;
+			if (c == '\n') {
+				*outptr++ = '\r';
+				*outptr++ = c;
+			} else {
+				*outptr++ = '\r';
+				*outptr++ = '\n';
+				*outptr++ = c;
+			}
+			istate = 0;
+			break;
+#endif
+		}
+	}
+	
+	*state = istate;
+	*save = isave;
+	
+	return (outptr - outbuf);
+}

Added: trunk/gmime/gmime-encodings.h
==============================================================================
--- (empty file)
+++ trunk/gmime/gmime-encodings.h	Thu May 29 03:36:20 2008
@@ -0,0 +1,161 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*  GMime
+ *  Copyright (C) 2000-2008 Jeffrey Stedfast
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public License
+ *  as published by the Free Software Foundation; either version 2.1
+ *  of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free
+ *  Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
+ *  02110-1301, USA.
+ */
+
+
+#ifndef __GMIME_ENCODINGS_H__
+#define __GMIME_ENCODINGS_H__
+
+#include <glib.h>
+#include <sys/types.h>
+
+G_BEGIN_DECLS
+
+
+/**
+ * GMimeContentEncoding:
+ * @GMIME_CONTENT_ENCODING_DEFAULT: Default transfer encoding.
+ * @GMIME_CONTENT_ENCODING_7BIT: 7bit text transfer encoding.
+ * @GMIME_CONTENT_ENCODING_8BIT: 8bit text transfer encoding.
+ * @GMIME_CONTENT_ENCODING_BINARY: Binary transfer encoding.
+ * @GMIME_CONTENT_ENCODING_BASE64: Base64 transfer encoding.
+ * @GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE: Quoted-printable transfer encoding.
+ * @GMIME_CONTENT_ENCODING_UUENCODE: Uuencode transfer encoding.
+ *
+ * A Content-Transfer-Encoding enumeration.
+ **/
+typedef enum {
+	GMIME_CONTENT_ENCODING_DEFAULT,
+	GMIME_CONTENT_ENCODING_7BIT,
+	GMIME_CONTENT_ENCODING_8BIT,
+	GMIME_CONTENT_ENCODING_BINARY,
+	GMIME_CONTENT_ENCODING_BASE64,
+	GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE,
+	GMIME_CONTENT_ENCODING_UUENCODE
+} GMimeContentEncoding;
+
+
+GMimeContentEncoding g_mime_content_encoding_from_string (const char *str);
+const char *g_mime_content_encoding_to_string (GMimeContentEncoding encoding);
+
+
+/**
+ * GMIME_BASE64_ENCODE_LEN:
+ * @x: Length of the input data to encode
+ *
+ * Calculates the maximum number of bytes needed to base64 encode the
+ * full input buffer of length @x.
+ *
+ * Returns the number of output bytes needed to base64 encode an input
+ * buffer of size @x.
+ **/
+#define GMIME_BASE64_ENCODE_LEN(x) ((size_t) (((((x) + 2) / 57) * 77) + 77))
+
+
+/**
+ * GMIME_QP_ENCODE_LEN:
+ * @x: Length of the input data to encode
+ *
+ * Calculates the maximum number of bytes needed to encode the full
+ * input buffer of length @x using the quoted-printable encoding.
+ *
+ * Returns the number of output bytes needed to encode an input buffer
+ * of size @x using the quoted-printable encoding.
+ **/
+#define GMIME_QP_ENCODE_LEN(x)     ((size_t) (((x) + 1) * 3))
+
+
+/**
+ * GMIME_UUENCODE_LEN:
+ * @x: Length of the input data to encode
+ *
+ * Calculates the maximum number of bytes needed to uuencode the full
+ * input buffer of length @x.
+ *
+ * Returns the number of output bytes needed to uuencode an input
+ * buffer of size @x.
+ **/
+#define GMIME_UUENCODE_LEN(x)      ((size_t) (((((x) + 2) / 45) * 62) + 62))
+
+
+/**
+ * GMIME_UUDECODE_STATE_INIT:
+ *
+ * Initial state for the g_mime_utils_uudecode_step() function.
+ **/
+#define GMIME_UUDECODE_STATE_INIT   (0)
+
+
+/**
+ * GMIME_UUDECODE_STATE_BEGIN:
+ *
+ * State for the g_mime_utils_uudecode_step() function, denoting that
+ * the 'begin' line has been found.
+ **/
+#define GMIME_UUDECODE_STATE_BEGIN  (1 << 16)
+
+
+/**
+ * GMIME_UUDECODE_STATE_END:
+ *
+ * State for the g_mime_utils_uudecode_step() function, denoting that
+ * the end of the UU encoded block has been found.
+ **/
+#define GMIME_UUDECODE_STATE_END    (1 << 17)
+#define GMIME_UUDECODE_STATE_MASK   (GMIME_UUDECODE_STATE_BEGIN | GMIME_UUDECODE_STATE_END)
+
+
+typedef struct _GMimeEncoding {
+	GMimeContentEncoding encoding;
+	unsigned char uubuf[60];
+	gboolean encode;
+	guint32 save;
+	int state;
+} GMimeEncoding;
+
+
+void g_mime_encoding_init_encode (GMimeEncoding *state, GMimeContentEncoding encoding);
+void g_mime_encoding_init_decode (GMimeEncoding *state, GMimeContentEncoding encoding);
+void g_mime_encoding_reset (GMimeEncoding *state);
+
+size_t g_mime_encoding_outlen (GMimeEncoding *state, size_t inlen);
+
+size_t g_mime_encoding_step (GMimeEncoding *state, const char *inbuf, size_t inlen, char *outbuf);
+size_t g_mime_encoding_flush (GMimeEncoding *state, const char *inbuf, size_t inlen, char *outbuf);
+
+
+/* do incremental base64 (de/en)coding */
+size_t g_mime_encoding_base64_decode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save);
+size_t g_mime_encoding_base64_encode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save);
+size_t g_mime_encoding_base64_encode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save);
+
+/* do incremental uu (de/en)coding */
+size_t g_mime_encoding_uudecode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save);
+size_t g_mime_encoding_uuencode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, unsigned char *uubuf, int *state, guint32 *save);
+size_t g_mime_encoding_uuencode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, unsigned char *uubuf, int *state, guint32 *save);
+
+/* do incremental quoted-printable (de/en)coding */
+size_t g_mime_encoding_quoted_decode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save);
+size_t g_mime_encoding_quoted_encode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save);
+size_t g_mime_encoding_quoted_encode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save);
+
+
+G_END_DECLS
+
+#endif /* __GMIME_ENCODINGS_H__ */



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]