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