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