Mercurial > hg > xemacs-beta
comparison lib-src/mmencode.c @ 428:3ecd8885ac67 r21-2-22
Import from CVS: tag r21-2-22
author | cvs |
---|---|
date | Mon, 13 Aug 2007 11:28:15 +0200 |
parents | |
children | a5df635868b2 |
comparison
equal
deleted
inserted
replaced
427:0a0253eac470 | 428:3ecd8885ac67 |
---|---|
1 /* | |
2 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore) | |
3 | |
4 Permission to use, copy, modify, and distribute this material | |
5 for any purpose and without fee is hereby granted, provided | |
6 that the above copyright notice and this permission notice | |
7 appear in all copies, and that the name of Bellcore not be | |
8 used in advertising or publicity pertaining to this | |
9 material without the specific, prior written permission | |
10 of an authorized representative of Bellcore. BELLCORE | |
11 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY | |
12 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", | |
13 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. | |
14 */ | |
15 | |
16 #define NEWLINE_CHAR '\n' | |
17 #include <stdlib.h> | |
18 #include <stdio.h> | |
19 #include <ctype.h> | |
20 #include <string.h> | |
21 | |
22 static void | |
23 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile); | |
24 | |
25 static signed char basis_64[] = | |
26 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; | |
27 | |
28 static signed char index_64[128] = { | |
29 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, | |
30 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, | |
31 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63, | |
32 52,53,54,55, 56,57,58,59, 60,61,-1,-1, -1,-1,-1,-1, | |
33 -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,10, 11,12,13,14, | |
34 15,16,17,18, 19,20,21,22, 23,24,25,-1, -1,-1,-1,-1, | |
35 -1,26,27,28, 29,30,31,32, 33,34,35,36, 37,38,39,40, | |
36 41,42,43,44, 45,46,47,48, 49,50,51,-1, -1,-1,-1,-1 | |
37 }; | |
38 | |
39 #define char64(c) (((c) < 0 || (c) > 127) ? -1 : index_64[(c)]) | |
40 | |
41 /* | |
42 char64(c) | |
43 char c; | |
44 { | |
45 char *s = (char *) strchr(basis_64, c); | |
46 if (s) return(s-basis_64); | |
47 return(-1); | |
48 } | |
49 */ | |
50 | |
51 /* the following gets a character, but fakes it properly into two chars if there's a newline character */ | |
52 static int InNewline=0; | |
53 | |
54 static int | |
55 nextcharin (FILE *infile, int PortableNewlines) | |
56 { | |
57 int c; | |
58 | |
59 #ifndef NEWLINE_CHAR | |
60 return(getc(infile)); | |
61 #else | |
62 if (!PortableNewlines) return(getc(infile)); | |
63 if (InNewline) { | |
64 InNewline = 0; | |
65 return(10); /* LF */ | |
66 } | |
67 c = getc(infile); | |
68 if (c == NEWLINE_CHAR) { | |
69 InNewline = 1; | |
70 return(13); /* CR */ | |
71 } | |
72 return(c); | |
73 #endif | |
74 } | |
75 | |
76 static void | |
77 to64(FILE *infile, FILE *outfile, int PortableNewlines) | |
78 { | |
79 int c1, c2, c3, ct=0; | |
80 InNewline = 0; /* always reset it */ | |
81 while ((c1 = nextcharin(infile, PortableNewlines)) != EOF) { | |
82 c2 = nextcharin(infile, PortableNewlines); | |
83 if (c2 == EOF) { | |
84 output64chunk(c1, 0, 0, 2, outfile); | |
85 } else { | |
86 c3 = nextcharin(infile, PortableNewlines); | |
87 if (c3 == EOF) { | |
88 output64chunk(c1, c2, 0, 1, outfile); | |
89 } else { | |
90 output64chunk(c1, c2, c3, 0, outfile); | |
91 } | |
92 } | |
93 ct += 4; | |
94 if (ct > 71) { | |
95 putc('\n', outfile); | |
96 ct = 0; | |
97 } | |
98 } | |
99 if (ct) putc('\n', outfile); | |
100 fflush(outfile); | |
101 } | |
102 | |
103 static void | |
104 output64chunk(int c1, int c2, int c3, int pads, FILE *outfile) | |
105 { | |
106 putc(basis_64[c1>>2], outfile); | |
107 putc(basis_64[((c1 & 0x3)<< 4) | ((c2 & 0xF0) >> 4)], outfile); | |
108 if (pads == 2) { | |
109 putc('=', outfile); | |
110 putc('=', outfile); | |
111 } else if (pads) { | |
112 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile); | |
113 putc('=', outfile); | |
114 } else { | |
115 putc(basis_64[((c2 & 0xF) << 2) | ((c3 & 0xC0) >>6)], outfile); | |
116 putc(basis_64[c3 & 0x3F], outfile); | |
117 } | |
118 } | |
119 | |
120 static int | |
121 PendingBoundary(char *s, char **Boundaries, int *BoundaryCt) | |
122 { | |
123 int i, len; | |
124 | |
125 if (s[0] != '-' || s[1] != '-') return(0); | |
126 | |
127 | |
128 for (i=0; i < *BoundaryCt; ++i) { | |
129 len = strlen(Boundaries[i]); | |
130 if (!strncmp(s, Boundaries[i], len)) { | |
131 if (s[len] == '-' && s[len+1] == '-') *BoundaryCt = i; | |
132 return(1); | |
133 } | |
134 } | |
135 return(0); | |
136 } | |
137 | |
138 /* If we're in portable newline mode, we have to convert CRLF to the | |
139 local newline convention on output */ | |
140 | |
141 static int CRpending = 0; | |
142 | |
143 #ifdef NEWLINE_CHAR | |
144 static void | |
145 almostputc(int c, FILE *outfile, int PortableNewlines) | |
146 { | |
147 if (CRpending) { | |
148 if (c == 10) { | |
149 putc(NEWLINE_CHAR, outfile); | |
150 CRpending = 0; | |
151 } else { | |
152 putc(13, outfile); | |
153 if (c != 13) { | |
154 putc(c, outfile); | |
155 CRpending = 0; | |
156 } | |
157 } | |
158 } else { | |
159 if (PortableNewlines && c == 13) { | |
160 CRpending = 1; | |
161 } else { | |
162 putc(c, outfile); | |
163 } | |
164 } | |
165 } | |
166 #else | |
167 static void | |
168 almostputc(int c, FILE *outfile, int PortableNewlines) | |
169 { | |
170 putc(c, outfile); | |
171 } | |
172 #endif | |
173 | |
174 static void | |
175 from64(FILE *infile, FILE *outfile, | |
176 char **boundaries, int *boundaryct, int PortableNewlines) | |
177 { | |
178 int c1, c2, c3, c4; | |
179 int newline = 1, DataDone = 0; | |
180 | |
181 /* always reinitialize */ | |
182 CRpending = 0; | |
183 while ((c1 = getc(infile)) != EOF) { | |
184 if (isspace(c1)) { | |
185 if (c1 == '\n') { | |
186 newline = 1; | |
187 } else { | |
188 newline = 0; | |
189 } | |
190 continue; | |
191 } | |
192 if (newline && boundaries && c1 == '-') { | |
193 char Buf[200]; | |
194 /* a dash is NOT base 64, so all bets are off if NOT a boundary */ | |
195 ungetc(c1, infile); | |
196 fgets(Buf, sizeof(Buf), infile); | |
197 if (boundaries | |
198 && (Buf[0] == '-') | |
199 && (Buf[1] == '-') | |
200 && PendingBoundary(Buf, boundaries, boundaryct)) { | |
201 return; | |
202 } | |
203 fprintf(stderr, "Ignoring unrecognized boundary line: %s\n", Buf); | |
204 continue; | |
205 } | |
206 if (DataDone) continue; | |
207 newline = 0; | |
208 do { | |
209 c2 = getc(infile); | |
210 } while (c2 != EOF && isspace(c2)); | |
211 do { | |
212 c3 = getc(infile); | |
213 } while (c3 != EOF && isspace(c3)); | |
214 do { | |
215 c4 = getc(infile); | |
216 } while (c4 != EOF && isspace(c4)); | |
217 if (c2 == EOF || c3 == EOF || c4 == EOF) { | |
218 fprintf(stderr, "Warning: base64 decoder saw premature EOF!\n"); | |
219 return; | |
220 } | |
221 if (c1 == '=' || c2 == '=') { | |
222 DataDone=1; | |
223 continue; | |
224 } | |
225 c1 = char64(c1); | |
226 c2 = char64(c2); | |
227 almostputc(((c1<<2) | ((c2&0x30)>>4)), outfile, PortableNewlines); | |
228 if (c3 == '=') { | |
229 DataDone = 1; | |
230 } else { | |
231 c3 = char64(c3); | |
232 almostputc((((c2&0XF) << 4) | ((c3&0x3C) >> 2)), outfile, PortableNewlines); | |
233 if (c4 == '=') { | |
234 DataDone = 1; | |
235 } else { | |
236 c4 = char64(c4); | |
237 almostputc((((c3&0x03) <<6) | c4), outfile, PortableNewlines); | |
238 } | |
239 } | |
240 } | |
241 if (CRpending) putc(13, outfile); /* Don't drop a lone trailing char 13 */ | |
242 } | |
243 | |
244 static signed char basis_hex[] = "0123456789ABCDEF"; | |
245 static signed char index_hex[128] = { | |
246 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, | |
247 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, | |
248 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, | |
249 0, 1, 2, 3, 4, 5, 6, 7, 8, 9,-1,-1, -1,-1,-1,-1, | |
250 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, | |
251 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, | |
252 -1,10,11,12, 13,14,15,-1, -1,-1,-1,-1, -1,-1,-1,-1, | |
253 -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1 | |
254 }; | |
255 | |
256 /* The following version generated complaints on Solaris. */ | |
257 /* #define hexchar(c) (((c) < 0 || (c) > 127) ? -1 : index_hex[(c)]) */ | |
258 /* Since we're no longer ever calling it with anything signed, this should work: */ | |
259 #define hexchar(c) (((c) > 127) ? -1 : index_hex[(c)]) | |
260 | |
261 /* | |
262 hexchar(c) | |
263 char c; | |
264 { | |
265 char *s; | |
266 if (islower(c)) c = toupper(c); | |
267 s = (char *) strchr(basis_hex, c); | |
268 if (s) return(s-basis_hex); | |
269 return(-1); | |
270 } | |
271 */ | |
272 | |
273 static void | |
274 toqp(FILE *infile, FILE *outfile) | |
275 { | |
276 int c, ct=0, prevc=255; | |
277 while ((c = getc(infile)) != EOF) { | |
278 if ((c < 32 && (c != '\n' && c != '\t')) | |
279 || (c == '=') | |
280 || (c >= 127) | |
281 /* Following line is to avoid single periods alone on lines, | |
282 which messes up some dumb smtp implementations, sigh... */ | |
283 || (ct == 0 && c == '.')) { | |
284 putc('=', outfile); | |
285 putc(basis_hex[c>>4], outfile); | |
286 putc(basis_hex[c&0xF], outfile); | |
287 ct += 3; | |
288 prevc = 'A'; /* close enough */ | |
289 } else if (c == '\n') { | |
290 if (prevc == ' ' || prevc == '\t') { | |
291 putc('=', outfile); /* soft & hard lines */ | |
292 putc(c, outfile); | |
293 } | |
294 putc(c, outfile); | |
295 ct = 0; | |
296 prevc = c; | |
297 } else { | |
298 if (c == 'F' && prevc == '\n') { | |
299 /* HORRIBLE but clever hack suggested by MTR for sendmail-avoidance */ | |
300 c = getc(infile); | |
301 if (c == 'r') { | |
302 c = getc(infile); | |
303 if (c == 'o') { | |
304 c = getc(infile); | |
305 if (c == 'm') { | |
306 c = getc(infile); | |
307 if (c == ' ') { | |
308 /* This is the case we are looking for */ | |
309 fputs("=46rom", outfile); | |
310 ct += 6; | |
311 } else { | |
312 fputs("From", outfile); | |
313 ct += 4; | |
314 } | |
315 } else { | |
316 fputs("Fro", outfile); | |
317 ct += 3; | |
318 } | |
319 } else { | |
320 fputs("Fr", outfile); | |
321 ct += 2; | |
322 } | |
323 } else { | |
324 putc('F', outfile); | |
325 ++ct; | |
326 } | |
327 ungetc(c, infile); | |
328 prevc = 'x'; /* close enough -- printable */ | |
329 } else { /* END horrible hack */ | |
330 putc(c, outfile); | |
331 ++ct; | |
332 prevc = c; | |
333 } | |
334 } | |
335 if (ct > 72) { | |
336 putc('=', outfile); | |
337 putc('\n', outfile); | |
338 ct = 0; | |
339 prevc = '\n'; | |
340 } | |
341 } | |
342 if (ct) { | |
343 putc('=', outfile); | |
344 putc('\n', outfile); | |
345 } | |
346 } | |
347 | |
348 static void | |
349 fromqp(FILE *infile, FILE *outfile, char **boundaries, int *boundaryct) | |
350 { | |
351 unsigned int c1, c2; | |
352 int sawnewline = 1, neednewline = 0; | |
353 /* The neednewline hack is necessary because the newline leading into | |
354 a multipart boundary is part of the boundary, not the data */ | |
355 | |
356 while ((c1 = getc(infile)) != EOF) { | |
357 if (sawnewline && boundaries && (c1 == '-')) { | |
358 char Buf[200]; | |
359 unsigned char *s; | |
360 | |
361 ungetc(c1, infile); | |
362 fgets(Buf, sizeof(Buf), infile); | |
363 if (boundaries | |
364 && (Buf[0] == '-') | |
365 && (Buf[1] == '-') | |
366 && PendingBoundary(Buf, boundaries, boundaryct)) { | |
367 return; | |
368 } | |
369 /* Not a boundary, now we must treat THIS line as q-p, sigh */ | |
370 if (neednewline) { | |
371 putc('\n', outfile); | |
372 neednewline = 0; | |
373 } | |
374 for (s=(unsigned char *) Buf; *s; ++s) { | |
375 if (*s == '=') { | |
376 if (!*++s) break; | |
377 if (*s == '\n') { | |
378 /* ignore it */ | |
379 sawnewline = 1; | |
380 } else { | |
381 c1 = hexchar(*s); | |
382 if (!*++s) break; | |
383 c2 = hexchar(*s); | |
384 putc(c1<<4 | c2, outfile); | |
385 } | |
386 } else { | |
387 #ifdef MSDOS | |
388 if (*s == '\n') | |
389 putc('\r', outfile); /* insert CR for binary-mode write */ | |
390 #endif | |
391 putc(*s, outfile); | |
392 } | |
393 } | |
394 } else { | |
395 if (neednewline) { | |
396 putc('\n', outfile); | |
397 neednewline = 0; | |
398 } | |
399 if (c1 == '=') { | |
400 sawnewline = 0; | |
401 c1 = getc(infile); | |
402 if (c1 == '\n') { | |
403 /* ignore it */ | |
404 sawnewline = 1; | |
405 } else { | |
406 c2 = getc(infile); | |
407 c1 = hexchar(c1); | |
408 c2 = hexchar(c2); | |
409 putc(c1<<4 | c2, outfile); | |
410 if (c2 == '\n') sawnewline = 1; | |
411 } | |
412 } else { | |
413 if (c1 == '\n') { | |
414 sawnewline = 1; | |
415 neednewline = 1; | |
416 } else { | |
417 sawnewline = 0; | |
418 putc(c1, outfile); | |
419 } | |
420 } | |
421 } | |
422 } | |
423 if (neednewline) { | |
424 putc('\n', outfile); | |
425 neednewline = 0; | |
426 } | |
427 } | |
428 | |
429 | |
430 /* | |
431 Copyright (c) 1991 Bell Communications Research, Inc. (Bellcore) | |
432 | |
433 Permission to use, copy, modify, and distribute this material | |
434 for any purpose and without fee is hereby granted, provided | |
435 that the above copyright notice and this permission notice | |
436 appear in all copies, and that the name of Bellcore not be | |
437 used in advertising or publicity pertaining to this | |
438 material without the specific, prior written permission | |
439 of an authorized representative of Bellcore. BELLCORE | |
440 MAKES NO REPRESENTATIONS ABOUT THE ACCURACY OR SUITABILITY | |
441 OF THIS MATERIAL FOR ANY PURPOSE. IT IS PROVIDED "AS IS", | |
442 WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES. | |
443 */ | |
444 #ifdef MSDOS | |
445 #include <fcntl.h> | |
446 #endif | |
447 | |
448 #define BASE64 1 | |
449 #define QP 2 /* quoted-printable */ | |
450 | |
451 int main(int argc, char *argv[]) | |
452 { | |
453 int encode = 1, which = BASE64, i, portablenewlines = 0; | |
454 FILE *fp = stdin; | |
455 FILE *fpo = stdout; | |
456 | |
457 for (i=1; i<argc; ++i) { | |
458 if (argv[i][0] == '-') { | |
459 switch (argv[i][1]) { | |
460 case 'o': | |
461 if (++i >= argc) { | |
462 fprintf(stderr, "mimencode: -o requires a file name.\n"); | |
463 exit(-1); | |
464 } | |
465 fpo = fopen(argv[i], "w"); | |
466 if (!fpo) { | |
467 perror(argv[i]); | |
468 exit(-1); | |
469 } | |
470 break; | |
471 case 'u': | |
472 encode = 0; | |
473 break; | |
474 case 'q': | |
475 which = QP; | |
476 break; | |
477 case 'p': | |
478 portablenewlines = 1; | |
479 break; | |
480 case 'b': | |
481 which = BASE64; | |
482 break; | |
483 default: | |
484 fprintf(stderr, | |
485 "Usage: mmencode [-u] [-q] [-b] [-p] [-o outputfile] [file name]\n"); | |
486 exit(-1); | |
487 } | |
488 } else { | |
489 #ifdef MSDOS | |
490 if (encode) | |
491 fp = fopen(argv[i], "rb"); | |
492 else | |
493 { | |
494 fp = fopen(argv[i], "rt"); | |
495 setmode(fileno(fpo), O_BINARY); | |
496 } /* else */ | |
497 #else | |
498 fp = fopen(argv[i], "r"); | |
499 #endif /* MSDOS */ | |
500 if (!fp) { | |
501 perror(argv[i]); | |
502 exit(-1); | |
503 } | |
504 } | |
505 } | |
506 #ifdef MSDOS | |
507 if (fp == stdin) setmode(fileno(fp), O_BINARY); | |
508 #endif /* MSDOS */ | |
509 if (which == BASE64) { | |
510 if (encode) { | |
511 to64(fp, fpo, portablenewlines); | |
512 } else { | |
513 from64(fp,fpo, (char **) NULL, (int *) 0, portablenewlines); | |
514 } | |
515 } else { | |
516 if (encode) toqp(fp, fpo); else fromqp(fp, fpo, NULL, 0); | |
517 } | |
518 return(0); | |
519 } | |
520 |