1/* 2 * uucode.c -- 3 * 4 * Implements and registers conversion from and to uuencoded representation. 5 * 6 * 7 * Copyright (c) 1996 Andreas Kupries (a.kupries@westend.com) 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 55static Trf_ControlBlock CreateEncoder _ANSI_ARGS_ ((ClientData writeClientData, Trf_WriteProc *fun, 56 Trf_Options optInfo, Tcl_Interp* interp, 57 ClientData clientData)); 58static void DeleteEncoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 59 ClientData clientData)); 60static int Encode _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 61 unsigned int character, 62 Tcl_Interp* interp, 63 ClientData clientData)); 64static int FlushEncoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 65 Tcl_Interp* interp, 66 ClientData clientData)); 67static void ClearEncoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 68 ClientData clientData)); 69 70 71static Trf_ControlBlock CreateDecoder _ANSI_ARGS_ ((ClientData writeClientData, Trf_WriteProc *fun, 72 Trf_Options optInfo, Tcl_Interp* interp, 73 ClientData clientData)); 74static void DeleteDecoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 75 ClientData clientData)); 76static int Decode _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 77 unsigned int character, 78 Tcl_Interp* interp, 79 ClientData clientData)); 80static int FlushDecoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 81 Tcl_Interp* interp, 82 ClientData clientData)); 83static void ClearDecoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 84 ClientData clientData)); 85 86 87/* 88 * Converter definition. 89 */ 90 91static 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 120typedef 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 132typedef 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 */ 153static 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 */ 166static 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 222int 223TrfInit_UU (interp) 224Tcl_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 252static Trf_ControlBlock 253CreateEncoder (writeClientData, fun, optInfo, interp, clientData) 254ClientData writeClientData; 255Trf_WriteProc *fun; 256Trf_Options optInfo; 257Tcl_Interp* interp; 258ClientData 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 292static void 293DeleteEncoder (ctrlBlock, clientData) 294Trf_ControlBlock ctrlBlock; 295ClientData 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 323static int 324Encode (ctrlBlock, character, interp, clientData) 325Trf_ControlBlock ctrlBlock; 326unsigned int character; 327Tcl_Interp* interp; 328ClientData 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 371static int 372FlushEncoder (ctrlBlock, interp, clientData) 373Trf_ControlBlock ctrlBlock; 374Tcl_Interp* interp; 375ClientData 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 414static void 415ClearEncoder (ctrlBlock, clientData) 416Trf_ControlBlock ctrlBlock; 417ClientData 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 446static Trf_ControlBlock 447CreateDecoder (writeClientData, fun, optInfo, interp, clientData) 448ClientData writeClientData; 449Trf_WriteProc *fun; 450Trf_Options optInfo; 451Tcl_Interp* interp; 452ClientData 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 487static void 488DeleteDecoder (ctrlBlock, clientData) 489Trf_ControlBlock ctrlBlock; 490ClientData 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 518static int 519Decode (ctrlBlock, character, interp, clientData) 520Trf_ControlBlock ctrlBlock; 521unsigned int character; 522Tcl_Interp* interp; 523ClientData 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 597static int 598FlushDecoder (ctrlBlock, interp, clientData) 599Trf_ControlBlock ctrlBlock; 600Tcl_Interp* interp; 601ClientData 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 661static void 662ClearDecoder (ctrlBlock, clientData) 663Trf_ControlBlock ctrlBlock; 664ClientData 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