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