1/* 2 * digest.c -- 3 * 4 * Implements and registers code common to all message digests. 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: digest.c,v 1.18 2009/05/07 05:30:35 andreas_kupries Exp $ 28 */ 29 30#include "transformInt.h" 31 32 33/* 34 * Declarations of internal procedures. 35 */ 36 37static Trf_ControlBlock CreateEncoder _ANSI_ARGS_ ((ClientData writeClientData, 38 Trf_WriteProc *fun, 39 Trf_Options optInfo, 40 Tcl_Interp* interp, 41 ClientData clientData)); 42static void DeleteEncoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 43 ClientData clientData)); 44static int Encode _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 45 unsigned int character, 46 Tcl_Interp* interp, 47 ClientData clientData)); 48static int EncodeBuffer _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 49 unsigned char* buffer, int bufLen, 50 Tcl_Interp* interp, 51 ClientData clientData)); 52static int FlushEncoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 53 Tcl_Interp* interp, 54 ClientData clientData)); 55static void ClearEncoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 56 ClientData clientData)); 57 58 59static Trf_ControlBlock CreateDecoder _ANSI_ARGS_ ((ClientData writeClientData, 60 Trf_WriteProc *fun, 61 Trf_Options optInfo, 62 Tcl_Interp* interp, 63 ClientData clientData)); 64static void DeleteDecoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 65 ClientData clientData)); 66static int Decode _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 67 unsigned int character, 68 Tcl_Interp* interp, 69 ClientData clientData)); 70static int DecodeBuffer _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 71 unsigned char* buffer, int bufLen, 72 Tcl_Interp* interp, 73 ClientData clientData)); 74static int FlushDecoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 75 Tcl_Interp* interp, 76 ClientData clientData)); 77static void ClearDecoder _ANSI_ARGS_ ((Trf_ControlBlock ctrlBlock, 78 ClientData clientData)); 79 80 81/* 82 * Generator definition. 83 */ 84 85static Trf_TypeDefinition mdDefinition = /* THREADING: constant, read-only => safe */ 86{ 87 NULL, /* filled later by Trf_RegisterMessageDigest (in a copy) */ 88 NULL, /* filled later by Trf_RegisterMessageDigest (in a copy) */ 89 NULL, /* filled later by Trf_RegisterMessageDigest (in a copy) */ 90 { 91 CreateEncoder, 92 DeleteEncoder, 93 Encode, 94 EncodeBuffer, 95 FlushEncoder, 96 ClearEncoder, 97 NULL /* no MaxRead */ 98 }, { 99 CreateDecoder, 100 DeleteDecoder, 101 Decode, 102 DecodeBuffer, 103 FlushDecoder, 104 ClearDecoder, 105 NULL /* no MaxRead */ 106 }, 107 TRF_UNSEEKABLE 108}; 109 110/* 111 * Definition of the control blocks for en- and decoder. 112 */ 113 114typedef struct _EncoderControl_ { 115 Trf_WriteProc* write; 116 ClientData writeClientData; 117 118 int operation_mode; 119 120 char* destHandle; /* Name of target for ATTACH_WRITE */ 121 Tcl_Channel dest; /* Channel target for ATTACH_WRITE. possibly NULL */ 122 Tcl_Interp* vInterp; /* Interpreter containing 'destHandle', if name of variable */ 123 124 /* Possible combinations: 125 * destHandle != NULL, vInterp != NULL, dest == NULL /ATTACH_WRITE, to variable 126 * destHandle == NULL, vInterp == NULL, dest != NULL /ATTACH_WRITE, to channel 127 * destHandle == NULL, vInterp == NULL, dest == NULL /ATTACH_ABSORB, or IMMEDIATE 128 * 129 * TRF_TRANSPARENT <=> TRF_WRITE_HASH 130 */ 131 132 VOID* context; 133 134 135} EncoderControl; 136 137#define IMMEDIATE (0) 138#define ATTACH_ABSORB (1) 139#define ATTACH_WRITE (2) 140#define ATTACH_TRANS (3) 141 142typedef struct _DecoderControl_ { 143 Trf_WriteProc* write; 144 ClientData writeClientData; 145 146 int operation_mode; 147 148 char* destHandle; /* Name of target for ATTACH_WRITE */ 149 Tcl_Channel dest; /* Channel target for ATTACH_WRITE. possibly NULL */ 150 Tcl_Interp* vInterp; /* Interpreter containing 'destHandle', if name of variable */ 151 152 /* Possible combinations: 153 * destHandle != NULL, dest == NULL /ATTACH_WRITE, to variable 154 * destHandle == NULL, dest != NULL /ATTACH_WRITE, to channel 155 * destHandle == NULL, dest == NULL /ATTACH_ABSORB, or IMMEDIATE 156 * vInterp always set, because of 'matchFlag'. 157 * 158 * TRF_TRANSPARENT <=> TRF_WRITE_HASH 159 */ 160 161 VOID* context; 162 char* matchFlag; /* target for ATTACH_ABSORB */ 163 164 unsigned char* digest_buffer; 165 short buffer_pos; 166 unsigned short charCount; 167 168} DecoderControl; 169 170 171static int 172WriteDigest _ANSI_ARGS_ ((Tcl_Interp* interp, char* destHandle, 173 Tcl_Channel dest, char* digest, 174 Trf_MessageDigestDescription* md)); 175 176 177/* 178 *------------------------------------------------------* 179 * 180 * Trf_RegisterMessageDigest -- 181 * 182 * ------------------------------------------------* 183 * Register the specified generator as transformer. 184 * ------------------------------------------------* 185 * 186 * Sideeffects: 187 * Allocates memory. As of 'Trf_Register'. 188 * 189 * Result: 190 * A standard Tcl error code. 191 * 192 *------------------------------------------------------* 193 */ 194 195int 196Trf_RegisterMessageDigest (interp, md_desc) 197Tcl_Interp* interp; 198CONST Trf_MessageDigestDescription* md_desc; 199{ 200 Trf_TypeDefinition* md; 201 int res; 202 203 START (Trf_RegisterMessageDigest); 204 205 /* THREADING: read-only access => safe */ 206 md = (Trf_TypeDefinition*) ckalloc (sizeof (Trf_TypeDefinition)); 207 208 memcpy ((VOID*) md, (VOID*) &mdDefinition, sizeof (Trf_TypeDefinition)); 209 210 md->name = md_desc->name; 211 md->clientData = (ClientData) md_desc; 212 md->options = TrfMDOptions (); 213 214 PRINT ("MD_Desc %p\n", md_desc); FL; IN; 215 216 PRINT ("Name: %s\n", md_desc->name); 217 PRINT ("Context: %d\n", md_desc->context_size); 218 PRINT ("Digest: %d\n", md_desc->digest_size); 219 PRINT ("Start: %p\n", md_desc->startProc); 220 PRINT ("Update: %p\n", md_desc->updateProc); 221 PRINT ("UpdateBuf: %p\n", md_desc->updateBufProc); 222 PRINT ("Final %p\n", md_desc->finalProc); 223 PRINT ("Check: %p\n", md_desc->checkProc); 224 225 OT; 226 227 228 res = Trf_Register (interp, md); 229 230 /* 'md' is a memory leak, it will never be released. 231 */ 232 233 DONE (Trf_RegisterMessageDigest); 234 return res; 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 TrfMDOptionBlock* o = (TrfMDOptionBlock*) optInfo; 266 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 267 268 START (digest.CreateEncoder); 269 PRINT ("%p: %s\n", md, md->name); 270 271 c = (EncoderControl*) ckalloc (sizeof (EncoderControl)); 272 c->write = fun; 273 c->writeClientData = writeClientData; 274 275 PRINT ("Setting up state\n"); FL; 276 277 if ((o->behaviour == TRF_IMMEDIATE) || (o->mode == TRF_ABSORB_HASH)) { 278 c->operation_mode = (o->behaviour == TRF_IMMEDIATE) ? IMMEDIATE : ATTACH_ABSORB; 279 c->vInterp = (Tcl_Interp*) NULL; 280 c->destHandle = (char*) NULL; 281 c->dest = (Tcl_Channel) NULL; 282 } else { 283 if (o->mode == TRF_WRITE_HASH) 284 c->operation_mode = ATTACH_WRITE; 285 else 286 c->operation_mode = ATTACH_TRANS; 287 288 if (o->wdIsChannel) { 289 c->vInterp = (Tcl_Interp*) NULL; 290 c->destHandle = (char*) NULL; 291 c->dest = o->wdChannel; 292 } else { 293 c->vInterp = o->vInterp; 294 c->destHandle = o->writeDestination; 295 c->dest = (Tcl_Channel) NULL; 296 297 o->writeDestination = (char*) NULL; /* ownership moved, prevent early free */ 298 } 299 } 300 301 /* 302 * Create and initialize the context. 303 */ 304 305 PRINT ("Setting up context (%d bytes)\n", md->context_size); FL; 306 307 c->context = (VOID*) ckalloc (md->context_size); 308 (*md->startProc) (c->context); 309 310 DONE (digest.CreateEncoder); 311 312 return (ClientData) c; 313} 314 315/* 316 *------------------------------------------------------* 317 * 318 * DeleteEncoder -- 319 * 320 * ------------------------------------------------* 321 * Destroy the control block of an encoder. 322 * ------------------------------------------------* 323 * 324 * Sideeffects: 325 * Releases the memory allocated by 'CreateEncoder' 326 * 327 * Result: 328 * None. 329 * 330 *------------------------------------------------------* 331 */ 332 333static void 334DeleteEncoder (ctrlBlock, clientData) 335Trf_ControlBlock ctrlBlock; 336ClientData clientData; 337{ 338 EncoderControl* c = (EncoderControl*) ctrlBlock; 339 340 /* [Bug 2788106]. */ 341 if (c->destHandle) { 342 ckfree (c->destHandle); 343 } 344 345 ckfree ((char*) c->context); 346 ckfree ((char*) c); 347} 348 349/* 350 *------------------------------------------------------* 351 * 352 * Encode -- 353 * 354 * ------------------------------------------------* 355 * Encode the given character and write the result. 356 * ------------------------------------------------* 357 * 358 * Sideeffects: 359 * As of the called WriteFun. 360 * 361 * Result: 362 * Generated bytes implicitly via WriteFun. 363 * A standard Tcl error code. 364 * 365 *------------------------------------------------------* 366 */ 367 368static int 369Encode (ctrlBlock, character, interp, clientData) 370Trf_ControlBlock ctrlBlock; 371unsigned int character; 372Tcl_Interp* interp; 373ClientData clientData; 374{ 375 EncoderControl* c = (EncoderControl*) ctrlBlock; 376 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 377 unsigned char buf; 378 379 buf = character; 380 (*md->updateProc) (c->context, character); 381 382 if ((c->operation_mode == ATTACH_ABSORB) || 383 (c->operation_mode == ATTACH_TRANS)) { 384 /* 385 * absorption/transparent mode: incoming characters flow 386 * unchanged through transformation. 387 */ 388 389 return c->write (c->writeClientData, &buf, 1, interp); 390 } 391 392 return TCL_OK; 393} 394 395/* 396 *------------------------------------------------------* 397 * 398 * EncodeBuffer -- 399 * 400 * ------------------------------------------------* 401 * Encode the given buffer and write the result. 402 * ------------------------------------------------* 403 * 404 * Sideeffects: 405 * As of the called WriteFun. 406 * 407 * Result: 408 * Generated bytes implicitly via WriteFun. 409 * A standard Tcl error code. 410 * 411 *------------------------------------------------------* 412 */ 413 414static int 415EncodeBuffer (ctrlBlock, buffer, bufLen, interp, clientData) 416Trf_ControlBlock ctrlBlock; 417unsigned char* buffer; 418int bufLen; 419Tcl_Interp* interp; 420ClientData clientData; 421{ 422 EncoderControl* c = (EncoderControl*) ctrlBlock; 423 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 424 425 if (*md->updateBufProc != (Trf_MDUpdateBuf*) NULL) { 426 (*md->updateBufProc) (c->context, buffer, bufLen); 427 } else { 428 unsigned int character, i; 429 430 for (i=0; i < ((unsigned int) bufLen); i++) { 431 character = buffer [i]; 432 (*md->updateProc) (c->context, character); 433 } 434 } 435 436 if ((c->operation_mode == ATTACH_ABSORB) || 437 (c->operation_mode == ATTACH_TRANS)) { 438 /* 439 * absorption/transparent mode: incoming characters flow 440 * unchanged through transformation. 441 */ 442 443 return c->write (c->writeClientData, buffer, bufLen, interp); 444 } 445 446 return TCL_OK; 447} 448 449/* 450 *------------------------------------------------------* 451 * 452 * FlushEncoder -- 453 * 454 * ------------------------------------------------* 455 * Encode an incomplete character sequence (if possible). 456 * ------------------------------------------------* 457 * 458 * Sideeffects: 459 * As of the called WriteFun. 460 * 461 * Result: 462 * Generated bytes implicitly via WriteFun. 463 * A standard Tcl error code. 464 * 465 *------------------------------------------------------* 466 */ 467 468static int 469FlushEncoder (ctrlBlock, interp, clientData) 470Trf_ControlBlock ctrlBlock; 471Tcl_Interp* interp; 472ClientData clientData; 473{ 474 EncoderControl* c = (EncoderControl*) ctrlBlock; 475 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 476 char* digest; 477 int res = TCL_OK; 478 479 /* 480 * Get a bit more, for a trailing \0 in 7.6, see 'WriteDigest' too 481 */ 482 digest = (char*) ckalloc (2 + md->digest_size); 483 (*md->finalProc) (c->context, digest); 484 485 if ((c->operation_mode == ATTACH_WRITE) || 486 (c->operation_mode == ATTACH_TRANS)) { 487 res = WriteDigest (c->vInterp, c->destHandle, c->dest, digest, md); 488 } else { 489 /* 490 * Immediate execution or attached channel absorbing the checksum. 491 */ 492 493 /* -W- check wether digest can be declared 'uchar*', or if this has 494 * -W- other sideeffects, see lines 636, 653, 82 too. 495 */ 496 res = c->write (c->writeClientData, (unsigned char*) digest, md->digest_size, interp); 497 } 498 499 ckfree (digest); 500 return res; 501} 502 503/* 504 *------------------------------------------------------* 505 * 506 * ClearEncoder -- 507 * 508 * ------------------------------------------------* 509 * Discard an incomplete character sequence. 510 * ------------------------------------------------* 511 * 512 * Sideeffects: 513 * See above. 514 * 515 * Result: 516 * None. 517 * 518 *------------------------------------------------------* 519 */ 520 521static void 522ClearEncoder (ctrlBlock, clientData) 523Trf_ControlBlock ctrlBlock; 524ClientData clientData; 525{ 526 EncoderControl* c = (EncoderControl*) ctrlBlock; 527 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 528 529 (*md->startProc) (c->context); 530} 531 532/* 533 *------------------------------------------------------* 534 * 535 * CreateDecoder -- 536 * 537 * ------------------------------------------------* 538 * Allocate and initialize the control block of a 539 * data decoder. 540 * ------------------------------------------------* 541 * 542 * Sideeffects: 543 * Allocates memory. 544 * 545 * Result: 546 * An opaque reference to the control block. 547 * 548 *------------------------------------------------------* 549 */ 550 551static Trf_ControlBlock 552CreateDecoder (writeClientData, fun, optInfo, interp, clientData) 553ClientData writeClientData; 554Trf_WriteProc *fun; 555Trf_Options optInfo; 556Tcl_Interp* interp; 557ClientData clientData; 558{ 559 DecoderControl* c; 560 TrfMDOptionBlock* o = (TrfMDOptionBlock*) optInfo; 561 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 562 563 c = (DecoderControl*) ckalloc (sizeof (DecoderControl)); 564 c->write = fun; 565 c->writeClientData = writeClientData; 566 567 c->matchFlag = o->matchFlag; 568 c->vInterp = o->vInterp; 569 o->matchFlag = NULL; 570 571 /* impossible: (o->behaviour == TRF_IMMEDIATE) */ 572 573 if (o->mode == TRF_ABSORB_HASH) { 574 c->operation_mode = ATTACH_ABSORB; 575 c->destHandle = (char*) NULL; 576 c->dest = (Tcl_Channel) NULL; 577 } else { 578 if (o->mode == TRF_WRITE_HASH) 579 c->operation_mode = ATTACH_WRITE; 580 else 581 c->operation_mode = ATTACH_TRANS; 582 583 if (o->rdIsChannel) { 584 c->destHandle = (char*) NULL; 585 c->dest = o->rdChannel; 586 } else { 587 c->destHandle = o->readDestination; 588 c->dest = (Tcl_Channel) NULL; 589 590 o->readDestination = (char*) NULL; /* ownership moved, prevent early free */ 591 } 592 } 593 594 c->buffer_pos = 0; 595 c->charCount = 0; 596 597 c->context = (VOID*) ckalloc (md->context_size); 598 (*md->startProc) (c->context); 599 600 c->digest_buffer = (unsigned char*) ckalloc (md->digest_size); 601 memset (c->digest_buffer, '\0', md->digest_size); 602 603 return (ClientData) c; 604} 605 606/* 607 *------------------------------------------------------* 608 * 609 * DeleteDecoder -- 610 * 611 * ------------------------------------------------* 612 * Destroy the control block of an decoder. 613 * ------------------------------------------------* 614 * 615 * Sideeffects: 616 * Releases the memory allocated by 'CreateDecoder' 617 * 618 * Result: 619 * None. 620 * 621 *------------------------------------------------------* 622 */ 623 624static void 625DeleteDecoder (ctrlBlock, clientData) 626Trf_ControlBlock ctrlBlock; 627ClientData clientData; 628{ 629 DecoderControl* c = (DecoderControl*) ctrlBlock; 630 631 /* [Bug 2788106]. */ 632 if (c->destHandle) { 633 ckfree (c->destHandle); 634 } 635 636 ckfree ((char*) c->digest_buffer); 637 ckfree ((char*) c->context); 638 ckfree ((char*) c); 639} 640 641/* 642 *------------------------------------------------------* 643 * 644 * Decode -- 645 * 646 * ------------------------------------------------* 647 * Decode the given character and write the result. 648 * ------------------------------------------------* 649 * 650 * Sideeffects: 651 * As of the called WriteFun. 652 * 653 * Result: 654 * Generated bytes implicitly via WriteFun. 655 * A standard Tcl error code. 656 * 657 *------------------------------------------------------* 658 */ 659 660static int 661Decode (ctrlBlock, character, interp, clientData) 662Trf_ControlBlock ctrlBlock; 663unsigned int character; 664Tcl_Interp* interp; 665ClientData clientData; 666{ 667 DecoderControl* c = (DecoderControl*) ctrlBlock; 668 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 669 char buf; 670 671 if (c->operation_mode == ATTACH_WRITE) { 672 buf = character; 673 (*md->updateProc) (c->context, character); 674 675 } else if (c->operation_mode == ATTACH_TRANS) { 676 buf = character; 677 (*md->updateProc) (c->context, character); 678 679 return c->write (c->writeClientData, (unsigned char*) &buf, 1, interp); 680 } else { 681 if (c->charCount == md->digest_size) { 682 /* 683 * ringbuffer full, forward oldest character 684 * and replace with new one. 685 */ 686 687 buf = c->digest_buffer [c->buffer_pos]; 688 689 c->digest_buffer [c->buffer_pos] = character; 690 c->buffer_pos ++; 691 c->buffer_pos %= md->digest_size; 692 693 character = buf; 694 (*md->updateProc) (c->context, character); 695 696 return c->write (c->writeClientData, (unsigned char*) &buf, 1, interp); 697 } else { 698 /* 699 * Fill ringbuffer. 700 */ 701 702 c->digest_buffer [c->buffer_pos] = character; 703 704 c->buffer_pos ++; 705 c->charCount ++; 706 } 707 } 708 709 return TCL_OK; 710} 711 712/* 713 *------------------------------------------------------* 714 * 715 * DecodeBuffer -- 716 * 717 * ------------------------------------------------* 718 * Decode the given buffer and write the result. 719 * ------------------------------------------------* 720 * 721 * Sideeffects: 722 * As of the called WriteFun. 723 * 724 * Result: 725 * Generated bytes implicitly via WriteFun. 726 * A standard Tcl error code. 727 * 728 *------------------------------------------------------* 729 */ 730 731static int 732DecodeBuffer (ctrlBlock, buffer, bufLen, interp, clientData) 733Trf_ControlBlock ctrlBlock; 734unsigned char* buffer; 735int bufLen; 736Tcl_Interp* interp; 737ClientData clientData; 738{ 739 DecoderControl* c = (DecoderControl*) ctrlBlock; 740 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 741 742 if (c->operation_mode == ATTACH_WRITE) { 743 if (*md->updateBufProc != (Trf_MDUpdateBuf*) NULL) { 744 (*md->updateBufProc) (c->context, buffer, bufLen); 745 } else { 746 int character, i; 747 748 for (i=0; i < bufLen; i++) { 749 character = buffer [i]; 750 (*md->updateProc) (c->context, character); 751 } 752 } 753 754 } else if (c->operation_mode == ATTACH_TRANS) { 755 if (*md->updateBufProc != (Trf_MDUpdateBuf*) NULL) { 756 (*md->updateBufProc) (c->context, buffer, bufLen); 757 } else { 758 int character, i; 759 760 for (i=0; i < bufLen; i++) { 761 character = buffer [i]; 762 (*md->updateProc) (c->context, character); 763 } 764 } 765 766 return c->write (c->writeClientData, buffer, bufLen, interp); 767 768 } else { 769 /* try to use more than character at a time. */ 770 771 if (*md->updateBufProc != NULL) { 772 773 /* 774 * 2 cases: 775 * 776 * - Incoming buffer and data stored from previous calls are less 777 * or just enough to fill the ringbuffer. Copy the incoming bytes 778 * into the buffer and return. 779 * 780 * - Incoming data + ringbuffer contain more than reqired for a 781 * digest. Concatenate both and use the oldest bytes to update the 782 * hash context. Place the remaining 'digest_size' bytes into the 783 * ringbuffer again. 784 * 785 * Both cases assume the ringbuffer data to be starting at index '0'. 786 */ 787 788 if ((c->charCount + bufLen) <= md->digest_size) { 789 /* extend ring buffer */ 790 791 memcpy ( (VOID*) (c->digest_buffer + c->charCount), (VOID*) buffer, bufLen); 792 c->charCount += bufLen; 793 } else { 794 /* 795 * n contains the number of bytes we are allowed to hash into the context. 796 */ 797 798 int n = c->charCount + bufLen - md->digest_size; 799 int res; 800 801 if (c->charCount > 0) { 802 if (n <= c->charCount) { 803 /* 804 * update context, then shift down the remaining bytes 805 */ 806 807 (*md->updateBufProc) (c->context, c->digest_buffer, n); 808 809 res = c->write (c->writeClientData, c->digest_buffer, n, interp); 810 811 memmove ((VOID*) c->digest_buffer, 812 (VOID*) (c->digest_buffer + n), c->charCount - n); 813 c->charCount -= n; 814 n = 0; 815 } else { 816 /* 817 * Hash everything inside the buffer. 818 */ 819 820 (*md->updateBufProc) (c->context, c->digest_buffer, c->charCount); 821 822 res = c->write (c->writeClientData, c->digest_buffer, c->charCount, interp); 823 824 n -= c->charCount; 825 c->charCount = 0; 826 } 827 828 if (res != TCL_OK) 829 return res; 830 } 831 832 if (n > 0) { 833 (*md->updateBufProc) (c->context, buffer, n); 834 835 res = c->write (c->writeClientData, buffer, n, interp); 836 837 memcpy ((VOID*) (c->digest_buffer + c->charCount), 838 (VOID*) (buffer + n), 839 (bufLen - n)); 840 c->charCount = md->digest_size; /* <=> 'c->charCount += bufLen - n;' */ 841 842 if (res != TCL_OK) 843 return res; 844 } 845 } 846 } else { 847 /* 848 * no 'updateBufProc', simulate it using the 849 * underlying single character routine 850 */ 851 852 int character, i, res; 853 char buf; 854 855 for (i=0; i < bufLen; i++) { 856 buf = c->digest_buffer [c->buffer_pos]; 857 character = buffer [i]; 858 859 if (c->charCount == md->digest_size) { 860 /* 861 * ringbuffer full, forward oldest character 862 * and replace with new one. 863 */ 864 865 c->digest_buffer [c->buffer_pos] = character; 866 c->buffer_pos ++; 867 c->buffer_pos %= md->digest_size; 868 869 character = buf; 870 (*md->updateProc) (c->context, character); 871 872 res = c->write (c->writeClientData, (unsigned char*) &buf, 1, interp); 873 if (res != TCL_OK) 874 return res; 875 } else { 876 /* 877 * Fill ringbuffer. 878 */ 879 880 c->digest_buffer [c->buffer_pos] = character; 881 882 c->buffer_pos ++; 883 c->charCount ++; 884 } 885 } /* for */ 886 } 887 } 888 889 return TCL_OK; 890} 891 892/* 893 *------------------------------------------------------* 894 * 895 * FlushDecoder -- 896 * 897 * ------------------------------------------------* 898 * Decode an incomplete character sequence (if possible). 899 * ------------------------------------------------* 900 * 901 * Sideeffects: 902 * As of the called WriteFun. 903 * 904 * Result: 905 * Generated bytes implicitly via WriteFun. 906 * A standard Tcl error code. 907 * 908 *------------------------------------------------------* 909 */ 910 911static int 912FlushDecoder (ctrlBlock, interp, clientData) 913Trf_ControlBlock ctrlBlock; 914Tcl_Interp* interp; 915ClientData clientData; 916{ 917 DecoderControl* c = (DecoderControl*) ctrlBlock; 918 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 919 char* digest; 920 int res= TCL_OK; 921 922 /* 923 * Get a bit more, for a trailing \0 in 7.6, see 'WriteDigest' too 924 */ 925 digest = (char*) ckalloc (2 + md->digest_size); 926 (*md->finalProc) (c->context, digest); 927 928 if ((c->operation_mode == ATTACH_WRITE) || 929 (c->operation_mode == ATTACH_TRANS)) { 930 res = WriteDigest (c->vInterp, c->destHandle, c->dest, digest, md); 931 } else if (c->charCount < md->digest_size) { 932 /* 933 * ATTACH_ABSORB, not enough data in input! 934 */ 935 936 if (interp) { 937 Tcl_AppendResult (interp, "not enough bytes in input", (char*) NULL); 938 } 939 940 res = TCL_ERROR; 941 } else { 942 char* result_text; 943 944 if (c->buffer_pos > 0) { 945 /* 946 * Reorder bytes in ringbuffer to form the correct digest. 947 */ 948 949 char* temp; 950 int i,j; 951 952 temp = (char*) ckalloc (md->digest_size); 953 954 for (i= c->buffer_pos, j=0; 955 j < md->digest_size; 956 i = (i+1) % md->digest_size, j++) { 957 temp [j] = c->digest_buffer [i]; 958 } 959 960 memcpy ((VOID*) c->digest_buffer, (VOID*) temp, md->digest_size); 961 ckfree (temp); 962 } 963 964 /* 965 * Compare computed and transmitted checksums. 966 */ 967 968 result_text = (0 == memcmp ((VOID*) digest, (VOID*) c->digest_buffer, md->digest_size) ? 969 "ok" : "failed"); 970 971 Tcl_SetVar (c->vInterp, c->matchFlag, result_text, TCL_GLOBAL_ONLY); 972 } 973 974 ckfree (digest); 975 return res; 976} 977 978/* 979 *------------------------------------------------------* 980 * 981 * ClearDecoder -- 982 * 983 * ------------------------------------------------* 984 * Discard an incomplete character sequence. 985 * ------------------------------------------------* 986 * 987 * Sideeffects: 988 * See above. 989 * 990 * Result: 991 * None. 992 * 993 *------------------------------------------------------* 994 */ 995 996static void 997ClearDecoder (ctrlBlock, clientData) 998Trf_ControlBlock ctrlBlock; 999ClientData clientData; 1000{ 1001 DecoderControl* c = (DecoderControl*) ctrlBlock; 1002 Trf_MessageDigestDescription* md = (Trf_MessageDigestDescription*) clientData; 1003 1004 c->buffer_pos = 0; 1005 c->charCount = 0; 1006 1007 (*md->startProc) (c->context); 1008 memset (c->digest_buffer, '\0', md->digest_size); 1009} 1010 1011/* 1012 *------------------------------------------------------* 1013 * 1014 * WriteDigest -- 1015 * 1016 * ------------------------------------------------* 1017 * Writes the generated digest into the destination 1018 * variable, or channel. 1019 * ------------------------------------------------* 1020 * 1021 * Sideeffects: 1022 * May leave an error message in the 1023 * interpreter result area. 1024 * 1025 * Result: 1026 * A standard Tcl error message. 1027 * 1028 *------------------------------------------------------* 1029 */ 1030 1031static int 1032WriteDigest (interp, destHandle, dest, digest, md) 1033Tcl_Interp* interp; 1034char* destHandle; 1035Tcl_Channel dest; 1036char* digest; 1037Trf_MessageDigestDescription* md; 1038{ 1039 if (destHandle != (char*) NULL) { 1040 1041#if GT81 1042 Tcl_Obj* digestObj = Tcl_NewByteArrayObj (digest, md->digest_size); 1043#else 1044 Tcl_Obj* digestObj = Tcl_NewStringObj (digest, md->digest_size); 1045#endif 1046 Tcl_Obj* result; 1047 1048 /*#if GT81 1049 / * 8.1 and beyond * / 1050 Tcl_IncrRefCount(digestObj); 1051 1052 result = Tcl_SetObjVar2 (interp, destHandle, (char*) NULL, digestObj, 1053 TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY); 1054 #else*/ 1055 /* 8.0 section */ 1056 Tcl_Obj* varName = Tcl_NewStringObj (destHandle, strlen (destHandle)); 1057 1058 Tcl_IncrRefCount(varName); 1059 Tcl_IncrRefCount(digestObj); 1060 1061 result = Tcl_ObjSetVar2 (interp, varName, (Tcl_Obj*) NULL, digestObj, 1062 TCL_LEAVE_ERR_MSG | TCL_GLOBAL_ONLY | 1063 TCL_PARSE_PART1); 1064 Tcl_DecrRefCount(varName); 1065 /*#endif / * GT81 */ 1066 1067 Tcl_DecrRefCount(digestObj); 1068 1069 if (result == (Tcl_Obj*) NULL) { 1070 return TCL_ERROR; 1071 } 1072 } else if (dest != (Tcl_Channel) NULL) { 1073 int res = Tcl_Write (dest, digest, md->digest_size); 1074 1075 if (res < 0) { 1076 if (interp) { 1077 Tcl_AppendResult (interp, 1078 "error writing \"", Tcl_GetChannelName (dest), 1079 "\": ", Tcl_PosixError (interp), (char*) NULL); 1080 } 1081 return TCL_ERROR; 1082 } 1083 } 1084 1085 return TCL_OK; 1086} 1087