1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2000-2012 Jeffrey Stedfast and Michael Zucchi
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public License
7 * as published by the Free Software Foundation; either version 2.1
8 * of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free
17 * Software Foundation, 51 Franklin Street, Fifth Floor, Boston, MA
30 #include "gmime-table-private.h"
31 #include "gmime-encodings.h"
34 #ifdef ENABLE_WARNINGS
38 #endif /* ENABLE_WARNINGS */
44 * SECTION: gmime-encodings
45 * @title: gmime-encodings
46 * @short_description: MIME encoding functions
49 * Utility functions to encode or decode MIME
50 * Content-Transfer-Encodings.
54 #define GMIME_UUENCODE_CHAR(c) ((c) ? (c) + ' ' : '`')
55 #define GMIME_UUDECODE_CHAR(c) (((c) - ' ') & 077)
57 static char base64_alphabet[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
59 static unsigned char gmime_base64_rank[256] = {
60 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
61 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
62 255,255,255,255,255,255,255,255,255,255,255, 62,255,255,255, 63,
63 52, 53, 54, 55, 56, 57, 58, 59, 60, 61,255,255,255, 0,255,255,
64 255, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14,
65 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,255,255,255,255,255,
66 255, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40,
67 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51,255,255,255,255,255,
68 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
69 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
70 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
71 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
72 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
73 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
74 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
75 255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,
78 static unsigned char gmime_uu_rank[256] = {
79 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
80 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
81 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
82 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
83 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
84 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
85 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
86 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
87 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
88 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
89 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
90 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
91 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
92 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
93 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
94 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
97 static unsigned char tohex[16] = {
98 '0', '1', '2', '3', '4', '5', '6', '7',
99 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
104 * g_mime_content_encoding_from_string:
105 * @str: a string representing a Content-Transfer-Encoding value
107 * Gets the appropriate #GMimeContentEncoding enumeration value based
108 * on the input string.
110 * Returns: the #GMimeContentEncoding specified by @str or
111 * #GMIME_CONTENT_ENCODING_DEFAULT on error.
114 g_mime_content_encoding_from_string (const char *str)
116 if (!g_ascii_strcasecmp (str, "7bit"))
117 return GMIME_CONTENT_ENCODING_7BIT;
118 else if (!g_ascii_strcasecmp (str, "8bit"))
119 return GMIME_CONTENT_ENCODING_8BIT;
120 else if (!g_ascii_strcasecmp (str, "7-bit"))
121 return GMIME_CONTENT_ENCODING_7BIT;
122 else if (!g_ascii_strcasecmp (str, "8-bit"))
123 return GMIME_CONTENT_ENCODING_8BIT;
124 else if (!g_ascii_strcasecmp (str, "binary"))
125 return GMIME_CONTENT_ENCODING_BINARY;
126 else if (!g_ascii_strcasecmp (str, "base64"))
127 return GMIME_CONTENT_ENCODING_BASE64;
128 else if (!g_ascii_strcasecmp (str, "quoted-printable"))
129 return GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE;
130 else if (!g_ascii_strcasecmp (str, "uuencode"))
131 return GMIME_CONTENT_ENCODING_UUENCODE;
132 else if (!g_ascii_strcasecmp (str, "x-uuencode"))
133 return GMIME_CONTENT_ENCODING_UUENCODE;
134 else if (!g_ascii_strcasecmp (str, "x-uue"))
135 return GMIME_CONTENT_ENCODING_UUENCODE;
137 return GMIME_CONTENT_ENCODING_DEFAULT;
142 * g_mime_content_encoding_to_string:
143 * @encoding: a #GMimeContentEncoding
145 * Gets the string value of the content encoding.
147 * Returns: the encoding type as a string or %NULL on error. Available
148 * values for the encoding are: #GMIME_CONTENT_ENCODING_DEFAULT,
149 * #GMIME_CONTENT_ENCODING_7BIT, #GMIME_CONTENT_ENCODING_8BIT,
150 * #GMIME_CONTENT_ENCODING_BINARY, #GMIME_CONTENT_ENCODING_BASE64,
151 * #GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE and
152 * #GMIME_CONTENT_ENCODING_UUENCODE.
155 g_mime_content_encoding_to_string (GMimeContentEncoding encoding)
158 case GMIME_CONTENT_ENCODING_7BIT:
160 case GMIME_CONTENT_ENCODING_8BIT:
162 case GMIME_CONTENT_ENCODING_BINARY:
164 case GMIME_CONTENT_ENCODING_BASE64:
166 case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
167 return "quoted-printable";
168 case GMIME_CONTENT_ENCODING_UUENCODE:
171 /* I guess this is a good default... */
178 * g_mime_encoding_init_encode:
179 * @state: a #GMimeEncoding to initialize
180 * @encoding: a #GMimeContentEncoding to use
182 * Initializes a #GMimeEncoding state machine for encoding to
186 g_mime_encoding_init_encode (GMimeEncoding *state, GMimeContentEncoding encoding)
188 state->encoding = encoding;
189 state->encode = TRUE;
191 g_mime_encoding_reset (state);
196 * g_mime_encoding_init_decode:
197 * @state: a #GMimeEncoding to initialize
198 * @encoding: a #GMimeContentEncoding to use
200 * Initializes a #GMimeEncoding state machine for decoding from
204 g_mime_encoding_init_decode (GMimeEncoding *state, GMimeContentEncoding encoding)
206 state->encoding = encoding;
207 state->encode = FALSE;
209 g_mime_encoding_reset (state);
214 * g_mime_encoding_reset:
215 * @state: a #GMimeEncoding to reset
217 * Resets the state of the #GMimeEncoding.
220 g_mime_encoding_reset (GMimeEncoding *state)
223 if (state->encoding == GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE)
236 * g_mime_encoding_outlen:
237 * @state: a #GMimeEncoding
238 * @inlen: an input length
240 * Given the input length, @inlen, calculate the needed output length
241 * to perform an encoding or decoding step.
243 * Returns: the maximum number of bytes needed to encode or decode a
244 * buffer of @inlen bytes.
247 g_mime_encoding_outlen (GMimeEncoding *state, size_t inlen)
249 switch (state->encoding) {
250 case GMIME_CONTENT_ENCODING_BASE64:
252 return GMIME_BASE64_ENCODE_LEN (inlen);
255 case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
257 return GMIME_QP_ENCODE_LEN (inlen);
260 case GMIME_CONTENT_ENCODING_UUENCODE:
262 return GMIME_UUENCODE_LEN (inlen);
272 * g_mime_encoding_step:
273 * @state: a #GMimeEncoding
274 * @inbuf: an input buffer to encode or decode
275 * @inlen: input buffer length
276 * @outbuf: an output buffer
278 * Incrementally encodes or decodes (depending on @state) an input
279 * stream by 'stepping' through a block of input at a time.
281 * You should make sure @outbuf is large enough by calling
282 * g_mime_encoding_outlen() to find out how large @outbuf might need
285 * Returns: the number of bytes written to @outbuf.
288 g_mime_encoding_step (GMimeEncoding *state, const char *inbuf, size_t inlen, char *outbuf)
290 const unsigned char *inptr = (const unsigned char *) inbuf;
291 unsigned char *outptr = (unsigned char *) outbuf;
293 switch (state->encoding) {
294 case GMIME_CONTENT_ENCODING_BASE64:
296 return g_mime_encoding_base64_encode_step (inptr, inlen, outptr, &state->state, &state->save);
298 return g_mime_encoding_base64_decode_step (inptr, inlen, outptr, &state->state, &state->save);
299 case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
301 return g_mime_encoding_quoted_encode_step (inptr, inlen, outptr, &state->state, &state->save);
303 return g_mime_encoding_quoted_decode_step (inptr, inlen, outptr, &state->state, &state->save);
304 case GMIME_CONTENT_ENCODING_UUENCODE:
306 return g_mime_encoding_uuencode_step (inptr, inlen, outptr, state->uubuf, &state->state, &state->save);
308 return g_mime_encoding_uudecode_step (inptr, inlen, outptr, &state->state, &state->save);
310 memcpy (outbuf, inbuf, inlen);
317 * g_mime_encoding_flush:
318 * @state: a #GMimeEncoding
319 * @inbuf: an input buffer to encode or decode
320 * @inlen: input buffer length
321 * @outbuf: an output buffer
323 * Completes the incremental encode or decode of the input stream (see
324 * g_mime_encoding_step() for details).
326 * Returns: the number of bytes written to @outbuf.
329 g_mime_encoding_flush (GMimeEncoding *state, const char *inbuf, size_t inlen, char *outbuf)
331 const unsigned char *inptr = (const unsigned char *) inbuf;
332 unsigned char *outptr = (unsigned char *) outbuf;
334 switch (state->encoding) {
335 case GMIME_CONTENT_ENCODING_BASE64:
337 return g_mime_encoding_base64_encode_close (inptr, inlen, outptr, &state->state, &state->save);
339 return g_mime_encoding_base64_decode_step (inptr, inlen, outptr, &state->state, &state->save);
340 case GMIME_CONTENT_ENCODING_QUOTEDPRINTABLE:
342 return g_mime_encoding_quoted_encode_close (inptr, inlen, outptr, &state->state, &state->save);
344 return g_mime_encoding_quoted_decode_step (inptr, inlen, outptr, &state->state, &state->save);
345 case GMIME_CONTENT_ENCODING_UUENCODE:
347 return g_mime_encoding_uuencode_close (inptr, inlen, outptr, state->uubuf, &state->state, &state->save);
349 return g_mime_encoding_uudecode_step (inptr, inlen, outptr, &state->state, &state->save);
351 memcpy (outbuf, inbuf, inlen);
358 * g_mime_encoding_base64_encode_close:
359 * @inbuf: input buffer
360 * @inlen: input buffer length
361 * @outbuf: output buffer
362 * @state: holds the number of bits that are stored in @save
363 * @save: leftover bits that have not yet been encoded
365 * Base64 encodes the input stream to the output stream. Call this
366 * when finished encoding data with g_mime_encoding_base64_encode_step()
367 * to flush off the last little bit.
369 * Returns: the number of bytes encoded.
372 g_mime_encoding_base64_encode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
374 unsigned char *outptr = outbuf;
378 outptr += g_mime_encoding_base64_encode_step (inbuf, inlen, outptr, state, save);
380 c1 = ((unsigned char *)save)[1];
381 c2 = ((unsigned char *)save)[2];
383 switch (((unsigned char *)save)[0]) {
385 outptr[2] = base64_alphabet [(c2 & 0x0f) << 2];
390 outptr[0] = base64_alphabet [c1 >> 2];
391 outptr[1] = base64_alphabet [c2 >> 4 | ((c1 & 0x3) << 4)];
402 return (outptr - outbuf);
407 * g_mime_encoding_base64_encode_step:
408 * @inbuf: input buffer
409 * @inlen: input buffer length
410 * @outbuf: output buffer
411 * @state: holds the number of bits that are stored in @save
412 * @save: leftover bits that have not yet been encoded
414 * Base64 encodes a chunk of data. Performs an 'encode step', only
415 * encodes blocks of 3 characters to the output at a time, saves
416 * left-over state in state and save (initialise to 0 on first
419 * Returns: the number of bytes encoded.
422 g_mime_encoding_base64_encode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
424 const register unsigned char *inptr;
425 register unsigned char *outptr;
433 if (inlen + ((unsigned char *)save)[0] > 2) {
434 const unsigned char *inend = inbuf + inlen - 2;
435 register int c1 = 0, c2 = 0, c3 = 0;
436 register int already;
440 switch (((char *)save)[0]) {
441 case 1: c1 = ((unsigned char *)save)[1]; goto skip1;
442 case 2: c1 = ((unsigned char *)save)[1];
443 c2 = ((unsigned char *)save)[2]; goto skip2;
446 /* yes, we jump into the loop, no i'm not going to change it, its beautiful! */
447 while (inptr < inend) {
453 *outptr++ = base64_alphabet [c1 >> 2];
454 *outptr++ = base64_alphabet [(c2 >> 4) | ((c1 & 0x3) << 4)];
455 *outptr++ = base64_alphabet [((c2 & 0x0f) << 2) | (c3 >> 6)];
456 *outptr++ = base64_alphabet [c3 & 0x3f];
457 /* this is a bit ugly ... */
458 if ((++already) >= 19) {
464 ((unsigned char *)save)[0] = 0;
465 inlen = 2 - (inptr - inend);
469 d(printf ("state = %d, inlen = %d\n", (int)((char *)save)[0], inlen));
472 register char *saveout;
474 /* points to the slot for the next char to save */
475 saveout = & (((char *)save)[1]) + ((char *)save)[0];
477 /* inlen can only be 0, 1 or 2 */
479 case 2: *saveout++ = *inptr++;
480 case 1: *saveout++ = *inptr++;
482 ((char *)save)[0] += (char) inlen;
485 d(printf ("mode = %d\nc1 = %c\nc2 = %c\n",
486 (int)((char *)save)[0],
487 (int)((char *)save)[1],
488 (int)((char *)save)[2]));
490 return (outptr - outbuf);
495 * g_mime_encoding_base64_decode_step:
496 * @inbuf: input buffer
497 * @inlen: input buffer length
498 * @outbuf: output buffer
499 * @state: holds the number of bits that are stored in @save
500 * @save: leftover bits that have not yet been decoded
502 * Decodes a chunk of base64 encoded data.
504 * Returns: the number of bytes decoded (which have been dumped in
508 g_mime_encoding_base64_decode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
510 const register unsigned char *inptr;
511 register unsigned char *outptr;
512 const unsigned char *inend;
513 register guint32 saved;
517 inend = inbuf + inlen;
521 npad = (*state >> 8) & 0xff;
525 /* convert 4 base64 bytes to 3 normal bytes */
526 while (inptr < inend) {
527 c = gmime_base64_rank[*inptr++];
529 saved = (saved << 6) | c;
532 *outptr++ = saved >> 16;
533 *outptr++ = saved >> 8;
545 /* quickly scan back for '=' on the end somewhere */
546 /* fortunately we can drop 1 output char for each trailing '=' (up to 2) */
547 for (i = 2; inptr > inbuf && i; ) {
549 if (gmime_base64_rank[*inptr] != 0xff) {
550 if (*inptr == '=' && outptr > outbuf) {
552 /* we've got a complete quartet so it's
553 safe to drop an output character. */
555 } else if (npad < 2) {
556 /* keep a record of the number of ='s at
557 the end of the input stream, up to 2 */
566 *state = (npad << 8) | n;
567 *save = n ? saved : 0;
569 return (outptr - outbuf);
574 * g_mime_encoding_uuencode_close:
575 * @inbuf: input buffer
576 * @inlen: input buffer length
577 * @outbuf: output buffer
578 * @uubuf: temporary buffer of 60 bytes
579 * @state: holds the number of bits that are stored in @save
580 * @save: leftover bits that have not yet been encoded
582 * Uuencodes a chunk of data. Call this when finished encoding data
583 * with g_mime_encoding_uuencode_step() to flush off the last little bit.
585 * Returns: the number of bytes encoded.
588 g_mime_encoding_uuencode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, unsigned char *uubuf, int *state, guint32 *save)
590 register unsigned char *outptr, *bufptr;
591 register guint32 saved;
592 int uulen, uufill, i;
597 outptr += g_mime_encoding_uuencode_step (inbuf, inlen, outbuf, uubuf, state, save);
603 uulen = (*state >> 8) & 0xff;
605 bufptr = uubuf + ((uulen / 3) * 4);
615 /* convert 3 normal bytes into 4 uuencoded bytes */
616 unsigned char b0, b1, b2;
618 b0 = (saved >> 16) & 0xff;
619 b1 = (saved >> 8) & 0xff;
622 *bufptr++ = GMIME_UUENCODE_CHAR ((b0 >> 2) & 0x3f);
623 *bufptr++ = GMIME_UUENCODE_CHAR (((b0 << 4) | ((b1 >> 4) & 0xf)) & 0x3f);
624 *bufptr++ = GMIME_UUENCODE_CHAR (((b1 << 2) | ((b2 >> 6) & 0x3)) & 0x3f);
625 *bufptr++ = GMIME_UUENCODE_CHAR (b2 & 0x3f);
634 int cplen = ((uulen / 3) * 4);
636 *outptr++ = GMIME_UUENCODE_CHAR ((uulen - uufill) & 0xff);
637 memcpy (outptr, uubuf, cplen);
643 *outptr++ = GMIME_UUENCODE_CHAR (uulen & 0xff);
649 return (outptr - outbuf);
654 * g_mime_encoding_uuencode_step:
655 * @inbuf: input buffer
656 * @inlen: input buffer length
657 * @outbuf: output stream
658 * @uubuf: temporary buffer of 60 bytes
659 * @state: holds the number of bits that are stored in @save
660 * @save: leftover bits that have not yet been encoded
662 * Uuencodes a chunk of data. Performs an 'encode step', only encodes
663 * blocks of 45 characters to the output at a time, saves left-over
664 * state in @uubuf, @state and @save (initialize to 0 on first
667 * Returns: the number of bytes encoded.
670 g_mime_encoding_uuencode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, unsigned char *uubuf, int *state, guint32 *save)
672 register unsigned char *outptr, *bufptr;
673 const register unsigned char *inptr;
674 const unsigned char *inend;
675 unsigned char b0, b1, b2;
682 inend = inbuf + inlen;
688 uulen = (*state >> 8) & 0xff;
690 if ((inlen + uulen) < 45) {
691 /* not enough input to write a full uuencoded line */
692 bufptr = uubuf + ((uulen / 3) * 4);
697 /* copy the previous call's tmpbuf to outbuf */
698 memcpy (bufptr, uubuf, ((uulen / 3) * 4));
699 bufptr += ((uulen / 3) * 4);
704 b0 = (saved >> 8) & 0xff;
711 if ((inptr + 2) < inend) {
719 while (inptr < inend) {
720 saved = (saved << 8) | *inptr++;
725 while (inptr < inend) {
726 while (uulen < 45 && (inptr + 3) <= inend) {
733 /* convert 3 normal bytes into 4 uuencoded bytes */
734 *bufptr++ = GMIME_UUENCODE_CHAR ((b0 >> 2) & 0x3f);
735 *bufptr++ = GMIME_UUENCODE_CHAR (((b0 << 4) | ((b1 >> 4) & 0xf)) & 0x3f);
736 *bufptr++ = GMIME_UUENCODE_CHAR (((b1 << 2) | ((b2 >> 6) & 0x3)) & 0x3f);
737 *bufptr++ = GMIME_UUENCODE_CHAR (b2 & 0x3f);
743 /* output the uu line length */
744 *outptr = GMIME_UUENCODE_CHAR (uulen & 0xff);
745 outptr += ((45 / 3) * 4) + 1;
750 if ((inptr + 45) <= inend) {
751 /* we have enough input to output another full line */
757 /* not enough input to continue... */
758 for (i = 0, saved = 0; inptr < inend; i++)
759 saved = (saved << 8) | *inptr++;
764 *state = ((uulen & 0xff) << 8) | (i & 0xff);
766 return (outptr - outbuf);
771 * g_mime_encoding_uudecode_step:
772 * @inbuf: input buffer
773 * @inlen: input buffer length
774 * @outbuf: output buffer
775 * @state: holds the number of bits that are stored in @save
776 * @save: leftover bits that have not yet been decoded
778 * Uudecodes a chunk of data. Performs a 'decode step' on a chunk of
779 * uuencoded data. Assumes the "begin mode filename" line has
782 * Returns: the number of bytes decoded.
785 g_mime_encoding_uudecode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
787 const register unsigned char *inptr;
788 register unsigned char *outptr;
789 const unsigned char *inend;
791 register guint32 saved;
792 gboolean last_was_eoln;
795 if (*state & GMIME_UUDECODE_STATE_END)
800 uulen = (*state >> 8) & 0xff;
802 last_was_eoln = TRUE;
804 last_was_eoln = FALSE;
806 inend = inbuf + inlen;
810 while (inptr < inend) {
811 if (*inptr == '\n') {
812 last_was_eoln = TRUE;
816 } else if (!uulen || last_was_eoln) {
817 /* first octet on a line is the uulen octet */
818 uulen = gmime_uu_rank[*inptr];
819 last_was_eoln = FALSE;
821 *state |= GMIME_UUDECODE_STATE_END;
833 saved = (saved << 8) | ch;
836 /* convert 4 uuencoded bytes to 3 normal bytes */
837 unsigned char b0, b1, b2, b3;
840 b1 = saved >> 16 & 0xff;
841 b2 = saved >> 8 & 0xff;
845 *outptr++ = gmime_uu_rank[b0] << 2 | gmime_uu_rank[b1] >> 4;
846 *outptr++ = gmime_uu_rank[b1] << 4 | gmime_uu_rank[b2] >> 2;
847 *outptr++ = gmime_uu_rank[b2] << 6 | gmime_uu_rank[b3];
851 *outptr++ = gmime_uu_rank[b0] << 2 | gmime_uu_rank[b1] >> 4;
856 *outptr++ = gmime_uu_rank[b1] << 4 | gmime_uu_rank[b2] >> 2;
870 *state = (*state & GMIME_UUDECODE_STATE_MASK) | ((uulen & 0xff) << 8) | (i & 0xff);
872 return (outptr - outbuf);
877 * g_mime_encoding_quoted_encode_close:
878 * @inbuf: input buffer
879 * @inlen: input buffer length
880 * @outbuf: output buffer
881 * @state: holds the number of bits that are stored in @save
882 * @save: leftover bits that have not yet been encoded
884 * Quoted-printable encodes a block of text. Call this when finished
885 * encoding data with g_mime_encoding_quoted_encode_step() to flush off
886 * the last little bit.
888 * Returns: the number of bytes encoded.
891 g_mime_encoding_quoted_encode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
893 register unsigned char *outptr = outbuf;
897 outptr += g_mime_encoding_quoted_encode_step (inbuf, inlen, outptr, state, save);
901 /* space/tab must be encoded if its the last character on
903 if (is_qpsafe (last) && !is_blank (last)) {
907 *outptr++ = tohex[(last >> 4) & 0xf];
908 *outptr++ = tohex[last & 0xf];
913 /* we end with =\n so that the \n isn't interpreted as a real
914 \n when it gets decoded later */
922 return (outptr - outbuf);
927 * g_mime_encoding_quoted_encode_step:
928 * @inbuf: input buffer
929 * @inlen: input buffer length
930 * @outbuf: output buffer
931 * @state: holds the number of bits that are stored in @save
932 * @save: leftover bits that have not yet been encoded
934 * Quoted-printable encodes a block of text. Performs an 'encode
935 * step', saves left-over state in state and save (initialise to -1 on
938 * Returns: the number of bytes encoded.
941 g_mime_encoding_quoted_encode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
943 const register unsigned char *inptr = inbuf;
944 const unsigned char *inend = inbuf + inlen;
945 register unsigned char *outptr = outbuf;
946 register guint32 sofar = *save; /* keeps track of how many chars on a line */
947 register int last = *state; /* keeps track if last char to end was a space cr etc */
950 while (inptr < inend) {
955 *outptr++ = tohex[(last >> 4) & 0xf];
956 *outptr++ = tohex[last & 0xf];
960 } else if (c == '\n') {
961 if (last != -1 && last != '\r') {
963 *outptr++ = tohex[(last >> 4) & 0xf];
964 *outptr++ = tohex[last & 0xf];
971 if (is_qpsafe (last)) {
976 *outptr++ = tohex[(last >> 4) & 0xf];
977 *outptr++ = tohex[last & 0xf];
989 /* delay output of space char */
1006 *outptr++ = tohex[(c >> 4) & 0xf];
1007 *outptr++ = tohex[c & 0xf];
1016 return (outptr - outbuf);
1021 * g_mime_encoding_quoted_decode_step:
1022 * @inbuf: input buffer
1023 * @inlen: input buffer length
1024 * @outbuf: output buffer
1025 * @state: holds the number of bits that are stored in @save
1026 * @save: leftover bits that have not yet been decoded
1028 * Decodes a block of quoted-printable encoded data. Performs a
1029 * 'decode step' on a chunk of QP encoded data.
1031 * Returns: the number of bytes decoded.
1034 g_mime_encoding_quoted_decode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf, int *state, guint32 *save)
1036 /* FIXME: this does not strip trailing spaces from lines (as
1037 * it should, rfc 2045, section 6.7) Should it also
1038 * canonicalise the end of line to CR LF??
1040 * Note: Trailing rubbish (at the end of input), like = or =x
1041 * or =\r will be lost.
1043 const register unsigned char *inptr = inbuf;
1044 const unsigned char *inend = inbuf + inlen;
1045 register unsigned char *outptr = outbuf;
1046 guint32 isave = *save;
1047 int istate = *state;
1050 d(printf ("quoted-printable, decoding text '%.*s'\n", inlen, inbuf));
1052 while (inptr < inend) {
1055 while (inptr < inend) {
1057 /* FIXME: use a specials table to avoid 3 comparisons for the common case */
1062 #ifdef CANONICALISE_EOL
1063 /*else if (c=='\r') {
1065 } else if (c=='\n') {
1078 /* soft break ... unix end of line */
1087 if (isxdigit (c) && isxdigit (isave)) {
1088 c = toupper ((int) c);
1089 isave = toupper ((int) isave);
1090 *outptr++ = (((isave >= 'A' ? isave - 'A' + 10 : isave - '0') & 0x0f) << 4)
1091 | ((c >= 'A' ? c - 'A' + 10 : c - '0') & 0x0f);
1092 } else if (c == '\n' && isave == '\r') {
1093 /* soft break ... canonical end of line */
1095 /* just output the data */
1102 #ifdef CANONICALISE_EOL
1104 /* convert \n -> to \r\n, leaves \r\n alone */
1123 return (outptr - outbuf);