chiark / gitweb /
Debianization and various other fixes.
[ezmlm] / encodeB.c
1 /* $Id: encodeB.c,v 1.3 1998/03/21 18:30:27 lindberg Exp $*/
2 /* $Name: ezmlm-idx-040 $*/
3
4 #include "stralloc.h"
5 #include "uint32.h"
6 #include "mime.h"
7 #include "strerr.h"
8 #include "errtxt.h"
9
10 static void die_nomem(fatal)
11   char *fatal;
12 {
13   strerr_die2x(111,fatal,ERR_NOMEM);
14 }
15
16 static unsigned char base64char[] =
17    "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
18
19 static unsigned int pos = 0;
20 static unsigned int i = 0;
21 static uint32 hold32;
22 static unsigned char *cpout;
23
24 static void addone(ch)
25 unsigned char ch;
26 {
27  if (!(pos++))
28     hold32 = (uint32) ch;
29   else
30     hold32 = (hold32 << 8) | ch;
31   if (pos == 3) {
32     *cpout++ = base64char[(hold32 >> 18) & 0x3f];
33     *cpout++ = base64char[(hold32 >> 12) & 0x3f];
34     *cpout++ = base64char[(hold32 >>  6) & 0x3f];
35     *cpout++ = base64char[hold32 & 0x3f];
36     if (++i == 18) {
37       *cpout++ = '\n';
38       i = 0;
39     }
40     pos = 0;
41   }
42 }
43
44 static void dorest()
45 {
46   switch (pos) {
47     case 2:
48       hold32 = hold32 << 2;
49       *cpout++ = base64char[(hold32 >> 12) & 0x3f];
50       *cpout++ = base64char[(hold32 >> 06) & 0x3f];
51       *cpout++ = base64char[hold32 & 0x3f];
52       *cpout++ = '=';
53       break;
54     case 1:
55       hold32 = hold32 << 4;
56       *cpout++ = base64char[(hold32 >> 06) & 0x3f];
57       *cpout++ = base64char[hold32 & 0x3f];
58       *cpout++ = '=';
59       *cpout++ = '=';
60       break;
61     default:
62       break;
63   }
64   *cpout++ = '\n';
65 }   
66
67 void encodeB(indata,n,outdata,control,fatal)
68 unsigned char *indata;
69 unsigned int n;
70 stralloc *outdata;
71 int control;    /* 1 = init, 2 = flush */
72 char *fatal;
73         /* converts any character with the high order bit set to */
74         /* base64. In: n chars of indata, out: stralloc outdata  */
75         /* as '=' is not allowed within the block, we cannot flush after */
76         /* each line, so we carry over data from call to call. The last  */
77         /* call to encodeB should have control = 2 to do the flushing.   */
78         /* control = 0 resets, and the routine starts out reset. */
79 {
80   register unsigned char ch;
81
82   if (control == 1) {
83     pos = 0;
84     i = 0;
85   }
86   if (!stralloc_copys(outdata,"")) die_nomem(fatal);
87   if (!stralloc_ready(outdata,n*8/3 + n/72 + 5)) die_nomem(fatal);
88   cpout = (unsigned char *) outdata->s;
89   while (n--) {
90     ch = *indata++;
91     if (ch == '\n')
92       addone('\r');
93     addone(ch);
94   }
95   if (control == 2)
96     dorest();
97   outdata->len = (unsigned int) (cpout - (unsigned char *) outdata->s);
98 }
99