1/* 2 * hexcode.c -- 3 * 4 * Implements and registers conversion from and to hexadecimal 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: hexcode.c,v 1.12 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 * Every byte is converted into 2 characters, using elements 38 * in the set {0-9,a-z} only. Thus a hexadecimal representation is 39 * generated. The MSBit is output first. 40 * 41 * Decoding: 42 * Only characters in the set {0-9a-zA-Z} are allowed as input. 43 * Each 2-tuple is converted into a single byte. A single character 44 * at the end of input is converted as if padded with "0". 45 */ 46 47 48/* 49 * Declarations of internal procedures. 50 */ 51 52static Trf_ControlBlock 53CreateEncoder _ANSI_ARGS_ ((ClientData writeClientData, Trf_WriteProc *fun, 54 Trf_Options optInfo, Tcl_Interp* interp, 55 ClientData clientData)); 56static void 57DeleteEncoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 58 ClientData clientData)); 59static int 60Encode _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 61 unsigned int character, 62 Tcl_Interp* interp, 63 ClientData clientData)); 64static int 65EncodeBuffer _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 66 unsigned char* buffer, 67 int bufLen, 68 Tcl_Interp* interp, 69 ClientData clientData)); 70static int 71FlushEncoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 72 Tcl_Interp* interp, 73 ClientData clientData)); 74static void 75ClearEncoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 76 ClientData clientData)); 77 78 79static Trf_ControlBlock 80CreateDecoder _ANSI_ARGS_ ((ClientData writeClientData, Trf_WriteProc *fun, 81 Trf_Options optInfo, Tcl_Interp* interp, 82 ClientData clientData)); 83static void 84DeleteDecoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 85 ClientData clientData)); 86static int 87Decode _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 88 unsigned int character, 89 Tcl_Interp* interp, 90 ClientData clientData)); 91static int 92DecodeBuffer _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 93 unsigned char* buffer, 94 int bufLen, 95 Tcl_Interp* interp, 96 ClientData clientData)); 97static int 98FlushDecoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 99 Tcl_Interp* interp, 100 ClientData clientData)); 101static void 102ClearDecoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 103 ClientData clientData)); 104 105 106/* 107 * Converter definition. 108 */ 109 110static Trf_TypeDefinition convDefinition = 111{ 112 "hex", 113 NULL, /* clientData not sed by converters */ 114 NULL, /* set by 'TrfInit_Hex'. THREAD: serialize initialization */ 115 { 116 CreateEncoder, 117 DeleteEncoder, 118 Encode, 119 EncodeBuffer, 120 FlushEncoder, 121 ClearEncoder, 122 NULL /* no MaxRead */ 123 }, { 124 CreateDecoder, 125 DeleteDecoder, 126 Decode, 127 DecodeBuffer, 128 FlushDecoder, 129 ClearDecoder, 130 NULL /* no MaxRead */ 131 }, 132 TRF_RATIO (1, 2) 133}; 134 135/* 136 * Definition of the control blocks for en- and decoder. 137 */ 138 139typedef struct _EncoderControl_ { 140 Trf_WriteProc* write; 141 ClientData writeClientData; 142 143} EncoderControl; 144 145 146typedef struct _DecoderControl_ { 147 Trf_WriteProc* write; 148 ClientData writeClientData; 149 150 unsigned char charCount; /* number of characters assembled so far (0..1) */ 151 unsigned char bench; /* buffer for assembled byte */ 152 153} DecoderControl; 154 155 156/* 157 * Use table lookup 158 */ 159 160static const char* code [] = { /* THREADING: constant, read-only => safe */ 161 "00", "01", "02", "03", "04", "05", "06", "07", "08", "09", "0A", "0B", "0C", "0D", "0E", "0F", 162 "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "1A", "1B", "1C", "1D", "1E", "1F", 163 "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "2A", "2B", "2C", "2D", "2E", "2F", 164 "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "3A", "3B", "3C", "3D", "3E", "3F", 165 "40", "41", "42", "43", "44", "45", "46", "47", "48", "49", "4A", "4B", "4C", "4D", "4E", "4F", 166 "50", "51", "52", "53", "54", "55", "56", "57", "58", "59", "5A", "5B", "5C", "5D", "5E", "5F", 167 "60", "61", "62", "63", "64", "65", "66", "67", "68", "69", "6A", "6B", "6C", "6D", "6E", "6F", 168 "70", "71", "72", "73", "74", "75", "76", "77", "78", "79", "7A", "7B", "7C", "7D", "7E", "7F", 169 "80", "81", "82", "83", "84", "85", "86", "87", "88", "89", "8A", "8B", "8C", "8D", "8E", "8F", 170 "90", "91", "92", "93", "94", "95", "96", "97", "98", "99", "9A", "9B", "9C", "9D", "9E", "9F", 171 "A0", "A1", "A2", "A3", "A4", "A5", "A6", "A7", "A8", "A9", "AA", "AB", "AC", "AD", "AE", "AF", 172 "B0", "B1", "B2", "B3", "B4", "B5", "B6", "B7", "B8", "B9", "BA", "BB", "BC", "BD", "BE", "BF", 173 "C0", "C1", "C2", "C3", "C4", "C5", "C6", "C7", "C8", "C9", "CA", "CB", "CC", "CD", "CE", "CF", 174 "D0", "D1", "D2", "D3", "D4", "D5", "D6", "D7", "D8", "D9", "DA", "DB", "DC", "DD", "DE", "DF", 175 "E0", "E1", "E2", "E3", "E4", "E5", "E6", "E7", "E8", "E9", "EA", "EB", "EC", "ED", "EE", "EF", 176 "F0", "F1", "F2", "F3", "F4", "F5", "F6", "F7", "F8", "F9", "FA", "FB", "FC", "FD", "FE", "FF", 177}; 178 179 180/* 181 *------------------------------------------------------* 182 * 183 * TrfInit_Hex -- 184 * 185 * ------------------------------------------------* 186 * Register the conversion implemented in this file. 187 * ------------------------------------------------* 188 * 189 * Sideeffects: 190 * As of 'Trf_Register'. 191 * 192 * Result: 193 * A standard Tcl error code. 194 * 195 *------------------------------------------------------* 196 */ 197 198int 199TrfInit_Hex (interp) 200Tcl_Interp* interp; 201{ 202 TrfLock; /* THREADING: serialize initialization */ 203 convDefinition.options = Trf_ConverterOptions (); 204 TrfUnlock; 205 206 return Trf_Register (interp, &convDefinition); 207} 208 209/* 210 *------------------------------------------------------* 211 * 212 * CreateEncoder -- 213 * 214 * ------------------------------------------------* 215 * Allocate and initialize the control block of a 216 * data encoder. 217 * ------------------------------------------------* 218 * 219 * Sideeffects: 220 * Allocates memory. 221 * 222 * Result: 223 * An opaque reference to the control block. 224 * 225 *------------------------------------------------------* 226 */ 227 228static Trf_ControlBlock 229CreateEncoder (writeClientData, fun, optInfo, interp, clientData) 230ClientData writeClientData; 231Trf_WriteProc *fun; 232Trf_Options optInfo; 233Tcl_Interp* interp; 234ClientData clientData; 235{ 236 EncoderControl* c; 237 238 c = (EncoderControl*) ckalloc (sizeof (EncoderControl)); 239 c->write = fun; 240 c->writeClientData = writeClientData; 241 242 return (ClientData) c; 243} 244 245/* 246 *------------------------------------------------------* 247 * 248 * DeleteEncoder -- 249 * 250 * ------------------------------------------------* 251 * Destroy the control block of an encoder. 252 * ------------------------------------------------* 253 * 254 * Sideeffects: 255 * Releases the memory allocated by 'CreateEncoder' 256 * 257 * Result: 258 * None. 259 * 260 *------------------------------------------------------* 261 */ 262 263static void 264DeleteEncoder (ctrlBlock, clientData) 265Trf_ControlBlock ctrlBlock; 266ClientData clientData; 267{ 268 EncoderControl* c = (EncoderControl*) ctrlBlock; 269 270 ckfree ((char*) c); 271} 272 273/* 274 *------------------------------------------------------* 275 * 276 * Encode -- 277 * 278 * ------------------------------------------------* 279 * Encode the given character and write the result. 280 * ------------------------------------------------* 281 * 282 * Sideeffects: 283 * As of the called WriteFun. 284 * 285 * Result: 286 * Generated bytes implicitly via WriteFun. 287 * A standard Tcl error code. 288 * 289 *------------------------------------------------------* 290 */ 291 292static int 293Encode (ctrlBlock, character, interp, clientData) 294Trf_ControlBlock ctrlBlock; 295unsigned int character; 296Tcl_Interp* interp; 297ClientData clientData; 298{ 299 EncoderControl* c = (EncoderControl*) ctrlBlock; 300 301#if 0 302 unsigned char buffer [2]; 303 304 char high = (character >> 4) & 0x0F; 305 char low = character & 0x0F; 306 307 high += ((high < 10) ? '0' : 'A'-10); 308 low += ((low < 10) ? '0' : 'A'-10); 309 310 buffer [0] = high; 311 buffer [1] = low; 312 313 return c->write (c->writeClientData, buffer, 2, interp); 314#endif 315 316 return c->write (c->writeClientData, (unsigned char*) code [character & 0x00ff], 2, interp); 317} 318 319/* 320 *------------------------------------------------------* 321 * 322 * EncodeBuffer -- 323 * 324 * ------------------------------------------------* 325 * Encode the given buffer and write the result. 326 * ------------------------------------------------* 327 * 328 * Sideeffects: 329 * As of the called WriteFun. 330 * 331 * Result: 332 * Generated bytes implicitly via WriteFun. 333 * A standard Tcl error code. 334 * 335 *------------------------------------------------------* 336 */ 337 338static int 339EncodeBuffer (ctrlBlock, buffer, bufLen, interp, clientData) 340Trf_ControlBlock ctrlBlock; 341unsigned char* buffer; 342int bufLen; 343Tcl_Interp* interp; 344ClientData clientData; 345{ 346 EncoderControl* c = (EncoderControl*) ctrlBlock; 347 char* out = (char*) ckalloc (2*bufLen+1); 348 int res, i, j; 349 CONST char* ch; 350 351 for (i=0, j=0; i < bufLen; i++) { 352 ch = code [buffer [i] & 0x00ff]; 353 out [j] = ch [0]; j++; 354 out [j] = ch [1]; j++; 355 } 356 out [j] = '\0'; 357 358 res = c->write (c->writeClientData, (unsigned char*) out, 2*bufLen, interp); 359 360 ckfree ((char*) out); 361 return res; 362} 363 364/* 365 *------------------------------------------------------* 366 * 367 * FlushEncoder -- 368 * 369 * ------------------------------------------------* 370 * Encode an incomplete character sequence (if possible). 371 * ------------------------------------------------* 372 * 373 * Sideeffects: 374 * As of the called WriteFun. 375 * 376 * Result: 377 * Generated bytes implicitly via WriteFun. 378 * A standard Tcl error code. 379 * 380 *------------------------------------------------------* 381 */ 382 383static int 384FlushEncoder (ctrlBlock, interp, clientData) 385Trf_ControlBlock ctrlBlock; 386Tcl_Interp* interp; 387ClientData clientData; 388{ 389 /* nothing to to */ 390 return TCL_OK; 391} 392 393/* 394 *------------------------------------------------------* 395 * 396 * ClearEncoder -- 397 * 398 * ------------------------------------------------* 399 * Discard an incomplete character sequence. 400 * ------------------------------------------------* 401 * 402 * Sideeffects: 403 * See above. 404 * 405 * Result: 406 * None. 407 * 408 *------------------------------------------------------* 409 */ 410 411static void 412ClearEncoder (ctrlBlock, clientData) 413Trf_ControlBlock ctrlBlock; 414ClientData clientData; 415{ 416 /* nothing to do */ 417} 418 419/* 420 *------------------------------------------------------* 421 * 422 * CreateDecoder -- 423 * 424 * ------------------------------------------------* 425 * Allocate and initialize the control block of a 426 * data decoder. 427 * ------------------------------------------------* 428 * 429 * Sideeffects: 430 * Allocates memory. 431 * 432 * Result: 433 * An opaque reference to the control block. 434 * 435 *------------------------------------------------------* 436 */ 437 438static Trf_ControlBlock 439CreateDecoder (writeClientData, fun, optInfo, interp, clientData) 440ClientData writeClientData; 441Trf_WriteProc *fun; 442Trf_Options optInfo; 443Tcl_Interp* interp; 444ClientData clientData; 445{ 446 DecoderControl* c; 447 448 c = (DecoderControl*) ckalloc (sizeof (DecoderControl)); 449 c->write = fun; 450 c->writeClientData = writeClientData; 451 452 c->charCount = 0; 453 c->bench = '\0'; 454 455 return (ClientData) c; 456} 457 458/* 459 *------------------------------------------------------* 460 * 461 * DeleteDecoder -- 462 * 463 * ------------------------------------------------* 464 * Destroy the control block of an decoder. 465 * ------------------------------------------------* 466 * 467 * Sideeffects: 468 * Releases the memory allocated by 'CreateDecoder' 469 * 470 * Result: 471 * None. 472 * 473 *------------------------------------------------------* 474 */ 475 476static void 477DeleteDecoder (ctrlBlock, clientData) 478Trf_ControlBlock ctrlBlock; 479ClientData clientData; 480{ 481 DecoderControl* c = (DecoderControl*) ctrlBlock; 482 483 ckfree ((char*) c); 484} 485 486/* 487 *------------------------------------------------------* 488 * 489 * Decode -- 490 * 491 * ------------------------------------------------* 492 * Decode the given character and write the result. 493 * ------------------------------------------------* 494 * 495 * Sideeffects: 496 * As of the called WriteFun. 497 * 498 * Result: 499 * Generated bytes implicitly via WriteFun. 500 * A standard Tcl error code. 501 * 502 *------------------------------------------------------* 503 */ 504 505static int 506Decode (ctrlBlock, character, interp, clientData) 507Trf_ControlBlock ctrlBlock; 508unsigned int character; 509Tcl_Interp* interp; 510ClientData clientData; 511{ 512 DecoderControl* c = (DecoderControl*) ctrlBlock; 513 unsigned char nibble = character; 514 515#define IN_RANGE(low,x,high) (((low) <= (x)) && ((x) <= (high))) 516 517 if (IN_RANGE ('0', nibble, '9')) 518 nibble -= '0'; 519 else if (IN_RANGE ('a', nibble, 'f')) 520 nibble -= 'a'-10; 521 else if (IN_RANGE ('A', nibble, 'F')) 522 nibble -= 'A'-10; 523 else { 524 if (interp) { 525 char buf [10]; 526 527 if (character < ' ' || character > 127) { 528 sprintf (buf, "0x%02x", character); 529 } else { 530 buf [0] = '\''; 531 buf [1] = character; 532 buf [2] = '\''; 533 buf [3] = '\0'; 534 } 535 536 Tcl_ResetResult (interp); 537 Tcl_AppendResult (interp, "illegal character ", buf, 538 " found in input", (char*) NULL); 539 } 540 return TCL_ERROR; 541 } 542 543 c->bench |= (nibble << (4 * (1- c->charCount))); 544 c->charCount ++; 545 546 if (c->charCount >= 2) { 547 int res = c->write (c->writeClientData, &c->bench, 1, interp); 548 549 c->bench = '\0'; 550 c->charCount = 0; 551 552 return res; 553 } 554 555 return TCL_OK; 556 557#undef IN_RANGE 558} 559 560/* 561 *------------------------------------------------------* 562 * 563 * DecodeBuffer -- 564 * 565 * ------------------------------------------------* 566 * Decode the given buffer and write the result. 567 * ------------------------------------------------* 568 * 569 * Sideeffects: 570 * As of the called WriteFun. 571 * 572 * Result: 573 * Generated bytes implicitly via WriteFun. 574 * A standard Tcl error code. 575 * 576 *------------------------------------------------------* 577 */ 578 579static int 580DecodeBuffer (ctrlBlock, buffer, bufLen, interp, clientData) 581Trf_ControlBlock ctrlBlock; 582unsigned char* buffer; 583int bufLen; 584Tcl_Interp* interp; 585ClientData clientData; 586{ 587#define IN_RANGE(low,x,high) (((low) <= (x)) && ((x) <= (high))) 588 589 DecoderControl* c = (DecoderControl*) ctrlBlock; 590 char* out = (char*) ckalloc (1+bufLen/2); 591 int res, i, j; 592 unsigned char nibble; 593 594 for (i=0, j=0; i < bufLen; i++) { 595 nibble = buffer [i]; 596 597 if (IN_RANGE ('0', nibble, '9')) 598 nibble -= '0'; 599 else if (IN_RANGE ('a', nibble, 'f')) 600 nibble -= 'a' - 10; 601 else if (IN_RANGE ('A', nibble, 'F')) 602 nibble -= 'A' - 10; 603 else { 604 if (interp) { 605 char buf [10]; 606 607 if (nibble < ' ' || nibble > 127) { 608 sprintf (buf, "0x%02x", nibble); 609 } else { 610 buf [0] = '\''; 611 buf [1] = nibble; 612 buf [2] = '\''; 613 buf [3] = '\0'; 614 } 615 616 Tcl_ResetResult (interp); 617 Tcl_AppendResult (interp, "illegal character ", buf, 618 " found in input", (char*) NULL); 619 } 620 621 ckfree (out); 622 return TCL_ERROR; 623 } 624 625 c->bench |= (nibble << (4 * (1 - c->charCount))); 626 c->charCount ++; 627 628 if (c->charCount >= 2) { 629 out [j] = c->bench; 630 631 c->bench = '\0'; 632 c->charCount = 0; 633 634 j ++; 635 } 636 } 637 638 res = c->write (c->writeClientData, (unsigned char*) out, j, interp); 639 return res; 640 641#undef IN_RANGE 642} 643 644/* 645 *------------------------------------------------------* 646 * 647 * FlushDecoder -- 648 * 649 * ------------------------------------------------* 650 * Decode an incomplete character sequence (if possible). 651 * ------------------------------------------------* 652 * 653 * Sideeffects: 654 * As of the called WriteFun. 655 * 656 * Result: 657 * Generated bytes implicitly via WriteFun. 658 * A standard Tcl error code. 659 * 660 *------------------------------------------------------* 661 */ 662 663static int 664FlushDecoder (ctrlBlock, interp, clientData) 665Trf_ControlBlock ctrlBlock; 666Tcl_Interp* interp; 667ClientData clientData; 668{ 669 DecoderControl* c = (DecoderControl*) ctrlBlock; 670 int res = TCL_OK; 671 672 if (c->charCount > 0) { 673 res = c->write (c->writeClientData, &c->bench, 1, interp); 674 675 c->bench = '\0'; 676 c->charCount = 0; 677 } 678 679 return res; 680} 681 682/* 683 *------------------------------------------------------* 684 * 685 * ClearDecoder -- 686 * 687 * ------------------------------------------------* 688 * Discard an incomplete character sequence. 689 * ------------------------------------------------* 690 * 691 * Sideeffects: 692 * See above. 693 * 694 * Result: 695 * None. 696 * 697 *------------------------------------------------------* 698 */ 699 700static void 701ClearDecoder (ctrlBlock, clientData) 702Trf_ControlBlock ctrlBlock; 703ClientData clientData; 704{ 705 DecoderControl* c = (DecoderControl*) ctrlBlock; 706 707 c->bench = '\0'; 708 c->charCount = 0; 709} 710