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 (andreas_kupries@users.sourceforge.net)
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 
56 static Trf_ControlBlock CreateEncoder  _ANSI_ARGS_ ((ClientData writeClientData, Trf_WriteProc *fun,
57 						     Trf_Options optInfo, Tcl_Interp*   interp,
58 						     ClientData clientData));
59 static void             DeleteEncoder  _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
60 						     ClientData clientData));
61 static int              Encode         _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
62 						     unsigned int character,
63 						     Tcl_Interp* interp,
64 						     ClientData clientData));
65 static int              FlushEncoder   _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
66 						     Tcl_Interp* interp,
67 						     ClientData clientData));
68 static void             ClearEncoder   _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
69 						     ClientData clientData));
70 
71 
72 static Trf_ControlBlock CreateDecoder  _ANSI_ARGS_ ((ClientData writeClientData, Trf_WriteProc *fun,
73 						     Trf_Options optInfo, Tcl_Interp*   interp,
74 						     ClientData clientData));
75 static void             DeleteDecoder  _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
76 						     ClientData clientData));
77 static int              Decode         _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
78 						     unsigned int character,
79 						     Tcl_Interp* interp,
80 						     ClientData clientData));
81 static int              FlushDecoder   _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
82 						     Tcl_Interp* interp,
83 						     ClientData clientData));
84 static void             ClearDecoder   _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock,
85 						     ClientData clientData));
86 
87 
88 /*
89  * Converter definition.
90  */
91 
92 static 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 
121 typedef 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 
136 typedef 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 */
157 static 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 */
170 static 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 
226 int
TrfInit_B64(interp)227 TrfInit_B64 (interp)
228 Tcl_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 
256 static Trf_ControlBlock
CreateEncoder(writeClientData,fun,optInfo,interp,clientData)257 CreateEncoder (writeClientData, fun, optInfo, interp, clientData)
258 ClientData    writeClientData;
259 Trf_WriteProc *fun;
260 Trf_Options   optInfo;
261 Tcl_Interp*   interp;
262 ClientData 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 
297 static void
DeleteEncoder(ctrlBlock,clientData)298 DeleteEncoder (ctrlBlock, clientData)
299 Trf_ControlBlock ctrlBlock;
300 ClientData 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 
328 static int
Encode(ctrlBlock,character,interp,clientData)329 Encode (ctrlBlock, character, interp, clientData)
330 Trf_ControlBlock ctrlBlock;
331 unsigned int character;
332 Tcl_Interp* interp;
333 ClientData 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 
403 static int
FlushEncoder(ctrlBlock,interp,clientData)404 FlushEncoder (ctrlBlock, interp, clientData)
405 Trf_ControlBlock ctrlBlock;
406 Tcl_Interp* interp;
407 ClientData 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 
449 static void
ClearEncoder(ctrlBlock,clientData)450 ClearEncoder (ctrlBlock, clientData)
451 Trf_ControlBlock ctrlBlock;
452 ClientData 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 
481 static Trf_ControlBlock
CreateDecoder(writeClientData,fun,optInfo,interp,clientData)482 CreateDecoder (writeClientData, fun, optInfo, interp, clientData)
483 ClientData    writeClientData;
484 Trf_WriteProc *fun;
485 Trf_Options   optInfo;
486 Tcl_Interp*   interp;
487 ClientData 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 
522 static void
DeleteDecoder(ctrlBlock,clientData)523 DeleteDecoder (ctrlBlock, clientData)
524 Trf_ControlBlock ctrlBlock;
525 ClientData 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 
553 static int
Decode(ctrlBlock,character,interp,clientData)554 Decode (ctrlBlock, character, interp, clientData)
555 Trf_ControlBlock ctrlBlock;
556 unsigned int character;
557 Tcl_Interp* interp;
558 ClientData 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 
640 static int
FlushDecoder(ctrlBlock,interp,clientData)641 FlushDecoder (ctrlBlock, interp, clientData)
642 Trf_ControlBlock ctrlBlock;
643 Tcl_Interp* interp;
644 ClientData 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 
704 static void
ClearDecoder(ctrlBlock,clientData)705 ClearDecoder (ctrlBlock, clientData)
706 Trf_ControlBlock ctrlBlock;
707 ClientData 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