1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
3 * Copyright (C) 2000-2012 Jeffrey Stedfast
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
28 #include "gmime-filter-yenc.h"
32 * SECTION: gmime-filter-yenc
33 * @title: GMimeFilterYenc
34 * @short_description: yEncode or yDecode
35 * @see_also: #GMimeFilter
37 * A #GMimeFilter used to encode or decode the Usenet yEncoding.
41 static void g_mime_filter_yenc_class_init (GMimeFilterYencClass *klass);
42 static void g_mime_filter_yenc_init (GMimeFilterYenc *filter, GMimeFilterYencClass *klass);
43 static void g_mime_filter_yenc_finalize (GObject *object);
45 static GMimeFilter *filter_copy (GMimeFilter *filter);
46 static void filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace,
47 char **out, size_t *outlen, size_t *outprespace);
48 static void filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace,
49 char **out, size_t *outlen, size_t *outprespace);
50 static void filter_reset (GMimeFilter *filter);
53 static GMimeFilterClass *parent_class = NULL;
57 g_mime_filter_yenc_get_type (void)
59 static GType type = 0;
62 static const GTypeInfo info = {
63 sizeof (GMimeFilterYencClass),
64 NULL, /* base_class_init */
65 NULL, /* base_class_finalize */
66 (GClassInitFunc) g_mime_filter_yenc_class_init,
67 NULL, /* class_finalize */
68 NULL, /* class_data */
69 sizeof (GMimeFilterYenc),
71 (GInstanceInitFunc) g_mime_filter_yenc_init,
74 type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterYenc", &info, 0);
82 g_mime_filter_yenc_class_init (GMimeFilterYencClass *klass)
84 GObjectClass *object_class = G_OBJECT_CLASS (klass);
85 GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass);
87 parent_class = g_type_class_ref (GMIME_TYPE_FILTER);
89 object_class->finalize = g_mime_filter_yenc_finalize;
91 filter_class->copy = filter_copy;
92 filter_class->filter = filter_filter;
93 filter_class->complete = filter_complete;
94 filter_class->reset = filter_reset;
98 g_mime_filter_yenc_init (GMimeFilterYenc *filter, GMimeFilterYencClass *klass)
101 filter->pcrc = GMIME_YENCODE_CRC_INIT;
102 filter->crc = GMIME_YENCODE_CRC_INIT;
106 g_mime_filter_yenc_finalize (GObject *object)
108 G_OBJECT_CLASS (parent_class)->finalize (object);
113 filter_copy (GMimeFilter *filter)
115 GMimeFilterYenc *yenc = (GMimeFilterYenc *) filter;
117 return g_mime_filter_yenc_new (yenc->encode);
120 /* here we do all of the basic yEnc filtering */
122 filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace,
123 char **out, size_t *outlen, size_t *outprespace)
125 GMimeFilterYenc *yenc = (GMimeFilterYenc *) filter;
126 const unsigned char *inbuf;
127 unsigned char *outbuf;
131 /* won't go to more than 2 * (x + 2) + 62 */
132 g_mime_filter_set_size (filter, (len + 2) * 2 + 62, FALSE);
133 outbuf = (unsigned char *) filter->outbuf;
134 inbuf = (const unsigned char *) in;
135 newlen = g_mime_yencode_step (inbuf, len, outbuf, ¥c->state,
136 ¥c->pcrc, ¥c->crc);
137 g_assert (newlen <= (len + 2) * 2 + 62);
139 if (!(yenc->state & GMIME_YDECODE_STATE_DECODE)) {
140 register char *inptr, *inend;
146 /* we cannot start decoding until we have found an =ybegin line */
147 if (!(yenc->state & GMIME_YDECODE_STATE_BEGIN)) {
148 while (inptr < inend) {
149 left = inend - inptr;
151 if (!strncmp (inptr, "=ybegin ", left))
152 g_mime_filter_backup (filter, inptr, left);
154 } else if (!strncmp (inptr, "=ybegin ", 8)) {
155 for (in = inptr; inptr < inend && *inptr != '\n'; inptr++);
158 yenc->state |= GMIME_YDECODE_STATE_BEGIN;
159 /* we can start ydecoding if the next line isn't
164 /* we don't have enough... */
165 g_mime_filter_backup (filter, in, left);
170 /* go to the next line */
171 while (inptr < inend && *inptr != '\n')
179 left = inend - inptr;
180 if ((yenc->state & GMIME_YDECODE_STATE_BEGIN) && left > 0) {
181 /* we have found an '=ybegin' line but we may yet have an "=ypart" line to
182 yield before decoding the content */
183 if (left < 7 && !strncmp (inptr, "=ypart ", left)) {
184 g_mime_filter_backup (filter, inptr, left);
185 } else if (!strncmp (inptr, "=ypart ", 7)) {
186 for (in = inptr; inptr < inend && *inptr != '\n'; inptr++);
189 yenc->state |= GMIME_YDECODE_STATE_PART | GMIME_YDECODE_STATE_DECODE;
193 g_mime_filter_backup (filter, in, left);
196 /* guess it doesn't have a =ypart line */
197 yenc->state |= GMIME_YDECODE_STATE_DECODE;
202 if ((yenc->state & GMIME_YDECODE_STATE_DECODE) && !(yenc->state & GMIME_YDECODE_STATE_END)) {
203 /* all yEnc headers have been found so we can now start decoding */
204 g_mime_filter_set_size (filter, len + 3, FALSE);
205 outbuf = (unsigned char *) filter->outbuf;
206 inbuf = (const unsigned char *) in;
207 newlen = g_mime_ydecode_step (inbuf, len, outbuf, ¥c->state,
208 ¥c->pcrc, ¥c->crc);
209 g_assert (newlen <= len + 3);
215 *outprespace = filter->outpre;
216 *out = filter->outbuf;
221 filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace,
222 char **out, size_t *outlen, size_t *outprespace)
224 GMimeFilterYenc *yenc = (GMimeFilterYenc *) filter;
225 const unsigned char *inbuf;
226 unsigned char *outbuf;
230 /* won't go to more than 2 * (x + 2) + 62 */
231 g_mime_filter_set_size (filter, (len + 2) * 2 + 62, FALSE);
232 outbuf = (unsigned char *) filter->outbuf;
233 inbuf = (const unsigned char *) in;
234 newlen = g_mime_yencode_close (inbuf, len, outbuf, ¥c->state,
235 ¥c->pcrc, ¥c->crc);
236 g_assert (newlen <= (len + 2) * 2 + 62);
238 if ((yenc->state & GMIME_YDECODE_STATE_DECODE) && !(yenc->state & GMIME_YDECODE_STATE_END)) {
239 /* all yEnc headers have been found so we can now start decoding */
240 g_mime_filter_set_size (filter, len + 3, FALSE);
241 outbuf = (unsigned char *) filter->outbuf;
242 inbuf = (const unsigned char *) in;
243 newlen = g_mime_ydecode_step (inbuf, len, outbuf, ¥c->state,
244 ¥c->pcrc, ¥c->crc);
245 g_assert (newlen <= len + 3);
251 *outprespace = filter->outpre;
252 *out = filter->outbuf;
256 /* should this 'flush' outstanding state/data bytes? */
258 filter_reset (GMimeFilter *filter)
260 GMimeFilterYenc *yenc = (GMimeFilterYenc *) filter;
263 yenc->state = GMIME_YENCODE_STATE_INIT;
265 yenc->state = GMIME_YDECODE_STATE_INIT;
267 yenc->pcrc = GMIME_YENCODE_CRC_INIT;
268 yenc->crc = GMIME_YENCODE_CRC_INIT;
273 * g_mime_filter_yenc_new:
274 * @encode: encode vs decode
276 * Creates a new yEnc filter.
278 * Returns: a new yEnc filter.
281 g_mime_filter_yenc_new (gboolean encode)
283 GMimeFilterYenc *new;
285 new = g_object_newv (GMIME_TYPE_FILTER_YENC, 0, NULL);
286 new->encode = encode;
289 new->state = GMIME_YENCODE_STATE_INIT;
291 new->state = GMIME_YDECODE_STATE_INIT;
293 return (GMimeFilter *) new;
298 * g_mime_filter_yenc_set_state:
300 * @state: encode/decode state
302 * Sets the current state of the yencoder/ydecoder
305 g_mime_filter_yenc_set_state (GMimeFilterYenc *yenc, int state)
307 g_return_if_fail (GMIME_IS_FILTER_YENC (yenc));
314 * g_mime_filter_yenc_set_crc:
318 * Sets the current crc32 value on the yEnc filter @yenc to @crc.
321 g_mime_filter_yenc_set_crc (GMimeFilterYenc *yenc, guint32 crc)
323 g_return_if_fail (GMIME_IS_FILTER_YENC (yenc));
330 /* FIXME: once we parse out the yenc part id, we can re-enable this interface */
332 * g_mime_filter_yenc_get_part:
335 * Gets the part id of the current decoded yEnc stream or %-1 on fail.
337 * Returns: the part id of the current decoded yEnc stream or %-1 on
341 g_mime_filter_yenc_get_part (GMimeFilterYenc *yenc)
343 g_return_val_if_fail (GMIME_IS_FILTER_YENC (yenc), -1);
345 if (yenc->state & GMIME_YDECODE_STATE_PART)
353 * g_mime_filter_yenc_get_pcrc:
356 * Get the computed part crc or (guint32) -1 on fail.
358 * Returns: the computed part crc or (guint32) -1 on fail.
361 g_mime_filter_yenc_get_pcrc (GMimeFilterYenc *yenc)
363 g_return_val_if_fail (GMIME_IS_FILTER_YENC (yenc), -1);
365 return GMIME_YENCODE_CRC_FINAL (yenc->pcrc);
370 * g_mime_filter_yenc_get_crc:
373 * Get the computed crc or (guint32) -1 on fail.
375 * Returns: the computed crc or (guint32) -1 on fail.
378 g_mime_filter_yenc_get_crc (GMimeFilterYenc *yenc)
380 g_return_val_if_fail (GMIME_IS_FILTER_YENC (yenc), -1);
382 return GMIME_YENCODE_CRC_FINAL (yenc->crc);
386 static const int yenc_crc_table[256] = {
387 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
388 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
389 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
390 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
391 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
392 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
393 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
394 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
395 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
396 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
397 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
398 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
399 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
400 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
401 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
402 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
403 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
404 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
405 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
406 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
407 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
408 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
409 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
410 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
411 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
412 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
413 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
414 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
415 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
416 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
417 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
418 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
421 #define yenc_crc_add(crc, c) (yenc_crc_table[(((int) (crc)) ^ ((unsigned char) (c))) & 0xff] ^ ((((int) (crc)) >> 8) & 0x00ffffff))
423 #define YENC_NEWLINE_ESCAPE (GMIME_YDECODE_STATE_EOLN | GMIME_YDECODE_STATE_ESCAPE)
427 * g_mime_ydecode_step:
428 * @inbuf: input buffer
429 * @inlen: input buffer length
430 * @outbuf: output buffer
431 * @state: ydecode state
432 * @pcrc: part crc state
435 * Performs a 'decode step' on a chunk of yEncoded data of length
436 * @inlen pointed to by @inbuf and writes to @outbuf. Assumes the =ybegin
437 * and =ypart lines have already been stripped off.
439 * To get the crc32 value of the part, use #GMIME_YENCODE_CRC_FINAL
440 * (@pcrc). If there are more parts, you should reuse @crc without
441 * re-initializing. Once all parts have been decoded, you may get the
442 * combined crc32 value of all the parts using #GMIME_YENCODE_CRC_FINAL
445 * Returns: the number of bytes decoded.
448 g_mime_ydecode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf,
449 int *state, guint32 *pcrc, guint32 *crc)
451 const register unsigned char *inptr;
452 register unsigned char *outptr;
453 const unsigned char *inend;
457 if (*state & GMIME_YDECODE_STATE_END)
462 inend = inbuf + inlen;
466 while (inptr < inend) {
469 if ((ystate & YENC_NEWLINE_ESCAPE) == YENC_NEWLINE_ESCAPE) {
470 ystate &= ~GMIME_YDECODE_STATE_EOLN;
473 /* we probably have a =yend here */
474 ystate |= GMIME_YDECODE_STATE_END;
480 ystate |= GMIME_YDECODE_STATE_EOLN;
484 if (ystate & GMIME_YDECODE_STATE_ESCAPE) {
485 ystate &= ~GMIME_YDECODE_STATE_ESCAPE;
487 } else if (c == '=') {
488 ystate |= GMIME_YDECODE_STATE_ESCAPE;
492 ystate &= ~GMIME_YDECODE_STATE_EOLN;
496 *pcrc = yenc_crc_add (*pcrc, c);
497 *crc = yenc_crc_add (*crc, c);
502 return outptr - outbuf;
507 * g_mime_yencode_step:
508 * @inbuf: input buffer
509 * @inlen: input buffer length
510 * @outbuf: output buffer
511 * @state: yencode state
512 * @pcrc: part crc state
515 * Performs an yEncode 'encode step' on a chunk of raw data of length
516 * @inlen pointed to by @inbuf and writes to @outbuf.
518 * @state should be initialized to #GMIME_YENCODE_STATE_INIT before
519 * beginning making the first call to this function. Subsequent calls
520 * should reuse @state.
522 * Along the same lines, @pcrc and @crc should be initialized to
523 * #GMIME_YENCODE_CRC_INIT before using.
525 * Returns: the number of bytes encoded.
528 g_mime_yencode_step (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf,
529 int *state, guint32 *pcrc, guint32 *crc)
531 const register unsigned char *inptr;
532 register unsigned char *outptr;
533 const unsigned char *inend;
534 register int already;
537 inend = inbuf + inlen;
543 while (inptr < inend) {
546 *pcrc = yenc_crc_add (*pcrc, c);
547 *crc = yenc_crc_add (*crc, c);
551 if (c == '\0' || c == '\t' || c == '\r' || c == '\n' || c == '=') {
560 if (already >= 128) {
568 return outptr - outbuf;
573 * g_mime_yencode_close:
574 * @inbuf: input buffer
575 * @inlen: input buffer length
576 * @outbuf: output buffer
577 * @state: yencode state
578 * @pcrc: part crc state
581 * Call this function when finished encoding data with
582 * g_mime_yencode_step() to flush off the remaining state.
584 * #GMIME_YENCODE_CRC_FINAL (@pcrc) will give you the crc32 of the
585 * encoded "part". If there are more "parts" to encode, you should
586 * re-use @crc when encoding the next "parts" and then use
587 * #GMIME_YENCODE_CRC_FINAL (@crc) to get the combined crc32 value of
590 * Returns: the number of bytes encoded.
593 g_mime_yencode_close (const unsigned char *inbuf, size_t inlen, unsigned char *outbuf,
594 int *state, guint32 *pcrc, guint32 *crc)
596 register unsigned char *outptr = outbuf;
599 outptr += g_mime_yencode_step (inbuf, inlen, outbuf, state, pcrc, crc);
604 *state = GMIME_YENCODE_STATE_INIT;
606 return outptr - outbuf;