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