1 /*
2  * util.c --
3  *
4  *	Implements helper procedures used by 3->4 encoders (uu, base64)
5  *	and other useful things.
6  *
7  *
8  * Copyright (c) 1996 Andreas Kupries (andreas_kupries@users.sourceforge.net)
9  * All rights reserved.
10  *
11  * Permission is hereby granted, without written agreement and without
12  * license or royalty fees, to use, copy, modify, and distribute this
13  * software and its documentation for any purpose, provided that the
14  * above copyright notice and the following two paragraphs appear in
15  * all copies of this software.
16  *
17  * IN NO EVENT SHALL I LIABLE TO ANY PARTY FOR DIRECT, INDIRECT, SPECIAL,
18  * INCIDENTAL, OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OF THIS
19  * SOFTWARE AND ITS DOCUMENTATION, EVEN IF I HAVE BEEN ADVISED OF THE
20  * POSSIBILITY OF SUCH DAMAGE.
21  *
22  * I SPECIFICALLY DISCLAIM ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
23  * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE.  THE SOFTWARE PROVIDED HEREUNDER IS ON AN "AS IS" BASIS, AND
25  * I HAVE NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES,
26  * ENHANCEMENTS, OR MODIFICATIONS.
27  *
28  * CVS: $Id: util.c,v 1.9 2007/10/05 23:12:24 andreas_kupries Exp $
29  */
30 
31 #include "transformInt.h"
32 
33 static void
34 Split _ANSI_ARGS_ ((CONST char* in, char* out));
35 
36 
37 /*
38  *------------------------------------------------------*
39  *
40  *	TrfSplit3to4 --
41  *
42  *	------------------------------------------------*
43  *	Splits every 3 bytes of input into 4 bytes,
44  *	actually 6-bit values and places them in the
45  *	target.  Padding at the end is done with a value
46  *	of '64' (6 bit -> values in range 0..63).
47  *	This feature is used by 'TrfApplyEncoding'.
48  *	'length' must be in the range 1, ..., 3.
49  *	------------------------------------------------*
50  *
51  *	Sideeffects:
52  *		'out' is changed.
53  *
54  *	Result:
55  *		See above.
56  *
57  *
58  *------------------------------------------------------*
59  */
60 
61 void
TrfSplit3to4(in,out,length)62 TrfSplit3to4 (in, out, length)
63 CONST unsigned char*  in;
64 unsigned char*       out;
65 int               length;
66 {
67   if (length == 3) {
68     Split ((char*) in, (char*) out);
69   } else {
70     char buf [3];
71 
72     /* expand incomplete sequence with with '\0' */
73     memset (buf, '\0', 3);
74     memcpy (buf, in,   length);
75 
76     Split (buf, (char*) out);
77 
78     switch (length) {
79     case 1:
80       out [2] = 64;
81       out [3] = 64;
82       break;
83 
84     case 2:
85       out [3] = 64;
86       break;
87 
88     case 0:
89     default:
90       /* should not happen */
91       Tcl_Panic ("illegal length given to TrfSplit3to4");
92     }
93   }
94 }
95 
96 /*
97  *------------------------------------------------------*
98  *
99  *	TrfMerge4to3 --
100  *
101  *	------------------------------------------------*
102  *	takes 4 bytes from 'in' (6-bit values) and
103  *	merges them into 3 bytes (8-bit values).
104  *	------------------------------------------------*
105  *
106  *	Sideeffects:
107  *		The generated bytes are written to 'out'.
108  *
109  *	Results:
110  *		See above.
111  *
112  *------------------------------------------------------*
113  */
114 
115 void
TrfMerge4to3(in,out)116 TrfMerge4to3 (in, out)
117 CONST unsigned char* in;
118 unsigned char*       out;
119 {
120 #define	TRF_MASK(i,by,mask) ((in [i] by) & mask)
121 
122   /*
123    * use temp storage to prevent problems in case of
124    * 'in', 'out' overlapping each other.
125    */
126 
127   unsigned char o1, o2, o3;
128 
129   o1 = TRF_MASK (0, << 2, 0374) | TRF_MASK (1, >> 4, 003);
130   o2 = TRF_MASK (1, << 4, 0360) | TRF_MASK (2, >> 2, 017);
131   o3 = TRF_MASK (2, << 6, 0300) | TRF_MASK (3, >> 0, 077);
132 
133   out [0] = o1;
134   out [1] = o2;
135   out [2] = o3;
136 
137 #undef TRF_MASK
138 }
139 
140 /*
141  *------------------------------------------------------*
142  *
143  *	 --
144  *
145  *	------------------------------------------------*
146  *	transform 6-bit values into real characters
147  *	according to the specified character-mapping.
148  *	The map HAS TO contain at least 65 characters,
149  *	the last one being the PAD character to use.
150  *	------------------------------------------------*
151  *
152  *	Sideeffects:
153  *		The characters are read from and written
154  *		to 'buf'.
155  *
156  *	Results:
157  *		See above.
158  *
159  *------------------------------------------------------*
160  */
161 
162 void
TrfApplyEncoding(buf,length,map)163 TrfApplyEncoding (buf, length, map)
164 unsigned char* buf;
165 int            length;
166 CONST char*    map;
167 {
168   int i;
169 
170   for (i=0; i < length; i++) {
171     buf [i] = map [buf [i]];
172   }
173 }
174 
175 /*
176  *------------------------------------------------------*
177  *
178  *	TrfReverseEncoding --
179  *
180  *	------------------------------------------------*
181  *	The given string is converted in place into its
182  *	equivalent binary representation.  The procedure
183  *	assummes the string to be encoded with a 3->4
184  *	byte scheme (such as uuencding, base64).
185  *
186  *	The map HAS TO contain at least 256 characters.
187  *      It is indexed by an 8 bit value to get the 6-bit
188  *	binary field corresponding to that value.  Any
189  *	illegal characters must have the high bit set.
190  *	------------------------------------------------*
191  *
192  *	Sideeffects:
193  *		The characters are read from and written
194  *		to 'buf'.
195  *
196  *	Result:
197  *		A standard TCL error code
198  *		'hasPadding' returns the number unused
199  *		bytes in buf (0..3).
200  *
201  *------------------------------------------------------*
202  */
203 
204 int
TrfReverseEncoding(buf,length,reverseMap,padChar,hasPadding)205 TrfReverseEncoding (buf, length, reverseMap, padChar, hasPadding)
206 unsigned char* buf;
207 int            length;
208 CONST char*    reverseMap;
209 unsigned int   padChar;
210 int*           hasPadding;
211 {
212   /*
213    * length has to be in the range 1..4.
214    */
215 
216   int i, pad, maplen;
217 
218   if ((length < 1) || (length > 4)) {
219     Tcl_Panic ("illegal length given to TrfReverseEncoding");
220   }
221 
222   pad = 4 - length;
223 
224   /* check for more pad chars */
225 
226   for (i=length-1;
227        (i >= 0) && (padChar == buf [i]);
228        pad++, i--) {
229     buf [i] = '\0';
230   }
231 
232   if (pad > 2)
233     /*
234      * Only xxxx, xxx= and xx== allowed
235      * (with x as legal character and = as pad-char.
236      */
237     return TCL_ERROR;
238 
239   *hasPadding = pad;
240 
241   maplen = i+1;
242 
243   /* convert characters to 6-bit values */
244 
245   for (i=0; i < maplen; i++) {
246     char tmp = reverseMap [buf [i]];
247 
248     if (tmp & 0x80)
249       /* high-bit set? => illegal character */
250       return TCL_ERROR;
251 
252     buf [i] = tmp;
253   }
254 
255   return TCL_OK;
256 }
257 
258 /*
259  *------------------------------------------------------*
260  *
261  *	Split --
262  *
263  *	------------------------------------------------*
264  *	takes 3 bytes from 'in', splits them into
265  *	4 6-bit values and places them then into 'out'.
266  *	------------------------------------------------*
267  *
268  *	Sideeffects:
269  *		The generated characters are written to
270  *		'out'.
271  *
272  *	Results:
273  *		See above.
274  *
275  *------------------------------------------------------*
276  */
277 
278 static void
Split(in,out)279 Split (in, out)
280 CONST char* in;
281 char*       out;
282 {
283   out [0] = (077 &   (in [0] >> 2));
284   out [1] = (077 & (((in [0] << 4) & 060) | ((in [1] >> 4) & 017)));
285   out [2] = (077 & (((in [1] << 2) & 074) | ((in [2] >> 6) &  03)));
286   out [3] = (077 &   (in [2] & 077));
287 }
288 
289 /*
290  *------------------------------------------------------*
291  *
292  *	Trf_XorBuffer --
293  *
294  *	------------------------------------------------*
295  *	Do an 'exclusive or' of all 'length' bytes in
296  *	'buffer' with the corresponding bytes in 'mask'.
297  *	------------------------------------------------*
298  *
299  *	Sideeffects:
300  *		See above.
301  *
302  *	Result:
303  *		None.
304  *
305  *------------------------------------------------------*
306  */
307 
308 void
Trf_XorBuffer(buffer,mask,length)309 Trf_XorBuffer (buffer, mask, length)
310 VOID* buffer;
311 VOID* mask;
312 int   length;
313 {
314   unsigned char* b = (unsigned char*) buffer;
315   unsigned char* m = (unsigned char*) mask;
316 
317   while (length > 0) {
318     *b++ ^= *m++;
319     length --;
320   }
321 }
322 
323 /*
324  *------------------------------------------------------*
325  *
326  *	Trf_ShiftRegister --
327  *
328  *	------------------------------------------------*
329  *	Take the 'shift' leftmost bytes of 'mask' and
330  *	shift them into the rightmost bytes of 'buffer'.
331  *	The leftmost bytes of 'buffer' are lost.  Both
332  *	buffers are assumed to be of size 'length'.
333  *	------------------------------------------------*
334  *
335  *	Sideeffects:
336  *		See above.
337  *
338  *	Result:
339  *		none.
340  *
341  *------------------------------------------------------*
342  */
343 
344 void
Trf_ShiftRegister(buffer,mask,shift,length)345 Trf_ShiftRegister (buffer, mask, shift, length)
346 VOID* buffer;
347 VOID* mask;
348 int   shift;
349 int   length;
350 {
351   assert (shift > 0);
352 
353   if (shift == length) {
354       /*
355        * Special case: Drop the whole old register.
356        */
357 
358     memcpy (buffer, mask, length);
359   } else {
360     unsigned char* b = (unsigned char*) buffer;
361     unsigned char* m = (unsigned char*) mask;
362 
363     int retained;
364 
365     /* number bytes in 'buffer' to retain */
366     retained = length - shift;
367 
368     /* left-shift retained bytes of 'buffer' over by
369      * 'shift' bytes to create space for new bytes
370      */
371 
372     while (retained --) {
373       *b = *(b + shift);
374       b ++;
375     }
376 
377     /* now copy 'shift' bytes from 'input' to shifted tail of 'buffer' */
378     do {
379       *b++ = *m++;
380     } while (--shift);
381   }
382 }
383 
384 /*
385  *------------------------------------------------------*
386  *
387  *	Trf_FlipRegisterShort --
388  *
389  *	------------------------------------------------*
390  *	Swap the bytes for all 2-Byte words contained in
391  *	the register.
392  *	------------------------------------------------*
393  *
394  *	Sideeffects:
395  *		See above.
396  *
397  *	Result:
398  *		none.
399  *
400  *------------------------------------------------------*
401  */
402 
403 void
Trf_FlipRegisterShort(buffer,length)404 Trf_FlipRegisterShort (buffer, length)
405 VOID* buffer;
406 int   length;
407 {
408   unsigned char  tmp;
409   unsigned char* b = (unsigned char*) buffer;
410   int n_shorts     = length / 2;
411   int i;
412 
413   for (i=0; i < n_shorts; i++, b+= 2) {
414     tmp = b [0]; b [0] = b [1]; b [1] = tmp;
415   }
416 }
417 
418 /*
419  *------------------------------------------------------*
420  *
421  *	Trf_FlipRegisterLong --
422  *
423  *	------------------------------------------------*
424  *	Swap the bytes for all 4-Byte words contained in
425  *	the register.
426  *	------------------------------------------------*
427  *
428  *	Sideeffects:
429  *		See above.
430  *
431  *	Result:
432  *		none.
433  *
434  *------------------------------------------------------*
435  */
436 
437 void
Trf_FlipRegisterLong(buffer,length)438 Trf_FlipRegisterLong (buffer, length)
439 VOID* buffer;
440 int   length;
441 {
442   unsigned char  tmp;
443   unsigned char* b = (unsigned char*) buffer;
444   int n_longs      = length / 4;
445   int i;
446 
447   /*
448    * 0 -> 3
449    * 1 -> 2
450    * 2 -> 1
451    * 3 -> 0
452    */
453 
454   for (i=0; i < n_longs; i++, b+= 4) {
455     tmp = b [0]; b [0] = b [3]; b [3] = tmp;
456     tmp = b [1]; b [1] = b [2]; b [2] = tmp;
457   }
458 }
459 
460 /*
461  *------------------------------------------------------*
462  */
463 /* internal procedures, for testing */
464 
465 void
TrfDumpHex(f,buffer,length,next)466 TrfDumpHex (f, buffer, length, next)
467 FILE* f;
468 VOID* buffer;
469 int   length;
470 int   next;
471 {
472   short i;
473   unsigned char* b = (unsigned char*) buffer;
474 
475   for (i=0; i < length; i++) fprintf (f, "%02x", (unsigned int) (b [i]));
476   switch (next) {
477   case 0: break;
478   case 1: fprintf (f, "   ");  break;
479   case 2: fprintf (f, "\n"); break;
480   }
481 }
482 
483 
484 void
TrfDumpShort(f,buffer,length,next)485 TrfDumpShort (f, buffer, length, next)
486 FILE* f;
487 VOID* buffer;
488 int   length;
489 int   next;
490 {
491   short i;
492   unsigned short* b = (unsigned short*) buffer;
493 
494   for (i=0; i < (length/2); i++) fprintf (f, "%06d ", (unsigned int) (b [i]));
495   switch (next) {
496   case 0: break;
497   case 1: fprintf (f, "   ");  break;
498   case 2: fprintf (f, "\n"); break;
499   }
500 }
501