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