1 /*
2  * uucode.c --
3  *
4  *	Implements and registers conversion from and to uuencoded representation.
5  *
6  *
7  * Copyright (c) 1996 Andreas Kupries (andreas_kupries@users.sourceforge.net)
8  * All rights reserved.
9  *
10  * Permission is hereby granted, without written agreement and without
11  * license or royalty fees, to use, copy, modify, and distribute this
12  * software and its documentation for any purpose, provided that the
13  * above copyright notice and the following two paragraphs appear in
14  * all copies of this software.
15  *
16  * IN NO EVENT SHALL I LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
17  * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
18  * SOFTWARE AND ITS DOCUMENTATION, EVEN IF I HAVE BEEN ADVISED OF THE
19  * POSSIBILITY OF SUCH DAMAGE.
20  *
21  * I SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
22  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
24  * I HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
25  * ENHANCEMENTS, OR MODIFICATIONS.
26  *
27  * CVS: $Id: uucode.c,v 1.8 2009/05/07 04:57:27 andreas_kupries Exp $
28  */
29 
30 #include "transformInt.h"
31 
32 /*
33  * Converter description
34  * ---------------------
35  *
36  * Encoding:
37  *	Each sequence of 3 bytes is expanded into 4 printable characters
38  *	using the 4 6bit-sequences contained in the 3 bytes. The mapping
39  *	from 6bit value to printable characters is done with the UU map.
40  *	Special processing is done for incomplete byte sequences at the
41  *	end of the input (1,2 bytes).
42  *
43  * Decoding:
44  *	Each sequence of 4 characters is mapped into 4 6bit values using
45  *	the reverse UU map and then concatenated to form 3 8bit bytes.
46  *	Special processing is done for incomplete character sequences at
47  *	the end of the input (1,2,3 bytes).
48  */
49 
50 
51 /*
52  * Declarations of internal procedures.
53  */
54 
55 static Trf_ControlBlock CreateEncoder  _ANSI_ARGS_ ((ClientData writeClientData, Trf_WriteProc *fun,
56 						     Trf_Options optInfo, Tcl_Interp*   interp,
57 						     ClientData clientData));
58 static void             DeleteEncoder  _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
59 						     ClientData clientData));
60 static int              Encode         _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
61 						     unsigned int character,
62 						     Tcl_Interp* interp,
63 						     ClientData clientData));
64 static int              FlushEncoder   _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
65 						     Tcl_Interp* interp,
66 						     ClientData clientData));
67 static void             ClearEncoder   _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
68 						     ClientData clientData));
69 
70 
71 static Trf_ControlBlock CreateDecoder  _ANSI_ARGS_ ((ClientData writeClientData, Trf_WriteProc *fun,
72 						     Trf_Options optInfo, Tcl_Interp*   interp,
73 						     ClientData clientData));
74 static void             DeleteDecoder  _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
75 						     ClientData clientData));
76 static int              Decode         _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
77 						     unsigned int character,
78 						     Tcl_Interp* interp,
79 						     ClientData clientData));
80 static int              FlushDecoder   _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
81 						     Tcl_Interp* interp,
82 						     ClientData clientData));
83 static void             ClearDecoder   _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
84 						     ClientData clientData));
85 
86 
87 /*
88  * Converter definition.
89  */
90 
91 static Trf_TypeDefinition convDefinition =
92 {
93   "uuencode",
94   NULL, /* clientData not used by converters */
95   NULL, /* set later by Trf_InitUU, THREADING: serialize initialization */
96   {
97     CreateEncoder,
98     DeleteEncoder,
99     Encode,
100     NULL,
101     FlushEncoder,
102     ClearEncoder,
103     NULL /* no MaxRead */
104   }, {
105     CreateDecoder,
106     DeleteDecoder,
107     Decode,
108     NULL,
109     FlushDecoder,
110     ClearDecoder,
111     NULL /* no MaxRead */
112   },
113   TRF_RATIO (3, 4)
114 };
115 
116 /*
117  * Definition of the control blocks for en- and decoder.
118  */
119 
120 typedef struct _EncoderControl_ {
121   Trf_WriteProc* write;
122   ClientData     writeClientData;
123 
124   /* add conversion specific items here (uuencode) */
125 
126   unsigned char charCount;
127   unsigned char buf [3];
128 
129 } EncoderControl;
130 
131 
132 typedef struct _DecoderControl_ {
133   Trf_WriteProc* write;
134   ClientData     writeClientData;
135 
136   /* add conversion specific items here (uudecode) */
137 
138   unsigned char charCount;
139   unsigned char buf [4];
140   unsigned char expectFlush;
141 
142 } DecoderControl;
143 
144 
145 /*
146  * Character mapping for uuencode (bin -> ascii)
147  *
148  * Index this array by a 6-bit value to obtain the corresponding
149  * 8-bit character. The last character (index 64) is the pad char (~)
150  *                                                                                              |
151  *                                       1         2         3         4         5          6   6
152  *                            01 2345678901234567890123456789012345678901234567890123456789 01234 */
153 static CONST char* uuMap   = "`!\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_~";
154 /* uuMap: THREADING: constant, read-only => safe */
155 
156 #define PAD '~'
157 
158 /*
159  * Character mappings for uudecode (ascii -> bin)
160  *
161  * Index this array by a 8 bit value to get the 6-bit binary field
162  * corresponding to that value.  Any illegal characters have high bit set.
163  */
164 
165 #define Ccc (CONST char) /* Ccc = CONST char cast */
166 static CONST char uuMapReverse [] = { /* THREADING: constant, read-only => safe */
167   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
168   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
169   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
170   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
171   Ccc 0200, Ccc 0001, Ccc 0002, Ccc 0003, Ccc 0004, Ccc 0005, Ccc 0006, Ccc 0007,
172   Ccc 0010, Ccc 0011, Ccc 0012, Ccc 0013, Ccc 0014, Ccc 0015, Ccc 0016, Ccc 0017,
173   Ccc 0020, Ccc 0021, Ccc 0022, Ccc 0023, Ccc 0024, Ccc 0025, Ccc 0026, Ccc 0027,
174   Ccc 0030, Ccc 0031, Ccc 0032, Ccc 0033, Ccc 0034, Ccc 0035, Ccc 0036, Ccc 0037,
175   Ccc 0040, Ccc 0041, Ccc 0042, Ccc 0043, Ccc 0044, Ccc 0045, Ccc 0046, Ccc 0047,
176   Ccc 0050, Ccc 0051, Ccc 0052, Ccc 0053, Ccc 0054, Ccc 0055, Ccc 0056, Ccc 0057,
177   Ccc 0060, Ccc 0061, Ccc 0062, Ccc 0063, Ccc 0064, Ccc 0065, Ccc 0066, Ccc 0067,
178   Ccc 0070, Ccc 0071, Ccc 0072, Ccc 0073, Ccc 0074, Ccc 0075, Ccc 0076, Ccc 0077,
179   Ccc 0000, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
180   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
181   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
182   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
183   /* */
184   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
185   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
186   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
187   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
188   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
189   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
190   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
191   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
192   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
193   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
194   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
195   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
196   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
197   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
198   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200,
199   Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200, Ccc 0200
200 };
201 #undef Ccc
202 
203 
204 /*
205  *------------------------------------------------------*
206  *
207  *	TrfInit_UU --
208  *
209  *	------------------------------------------------*
210  *	Register the conversion implemented in this file.
211  *	------------------------------------------------*
212  *
213  *	Sideeffects:
214  *		As of 'Trf_Register'.
215  *
216  *	Result:
217  *		A standard Tcl error code.
218  *
219  *------------------------------------------------------*
220  */
221 
222 int
TrfInit_UU(interp)223 TrfInit_UU (interp)
224 Tcl_Interp* interp;
225 {
226   TrfLock; /* THREADING: serialize initialization */
227   convDefinition.options = Trf_ConverterOptions ();
228   TrfUnlock;
229 
230   return Trf_Register (interp, &convDefinition);
231 }
232 
233 /*
234  *------------------------------------------------------*
235  *
236  *	CreateEncoder --
237  *
238  *	------------------------------------------------*
239  *	Allocate and initialize the control block of a
240  *	data encoder.
241  *	------------------------------------------------*
242  *
243  *	Sideeffects:
244  *		Allocates memory.
245  *
246  *	Result:
247  *		An opaque reference to the control block.
248  *
249  *------------------------------------------------------*
250  */
251 
252 static Trf_ControlBlock
CreateEncoder(writeClientData,fun,optInfo,interp,clientData)253 CreateEncoder (writeClientData, fun, optInfo, interp, clientData)
254 ClientData    writeClientData;
255 Trf_WriteProc *fun;
256 Trf_Options   optInfo;
257 Tcl_Interp*   interp;
258 ClientData clientData;
259 {
260   EncoderControl* c;
261 
262   c = (EncoderControl*) ckalloc (sizeof (EncoderControl));
263   c->write           = fun;
264   c->writeClientData = writeClientData;
265 
266   /* initialize conversion specific items here (uuencode) */
267 
268   c->charCount = 0;
269   memset (c->buf, '\0', 3);
270 
271   return (ClientData) c;
272 }
273 
274 /*
275  *------------------------------------------------------*
276  *
277  *	DeleteEncoder --
278  *
279  *	------------------------------------------------*
280  *	Destroy the control block of an encoder.
281  *	------------------------------------------------*
282  *
283  *	Sideeffects:
284  *		Releases the memory allocated by 'CreateEncoder'
285  *
286  *	Result:
287  *		None.
288  *
289  *------------------------------------------------------*
290  */
291 
292 static void
DeleteEncoder(ctrlBlock,clientData)293 DeleteEncoder (ctrlBlock, clientData)
294 Trf_ControlBlock ctrlBlock;
295 ClientData clientData;
296 {
297   EncoderControl* c = (EncoderControl*) ctrlBlock;
298 
299   /* release conversion specific items here (uuencode) */
300 
301   ckfree ((char*) c);
302 }
303 
304 /*
305  *------------------------------------------------------*
306  *
307  *	Encode --
308  *
309  *	------------------------------------------------*
310  *	Encode the given character and write the result.
311  *	------------------------------------------------*
312  *
313  *	Sideeffects:
314  *		As of the called WriteFun.
315  *
316  *	Result:
317  *		Generated bytes implicitly via WriteFun.
318  *		A standard Tcl error code.
319  *
320  *------------------------------------------------------*
321  */
322 
323 static int
Encode(ctrlBlock,character,interp,clientData)324 Encode (ctrlBlock, character, interp, clientData)
325 Trf_ControlBlock ctrlBlock;
326 unsigned int character;
327 Tcl_Interp* interp;
328 ClientData clientData;
329 {
330   EncoderControl* c = (EncoderControl*) ctrlBlock;
331 
332   /* execute conversion specific code here (uuencode) */
333 
334   c->buf [c->charCount] = character;
335   c->charCount ++;
336 
337   if (c->charCount == 3) {
338     unsigned char buf [4];
339 
340     TrfSplit3to4     (c->buf, buf, 3);
341     TrfApplyEncoding (buf, 4, uuMap);
342 
343     c->charCount = 0;
344     memset (c->buf, '\0', 3);
345 
346     return c->write (c->writeClientData, buf, 4, interp);
347   }
348 
349   return TCL_OK;
350 }
351 
352 /*
353  *------------------------------------------------------*
354  *
355  *	FlushEncoder --
356  *
357  *	------------------------------------------------*
358  *	Encode an incomplete character sequence (if possible).
359  *	------------------------------------------------*
360  *
361  *	Sideeffects:
362  *		As of the called WriteFun.
363  *
364  *	Result:
365  *		Generated bytes implicitly via WriteFun.
366  *		A standard Tcl error code.
367  *
368  *------------------------------------------------------*
369  */
370 
371 static int
FlushEncoder(ctrlBlock,interp,clientData)372 FlushEncoder (ctrlBlock, interp, clientData)
373 Trf_ControlBlock ctrlBlock;
374 Tcl_Interp* interp;
375 ClientData clientData;
376 {
377   EncoderControl* c = (EncoderControl*) ctrlBlock;
378 
379   /* execute conversion specific code here (uuencode) */
380 
381   if (c->charCount > 0) {
382     unsigned char buf [4];
383 
384     TrfSplit3to4     (c->buf, buf, c->charCount);
385     TrfApplyEncoding (buf, 4, uuMap);
386 
387     c->charCount = 0;
388     memset (c->buf, '\0', 3);
389 
390     return c->write (c->writeClientData, buf, 4, interp);
391   }
392 
393   return TCL_OK;
394 }
395 
396 /*
397  *------------------------------------------------------*
398  *
399  *	ClearEncoder --
400  *
401  *	------------------------------------------------*
402  *	Discard an incomplete character sequence.
403  *	------------------------------------------------*
404  *
405  *	Sideeffects:
406  *		See above.
407  *
408  *	Result:
409  *		None.
410  *
411  *------------------------------------------------------*
412  */
413 
414 static void
ClearEncoder(ctrlBlock,clientData)415 ClearEncoder (ctrlBlock, clientData)
416 Trf_ControlBlock ctrlBlock;
417 ClientData clientData;
418 {
419   EncoderControl* c = (EncoderControl*) ctrlBlock;
420 
421   /* execute conversion specific code here (uuencode) */
422 
423   c->charCount = 0;
424   memset (c->buf, '\0', 3);
425 }
426 
427 /*
428  *------------------------------------------------------*
429  *
430  *	CreateDecoder --
431  *
432  *	------------------------------------------------*
433  *	Allocate and initialize the control block of a
434  *	data decoder.
435  *	------------------------------------------------*
436  *
437  *	Sideeffects:
438  *		Allocates memory.
439  *
440  *	Result:
441  *		An opaque reference to the control block.
442  *
443  *------------------------------------------------------*
444  */
445 
446 static Trf_ControlBlock
CreateDecoder(writeClientData,fun,optInfo,interp,clientData)447 CreateDecoder (writeClientData, fun, optInfo, interp, clientData)
448 ClientData    writeClientData;
449 Trf_WriteProc *fun;
450 Trf_Options   optInfo;
451 Tcl_Interp*   interp;
452 ClientData clientData;
453 {
454   DecoderControl* c;
455 
456   c = (DecoderControl*) ckalloc (sizeof (DecoderControl));
457   c->write           = fun;
458   c->writeClientData = writeClientData;
459 
460   /* initialize conversion specific items here (uudecode) */
461 
462   c->charCount = 0;
463   memset (c->buf, '\0', 4);
464   c->expectFlush = 0;
465 
466   return (ClientData) c;
467 }
468 
469 /*
470  *------------------------------------------------------*
471  *
472  *	DeleteDecoder --
473  *
474  *	------------------------------------------------*
475  *	Destroy the control block of an decoder.
476  *	------------------------------------------------*
477  *
478  *	Sideeffects:
479  *		Releases the memory allocated by 'CreateDecoder'
480  *
481  *	Result:
482  *		None.
483  *
484  *------------------------------------------------------*
485  */
486 
487 static void
DeleteDecoder(ctrlBlock,clientData)488 DeleteDecoder (ctrlBlock, clientData)
489 Trf_ControlBlock ctrlBlock;
490 ClientData clientData;
491 {
492   DecoderControl* c = (DecoderControl*) ctrlBlock;
493 
494   /* release conversion specific items here (uudecode) */
495 
496   ckfree ((char*) c);
497 }
498 
499 /*
500  *------------------------------------------------------*
501  *
502  *	Decode --
503  *
504  *	------------------------------------------------*
505  *	Decode the given character and write the result.
506  *	------------------------------------------------*
507  *
508  *	Sideeffects:
509  *		As of the called WriteFun.
510  *
511  *	Result:
512  *		Generated bytes implicitly via WriteFun.
513  *		A standard Tcl error code.
514  *
515  *------------------------------------------------------*
516  */
517 
518 static int
Decode(ctrlBlock,character,interp,clientData)519 Decode (ctrlBlock, character, interp, clientData)
520 Trf_ControlBlock ctrlBlock;
521 unsigned int character;
522 Tcl_Interp* interp;
523 ClientData clientData;
524 {
525   DecoderControl* c = (DecoderControl*) ctrlBlock;
526 
527   /* execute conversion specific code here (uudecode) */
528 
529   if (c->expectFlush) {
530     /*
531      * We had a quadruple with pad characters at the last call,
532      * this had to be the last characters in input!  coming here
533      * now indicates, that the padding characters were in the
534      * middle of the string, therefore illegal.
535      */
536 
537     if (interp) {
538       Tcl_ResetResult  (interp);
539       Tcl_AppendResult (interp, "illegal padding inside the string", (char*) NULL);
540     }
541     return TCL_ERROR;
542   }
543 
544 
545   c->buf [c->charCount] = character;
546   c->charCount ++;
547 
548   if (c->charCount == 4) {
549     int res, hasPadding;
550     unsigned char buf [3];
551 
552     hasPadding = 0;
553     res = TrfReverseEncoding (c->buf, 4, uuMapReverse,
554 			      PAD, &hasPadding);
555 
556     if (res != TCL_OK) {
557       if (interp) {
558 	Tcl_ResetResult  (interp);
559 	Tcl_AppendResult (interp, "illegal character found in input", (char*) NULL);
560       }
561       return res;
562     }
563 
564     if (hasPadding)
565       c->expectFlush = 1;
566 
567     TrfMerge4to3 (c->buf, buf);
568 
569     c->charCount = 0;
570     memset (c->buf, '\0', 4);
571 
572     return c->write (c->writeClientData, buf, 3-hasPadding, interp);
573   }
574 
575   return TCL_OK;
576 }
577 
578 /*
579  *------------------------------------------------------*
580  *
581  *	FlushDecoder --
582  *
583  *	------------------------------------------------*
584  *	Decode an incomplete character sequence (if possible).
585  *	------------------------------------------------*
586  *
587  *	Sideeffects:
588  *		As of the called WriteFun.
589  *
590  *	Result:
591  *		Generated bytes implicitly via WriteFun.
592  *		A standard Tcl error code.
593  *
594  *------------------------------------------------------*
595  */
596 
597 static int
FlushDecoder(ctrlBlock,interp,clientData)598 FlushDecoder (ctrlBlock, interp, clientData)
599 Trf_ControlBlock ctrlBlock;
600 Tcl_Interp* interp;
601 ClientData clientData;
602 {
603   DecoderControl* c = (DecoderControl*) ctrlBlock;
604 
605   /* execute conversion specific code here (uudecode) */
606 
607   /*
608    * expectFlush && c->charcount > 0 impossible, catched
609    * in 'Decode' already.
610    */
611 
612   if (c->charCount > 0) {
613     /*
614      * Convert, as if padded with the pad-character.
615      */
616 
617     int res, hasPadding;
618     unsigned char buf [3];
619 
620     hasPadding = 0;
621     res = TrfReverseEncoding (c->buf, c->charCount, uuMapReverse,
622 			      PAD, &hasPadding);
623 
624     if (res != TCL_OK) {
625       if (interp) {
626 	Tcl_ResetResult  (interp);
627 	Tcl_AppendResult (interp, "illegal character found in input", (char*) NULL);
628       }
629       return res;
630     }
631 
632     TrfMerge4to3 (c->buf, buf);
633 
634     c->charCount = 0;
635     memset (c->buf, '\0', 4);
636 
637     return c->write (c->writeClientData, buf, 3-hasPadding, interp);
638   }
639 
640   return TCL_OK;
641 }
642 
643 /*
644  *------------------------------------------------------*
645  *
646  *	ClearDecoder --
647  *
648  *	------------------------------------------------*
649  *	Discard an incomplete character sequence.
650  *	------------------------------------------------*
651  *
652  *	Sideeffects:
653  *		See above.
654  *
655  *	Result:
656  *		None.
657  *
658  *------------------------------------------------------*
659  */
660 
661 static void
ClearDecoder(ctrlBlock,clientData)662 ClearDecoder (ctrlBlock, clientData)
663 Trf_ControlBlock ctrlBlock;
664 ClientData clientData;
665 {
666   DecoderControl* c = (DecoderControl*) ctrlBlock;
667 
668   /* execute conversion specific code here (uudecode) */
669 
670   c->charCount = 0;
671   memset (c->buf, '\0', 4);
672   c->expectFlush = 0;
673 }
674