1 /* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /* GMime
3 * Copyright (C) 2000-2009 Jeffrey Stedfast
4 *
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.
9 *
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.
14 *
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
18 * 02110-1301, USA.
19 */
20
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <string.h>
27
28 #include "gmime-filter-yenc.h"
29
30
31 /**
32 * SECTION: gmime-filter-yenc
33 * @title: GMimeFilterYenc
34 * @short_description: yEncode or yDecode
35 * @see_also: #GMimeFilter
36 *
37 * A #GMimeFilter used to encode or decode the Usenet yEncoding.
38 **/
39
40
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);
44
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);
51
52
53 static GMimeFilterClass *parent_class = NULL;
54
55
56 GType
g_mime_filter_yenc_get_type(void)57 g_mime_filter_yenc_get_type (void)
58 {
59 static GType type = 0;
60
61 if (!type) {
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),
70 0, /* n_preallocs */
71 (GInstanceInitFunc) g_mime_filter_yenc_init,
72 };
73
74 type = g_type_register_static (GMIME_TYPE_FILTER, "GMimeFilterYenc", &info, 0);
75 }
76
77 return type;
78 }
79
80
81 static void
g_mime_filter_yenc_class_init(GMimeFilterYencClass * klass)82 g_mime_filter_yenc_class_init (GMimeFilterYencClass *klass)
83 {
84 GObjectClass *object_class = G_OBJECT_CLASS (klass);
85 GMimeFilterClass *filter_class = GMIME_FILTER_CLASS (klass);
86
87 parent_class = g_type_class_ref (GMIME_TYPE_FILTER);
88
89 object_class->finalize = g_mime_filter_yenc_finalize;
90
91 filter_class->copy = filter_copy;
92 filter_class->filter = filter_filter;
93 filter_class->complete = filter_complete;
94 filter_class->reset = filter_reset;
95 }
96
97 static void
g_mime_filter_yenc_init(GMimeFilterYenc * filter,GMimeFilterYencClass * klass)98 g_mime_filter_yenc_init (GMimeFilterYenc *filter, GMimeFilterYencClass *klass)
99 {
100 filter->part = 0;
101 filter->pcrc = GMIME_YENCODE_CRC_INIT;
102 filter->crc = GMIME_YENCODE_CRC_INIT;
103 }
104
105 static void
g_mime_filter_yenc_finalize(GObject * object)106 g_mime_filter_yenc_finalize (GObject *object)
107 {
108 G_OBJECT_CLASS (parent_class)->finalize (object);
109 }
110
111
112 static GMimeFilter *
filter_copy(GMimeFilter * filter)113 filter_copy (GMimeFilter *filter)
114 {
115 GMimeFilterYenc *yenc = (GMimeFilterYenc *) filter;
116
117 return g_mime_filter_yenc_new (yenc->direction);
118 }
119
120 /* here we do all of the basic yEnc filtering */
121 static void
filter_filter(GMimeFilter * filter,char * in,size_t len,size_t prespace,char ** out,size_t * outlen,size_t * outprespace)122 filter_filter (GMimeFilter *filter, char *in, size_t len, size_t prespace,
123 char **out, size_t *outlen, size_t *outprespace)
124 {
125 GMimeFilterYenc *yenc = (GMimeFilterYenc *) filter;
126 const unsigned char *inbuf;
127 unsigned char *outbuf;
128 size_t newlen = 0;
129
130 switch (yenc->direction) {
131 case GMIME_FILTER_YENC_DIRECTION_ENCODE:
132 /* won't go to more than 2 * (x + 2) + 62 */
133 g_mime_filter_set_size (filter, (len + 2) * 2 + 62, FALSE);
134 outbuf = (unsigned char *) filter->outbuf;
135 inbuf = (const unsigned char *) in;
136 newlen = g_mime_yencode_step (inbuf, len, outbuf, ¥c->state,
137 ¥c->pcrc, ¥c->crc);
138 g_assert (newlen <= (len + 2) * 2 + 62);
139 break;
140 case GMIME_FILTER_YENC_DIRECTION_DECODE:
141 if (!(yenc->state & GMIME_YDECODE_STATE_DECODE)) {
142 register char *inptr, *inend;
143 size_t left;
144
145 inptr = in;
146 inend = inptr + len;
147
148 /* we cannot start decoding until we have found an =ybegin line */
149 if (!(yenc->state & GMIME_YDECODE_STATE_BEGIN)) {
150 while (inptr < inend) {
151 left = inend - inptr;
152 if (left < 8) {
153 if (!strncmp (inptr, "=ybegin ", left))
154 g_mime_filter_backup (filter, inptr, left);
155 break;
156 } else if (!strncmp (inptr, "=ybegin ", 8)) {
157 for (in = inptr; inptr < inend && *inptr != '\n'; inptr++);
158 if (inptr < inend) {
159 inptr++;
160 yenc->state |= GMIME_YDECODE_STATE_BEGIN;
161 /* we can start ydecoding if the next line isn't
162 a ypart... */
163 in = inptr;
164 len = inend - in;
165 } else {
166 /* we don't have enough... */
167 g_mime_filter_backup (filter, in, left);
168 }
169 break;
170 }
171
172 /* go to the next line */
173 while (inptr < inend && *inptr != '\n')
174 inptr++;
175
176 if (inptr < inend)
177 inptr++;
178 }
179 }
180
181 left = inend - inptr;
182 if ((yenc->state & GMIME_YDECODE_STATE_BEGIN) && left > 0) {
183 /* we have found an '=ybegin' line but we may yet have an "=ypart" line to
184 yield before decoding the content */
185 if (left < 7 && !strncmp (inptr, "=ypart ", left)) {
186 g_mime_filter_backup (filter, inptr, left);
187 } else if (!strncmp (inptr, "=ypart ", 7)) {
188 for (in = inptr; inptr < inend && *inptr != '\n'; inptr++);
189 if (inptr < inend) {
190 inptr++;
191 yenc->state |= GMIME_YDECODE_STATE_PART | GMIME_YDECODE_STATE_DECODE;
192 in = inptr;
193 len = inend - in;
194 } else {
195 g_mime_filter_backup (filter, in, left);
196 }
197 } else {
198 /* guess it doesn't have a =ypart line */
199 yenc->state |= GMIME_YDECODE_STATE_DECODE;
200 }
201 }
202 }
203
204 if ((yenc->state & GMIME_YDECODE_STATE_DECODE) && !(yenc->state & GMIME_YDECODE_STATE_END)) {
205 /* all yEnc headers have been found so we can now start decoding */
206 g_mime_filter_set_size (filter, len + 3, FALSE);
207 outbuf = (unsigned char *) filter->outbuf;
208 inbuf = (const unsigned char *) in;
209 newlen = g_mime_ydecode_step (inbuf, len, outbuf, ¥c->state,
210 ¥c->pcrc, ¥c->crc);
211 g_assert (newlen <= len + 3);
212 } else {
213 newlen = 0;
214 }
215 break;
216 }
217
218 *out = filter->outbuf;
219 *outlen = newlen;
220 *outprespace = filter->outpre;
221 }
222
223 static void
filter_complete(GMimeFilter * filter,char * in,size_t len,size_t prespace,char ** out,size_t * outlen,size_t * outprespace)224 filter_complete (GMimeFilter *filter, char *in, size_t len, size_t prespace,
225 char **out, size_t *outlen, size_t *outprespace)
226 {
227 GMimeFilterYenc *yenc = (GMimeFilterYenc *) filter;
228 const unsigned char *inbuf;
229 unsigned char *outbuf;
230 size_t newlen = 0;
231
232 switch (yenc->direction) {
233 case GMIME_FILTER_YENC_DIRECTION_ENCODE:
234 /* won't go to more than 2 * (x + 2) + 62 */
235 g_mime_filter_set_size (filter, (len + 2) * 2 + 62, FALSE);
236 outbuf = (unsigned char *) filter->outbuf;
237 inbuf = (const unsigned char *) in;
238 newlen = g_mime_yencode_close (inbuf, len, outbuf, ¥c->state,
239 ¥c->pcrc, ¥c->crc);
240 g_assert (newlen <= (len + 2) * 2 + 62);
241 break;
242 case GMIME_FILTER_YENC_DIRECTION_DECODE:
243 if ((yenc->state & GMIME_YDECODE_STATE_DECODE) && !(yenc->state & GMIME_YDECODE_STATE_END)) {
244 /* all yEnc headers have been found so we can now start decoding */
245 g_mime_filter_set_size (filter, len + 3, FALSE);
246 outbuf = (unsigned char *) filter->outbuf;
247 inbuf = (const unsigned char *) in;
248 newlen = g_mime_ydecode_step (inbuf, len, outbuf, ¥c->state,
249 ¥c->pcrc, ¥c->crc);
250 g_assert (newlen <= len + 3);
251 } else {
252 newlen = 0;
253 }
254 break;
255 }
256
257 *out = filter->outbuf;
258 *outlen = newlen;
259 *outprespace = filter->outpre;
260 }
261
262 /* should this 'flush' outstanding state/data bytes? */
263 static void
filter_reset(GMimeFilter * filter)264 filter_reset (GMimeFilter *filter)
265 {
266 GMimeFilterYenc *yenc = (GMimeFilterYenc *) filter;
267
268 switch (yenc->direction) {
269 case GMIME_FILTER_YENC_DIRECTION_ENCODE:
270 yenc->state = GMIME_YENCODE_STATE_INIT;
271 break;
272 case GMIME_FILTER_YENC_DIRECTION_DECODE:
273 yenc->state = GMIME_YDECODE_STATE_INIT;
274 break;
275 }
276 yenc->pcrc = GMIME_YENCODE_CRC_INIT;
277 yenc->crc = GMIME_YENCODE_CRC_INIT;
278 }
279
280
281 /**
282 * g_mime_filter_yenc_new:
283 * @direction: encode direction
284 *
285 * Creates a new yEnc filter.
286 *
287 * Returns a new yEnc filter.
288 **/
289 GMimeFilter *
g_mime_filter_yenc_new(GMimeFilterYencDirection direction)290 g_mime_filter_yenc_new (GMimeFilterYencDirection direction)
291 {
292 GMimeFilterYenc *new;
293
294 new = g_object_new (GMIME_TYPE_FILTER_YENC, NULL);
295 new->direction = direction;
296
297 switch (direction) {
298 case GMIME_FILTER_YENC_DIRECTION_ENCODE:
299 new->state = GMIME_YENCODE_STATE_INIT;
300 break;
301 case GMIME_FILTER_YENC_DIRECTION_DECODE:
302 new->state = GMIME_YDECODE_STATE_INIT;
303 break;
304 default:
305 g_assert_not_reached ();
306 }
307
308 return (GMimeFilter *) new;
309 }
310
311
312 /**
313 * g_mime_filter_yenc_set_state:
314 * @yenc: yEnc filter
315 * @state: encode/decode state
316 *
317 * Sets the current state of the yencoder/ydecoder
318 **/
319 void
g_mime_filter_yenc_set_state(GMimeFilterYenc * yenc,int state)320 g_mime_filter_yenc_set_state (GMimeFilterYenc *yenc, int state)
321 {
322 g_return_if_fail (GMIME_IS_FILTER_YENC (yenc));
323
324 yenc->state = state;
325 }
326
327
328 /**
329 * g_mime_filter_yenc_set_crc:
330 * @yenc: yEnc filter
331 * @crc: crc32
332 *
333 * Sets the current crc32 value on the yEnc filter @yenc to @crc.
334 **/
335 void
g_mime_filter_yenc_set_crc(GMimeFilterYenc * yenc,guint32 crc)336 g_mime_filter_yenc_set_crc (GMimeFilterYenc *yenc, guint32 crc)
337 {
338 g_return_if_fail (GMIME_IS_FILTER_YENC (yenc));
339
340 yenc->crc = crc;
341 }
342
343
344 #if 0
345 /* FIXME: once we parse out the yenc part id, we can re-enable this interface */
346 /**
347 * g_mime_filter_yenc_get_part:
348 * @yenc: yEnc filter
349 *
350 * Gets the part id of the current decoded yEnc stream or %-1 on fail.
351 *
352 * Returns the part id of the current decoded yEnc stream or %-1 on
353 * fail.
354 **/
355 int
356 g_mime_filter_yenc_get_part (GMimeFilterYenc *yenc)
357 {
358 g_return_val_if_fail (GMIME_IS_FILTER_YENC (yenc), -1);
359
360 if (yenc->state & GMIME_YDECODE_STATE_PART)
361 return yenc->part;
362
363 return -1;
364 }
365 #endif
366
367 /**
368 * g_mime_filter_yenc_get_pcrc:
369 * @yenc: yEnc filter
370 *
371 * Get the computed part crc or (guint32) -1 on fail.
372 *
373 * Returns the computed part crc or (guint32) -1 on fail.
374 **/
375 guint32
g_mime_filter_yenc_get_pcrc(GMimeFilterYenc * yenc)376 g_mime_filter_yenc_get_pcrc (GMimeFilterYenc *yenc)
377 {
378 g_return_val_if_fail (GMIME_IS_FILTER_YENC (yenc), -1);
379
380 return GMIME_YENCODE_CRC_FINAL (yenc->pcrc);
381 }
382
383
384 /**
385 * g_mime_filter_yenc_get_crc:
386 * @yenc: yEnc filter
387 *
388 * Get the computed crc or (guint32) -1 on fail.
389 *
390 * Returns the computed crc or (guint32) -1 on fail.
391 **/
392 guint32
g_mime_filter_yenc_get_crc(GMimeFilterYenc * yenc)393 g_mime_filter_yenc_get_crc (GMimeFilterYenc *yenc)
394 {
395 g_return_val_if_fail (GMIME_IS_FILTER_YENC (yenc), -1);
396
397 return GMIME_YENCODE_CRC_FINAL (yenc->crc);
398 }
399
400
401 static const int yenc_crc_table[256] = {
402 0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3,
403 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91,
404 0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
405 0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5,
406 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b,
407 0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
408 0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f,
409 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d,
410 0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
411 0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01,
412 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457,
413 0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
414 0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb,
415 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9,
416 0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
417 0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad,
418 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683,
419 0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
420 0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7,
421 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5,
422 0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
423 0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79,
424 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f,
425 0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
426 0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713,
427 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21,
428 0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
429 0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45,
430 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db,
431 0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
432 0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf,
433 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
434 };
435
436 #define yenc_crc_add(crc, c) (yenc_crc_table[(((int) (crc)) ^ ((unsigned char) (c))) & 0xff] ^ ((((int) (crc)) >> 8) & 0x00ffffff))
437
438 #define YENC_NEWLINE_ESCAPE (GMIME_YDECODE_STATE_EOLN | GMIME_YDECODE_STATE_ESCAPE)
439
440
441 /**
442 * g_mime_ydecode_step:
443 * @in: input buffer
444 * @inlen: input buffer length
445 * @out: output buffer
446 * @state: ydecode state
447 * @pcrc: part crc state
448 * @crc: crc state
449 *
450 * Performs a 'decode step' on a chunk of yEncoded data of length
451 * @inlen pointed to by @in and writes to @out. Assumes the =ybegin
452 * and =ypart lines have already been stripped off.
453 *
454 * To get the crc32 value of the part, use #GMIME_YENCODE_CRC_FINAL
455 * (@pcrc). If there are more parts, you should reuse @crc without
456 * re-initializing. Once all parts have been decoded, you may get the
457 * combined crc32 value of all the parts using #GMIME_YENCODE_CRC_FINAL
458 * (@crc).
459 *
460 * Returns the number of bytes decoded.
461 **/
462 size_t
g_mime_ydecode_step(const unsigned char * in,size_t inlen,unsigned char * out,int * state,guint32 * pcrc,guint32 * crc)463 g_mime_ydecode_step (const unsigned char *in, size_t inlen, unsigned char *out,
464 int *state, guint32 *pcrc, guint32 *crc)
465 {
466 const register unsigned char *inptr;
467 register unsigned char *outptr;
468 const unsigned char *inend;
469 unsigned char c;
470 int ystate;
471
472 if (*state & GMIME_YDECODE_STATE_END)
473 return 0;
474
475 ystate = *state;
476
477 inend = in + inlen;
478 outptr = out;
479
480 inptr = in;
481 while (inptr < inend) {
482 c = *inptr++;
483
484 if ((ystate & YENC_NEWLINE_ESCAPE) == YENC_NEWLINE_ESCAPE) {
485 ystate &= ~GMIME_YDECODE_STATE_EOLN;
486
487 if (c == 'y') {
488 /* we probably have a =yend here */
489 ystate |= GMIME_YDECODE_STATE_END;
490 break;
491 }
492 }
493
494 if (c == '\n') {
495 ystate |= GMIME_YDECODE_STATE_EOLN;
496 continue;
497 }
498
499 if (ystate & GMIME_YDECODE_STATE_ESCAPE) {
500 ystate &= ~GMIME_YDECODE_STATE_ESCAPE;
501 c -= 64;
502 } else if (c == '=') {
503 ystate |= GMIME_YDECODE_STATE_ESCAPE;
504 continue;
505 }
506
507 ystate &= ~GMIME_YDECODE_STATE_EOLN;
508
509 *outptr++ = c -= 42;
510
511 *pcrc = yenc_crc_add (*pcrc, c);
512 *crc = yenc_crc_add (*crc, c);
513 }
514
515 *state = ystate;
516
517 return outptr - out;
518 }
519
520
521 /**
522 * g_mime_yencode_step:
523 * @in: input buffer
524 * @inlen: input buffer length
525 * @out: output buffer
526 * @state: yencode state
527 * @pcrc: part crc state
528 * @crc: crc state
529 *
530 * Performs an yEncode 'encode step' on a chunk of raw data of length
531 * @inlen pointed to by @in and writes to @out.
532 *
533 * @state should be initialized to GMIME_YENCODE_STATE_INIT before
534 * beginning making the first call to this function. Subsequent calls
535 * should reuse @state.
536 *
537 * Along the same lines, @pcrc and @crc should be initialized to
538 * #GMIME_YENCODE_CRC_INIT before using.
539 *
540 * Returns the number of bytes encoded.
541 **/
542 size_t
g_mime_yencode_step(const unsigned char * in,size_t inlen,unsigned char * out,int * state,guint32 * pcrc,guint32 * crc)543 g_mime_yencode_step (const unsigned char *in, size_t inlen, unsigned char *out,
544 int *state, guint32 *pcrc, guint32 *crc)
545 {
546 const register unsigned char *inptr;
547 register unsigned char *outptr;
548 const unsigned char *inend;
549 register int already;
550 unsigned char c;
551
552 inend = in + inlen;
553 outptr = out;
554
555 already = *state;
556
557 inptr = in;
558 while (inptr < inend) {
559 c = *inptr++;
560
561 *pcrc = yenc_crc_add (*pcrc, c);
562 *crc = yenc_crc_add (*crc, c);
563
564 c += 42;
565
566 if (c == '\0' || c == '\t' || c == '\r' || c == '\n' || c == '=') {
567 *outptr++ = '=';
568 *outptr++ = c + 64;
569 already += 2;
570 } else {
571 *outptr++ = c;
572 already++;
573 }
574
575 if (already >= 128) {
576 *outptr++ = '\n';
577 already = 0;
578 }
579 }
580
581 *state = already;
582
583 return outptr - out;
584 }
585
586
587 /**
588 * g_mime_yencode_close:
589 * @in: input buffer
590 * @inlen: input buffer length
591 * @out: output buffer
592 * @state: yencode state
593 * @pcrc: part crc state
594 * @crc: crc state
595 *
596 * Call this function when finished encoding data with
597 * g_mime_yencode_step to flush off the remaining state.
598 *
599 * GMIME_YENCODE_CRC_FINAL (@pcrc) will give you the crc32 of the
600 * encoded "part". If there are more "parts" to encode, you should
601 * re-use @crc when encoding the next "parts" and then use
602 * GMIME_YENCODE_CRC_FINAL (@crc) to get the combined crc32 value of
603 * all the parts.
604 *
605 * Returns the number of bytes encoded.
606 **/
607 size_t
g_mime_yencode_close(const unsigned char * in,size_t inlen,unsigned char * out,int * state,guint32 * pcrc,guint32 * crc)608 g_mime_yencode_close (const unsigned char *in, size_t inlen, unsigned char *out,
609 int *state, guint32 *pcrc, guint32 *crc)
610 {
611 register unsigned char *outptr;
612
613 outptr = out;
614
615 if (inlen)
616 outptr += g_mime_yencode_step (in, inlen, out, state, pcrc, crc);
617
618 if (*state)
619 *outptr++ = '\n';
620
621 *state = GMIME_YENCODE_STATE_INIT;
622
623 return outptr - out;
624 }
625