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