1 /*****************************************************************************
2 Major portions of this software are copyrighted by the Medical College
3 of Wisconsin, 1994-2000, and are released under the Gnu General Public
4 License, Version 2. See the file README.Copyright for details.
5 ******************************************************************************/
6
7 #include "stdlib.h"
8
9 typedef unsigned char byte ;
10
11 static int dtable_mode = -1 ; /* 1=encode, 2=decode, -1=neither */
12 static byte dtable[256] ; /* encode/decode table */
13 static int linelen = 72 ; /* line length (max 76) */
14 static int ncrlf = 1 ;
15
16 #define B64_goodchar(c) (dtable[c] != 0x80) /* for decode only */
17
18 #define B64_EOL1 '\r' /* CR */
19 #define B64_EOL2 '\n' /* LF */
20
21 /*----------------------------------------------------------------------*/
22
B64_set_crlf(int nn)23 void B64_set_crlf( int nn )
24 {
25 if( nn >= 1 && nn <= 2 ) ncrlf = nn ;
26 return ;
27 }
28
29 /*----------------------------------------------------------------------*/
30
B64_set_linelen(int ll)31 void B64_set_linelen( int ll )
32 {
33 if( ll >= 16 && ll <= 76 ) linelen = 4*(ll/4) ; /* multiple of 4 */
34 else linelen = 72 ;
35 return ;
36 }
37
38 /*----------------------------------------------------------------------*/
39
load_encode_table(void)40 static void load_encode_table(void)
41 {
42 int i ;
43 if( dtable_mode == 1 ) return ;
44 for (i = 0; i < 26; i++) {
45 dtable[i] = 'A' + i;
46 dtable[26 + i] = 'a' + i;
47 }
48 for (i = 0; i < 10; i++) dtable[52 + i] = '0' + i;
49 dtable[62] = '+'; dtable[63] = '/'; dtable_mode = 1 ;
50 return ;
51 }
52
53 /*----------------------------------------------------------------------*/
54
load_decode_table(void)55 static void load_decode_table(void)
56 {
57 int i;
58 if( dtable_mode == 2 ) return ;
59 for (i = 0 ; i < 255 ; i++) dtable[i] = 0x80; /* bad */
60 for (i = 'A'; i <= 'Z'; i++) dtable[i] = 0 + (i - 'A');
61 for (i = 'a'; i <= 'z'; i++) dtable[i] = 26 + (i - 'a');
62 for (i = '0'; i <= '9'; i++) dtable[i] = 52 + (i - '0');
63 dtable['+'] = 62; dtable['/'] = 63; dtable['='] = 0; dtable_mode = 2 ;
64 return ;
65 }
66
67 #define B64_encode3(a,b,c,w,x,y,z) \
68 ( w = dtable[(a)>>2] , \
69 x = dtable[((a & 3) << 4) | (b >> 4)] , \
70 y = dtable[((b & 0xF) << 2) | (c >> 6)] , \
71 z = dtable[c & 0x3F] )
72
73 #define B64_encode2(a,b,w,x,y,z) \
74 ( B64_encode3(a,b,0,w,x,y,z) , z = '=' )
75
76 #define B64_encode1(a,w,x,y,z) \
77 ( B64_encode3(a,0,0,w,x,y,z) , y=z = '=' )
78
79 #define B64_decode4(w,x,y,z,a,b,c) \
80 ( a = (dtable[w] << 2) | (dtable[x] >> 4) , \
81 b = (dtable[x] << 4) | (dtable[y] >> 2) , \
82 c = (dtable[y] << 6) | dtable[z] )
83
84 #define B64_decode_count(w,x,y,z) \
85 ( ((w)=='='||(x)=='=') ? 0 \
86 : ((y)=='=') ? 1 \
87 : ((z)=='=') ? 2 : 3 )
88
89 /*----------------------------------------------------------------------
90 Convert base64 encoding to a binary array
91
92 Inputs: nb64 = number of bytes in b64
93 b64 = array of base64 encoding bytes
94 values not in the base64 encoding set will be skipped
95
96 Outputs: *nbin = number of binary bytes [*nbin==0 flags an error]
97 *bin = pointer to newly malloc()-ed space with bytes
98 ------------------------------------------------------------------------*/
99
B64_to_binary(int nb64,byte * b64,int * nbin,byte ** bin)100 void B64_to_binary( int nb64 , byte * b64 , int * nbin , byte ** bin )
101 {
102 int ii,jj , nn ;
103 byte a,b,c , w,x,y,z ;
104
105 /*- sanity checks -*/
106
107 if( nbin == NULL || bin == NULL ) return ;
108
109 if( nb64 < 4 || b64 == NULL ){ *nbin = 0 ; *bin = NULL ; return ; }
110
111 *bin = (byte *) malloc(sizeof(byte)*(2+3*nb64/4)) ;
112 if( *bin == NULL ){ *nbin = 0 ; return ; }
113
114 /*- some work -*/
115
116 load_decode_table() ;
117 for( ii=jj=0 ; ii < nb64 ; ){ /* scan inputs, skipping bad characters */
118 w = b64[ii++] ;
119 while( !B64_goodchar(w) && ii < nb64 ) w = b64[ii++] ;
120 x = (ii < nb64) ? b64[ii++] : '=' ;
121 while( !B64_goodchar(x) && ii < nb64 ) x = b64[ii++] ;
122 y = (ii < nb64) ? b64[ii++] : '=' ;
123 while( !B64_goodchar(y) && ii < nb64 ) y = b64[ii++] ;
124 z = (ii < nb64) ? b64[ii++] : '=' ;
125 while( !B64_goodchar(z) && ii < nb64 ) z = b64[ii++] ;
126
127 B64_decode4(w,x,y,z,a,b,c) ;
128
129 if( z == '=' ){ /* got to the end? */
130 nn = B64_decode_count(w,x,y,z) ; /* see how many to save */
131 if( nn > 0 ) (*bin)[jj++] = a ;
132 if( nn > 1 ) (*bin)[jj++] = b ;
133 break ;
134 }
135
136 /* not at the end => save all 3 outputs */
137
138 (*bin)[jj++] = a ; (*bin)[jj++] = b ; (*bin)[jj++] = c ;
139 }
140
141 *bin = (byte *) realloc( *bin , sizeof(byte)*jj ) ;
142 *nbin = jj ;
143 return ;
144 }
145
146 /*----------------------------------------------------------------------
147 Convert binary array to base64 encoding
148
149 Inputs: nbin = number of bytes in bin
150 bin = array of binary bytes to encode
151
152 Outputs: *nb64 = number of base64 bytes [*nb64==0 flags an error]
153 *b64 = pointer to newly malloc()-ed space with bytes
154
155 The output array (*b64) line length can be set by
156 B64_set_linelen(n)
157 where n is from 16 to 76. The default is 72. Note, however, that
158 encoded bytes will always be written out in groups of 4.
159 The output array line separator can be the LF character only (Unix)
160 or the CR-LF combination (DOS, etc.). This is controlled by
161 B64_set_crlf(n)
162 where n=1 for LF, n=2 for CR-LF. The default is LF. The output
163 array will be terminated with a line separator. There will be
164 no ASCII NUL character at the end of *b64 -- that is, the output
165 is not a C string.
166 ------------------------------------------------------------------------*/
167
B64_to_base64(int nbin,byte * bin,int * nb64,byte ** b64)168 void B64_to_base64( int nbin , byte * bin , int * nb64 , byte ** b64 )
169 {
170 int ii,jj , nn,n3 ;
171 byte a,b,c , w,x,y,z ;
172
173 /*- sanity checks -*/
174
175 if( nb64 == NULL || b64 == NULL ) return ;
176 if( nbin <= 0 || bin == NULL ){ *nb64 = 0 ; *b64 = NULL ; return ; }
177
178 nn = (4.0*(linelen+ncrlf+1.0)/(3.0*linelen))*nbin + 256 ;
179 *b64 = (byte *) malloc(sizeof(byte)*nn) ;
180 if( *b64 == NULL ){ *nb64 = 0 ; return ; }
181
182 /*- do blocks of 3 -*/
183
184 load_encode_table() ;
185 n3 = (nbin/3)*3 ;
186 for( nn=jj=ii=0 ; ii < n3 ; ){
187 a = bin[ii++] ; b = bin[ii++] ; c = bin[ii++] ;
188 B64_encode3(a,b,c,w,x,y,z) ;
189 (*b64)[jj++] = w ;
190 (*b64)[jj++] = x ;
191 (*b64)[jj++] = y ;
192 (*b64)[jj++] = z ;
193 nn += 4 ; if( nn >= linelen ){
194 if( ncrlf == 2 ) (*b64)[jj++] = B64_EOL1 ;
195 (*b64)[jj++] = B64_EOL2 ;
196 nn = 0 ;
197 }
198 }
199
200 /*- do the leftovers, if any (1 or 2 bytes) -*/
201
202 if( ii < nbin ){
203 if( ii == nbin-2 )
204 B64_encode2(bin[ii],bin[ii+1],w,x,y,z) ;
205 else
206 B64_encode1(bin[ii],w,x,y,z) ;
207
208 (*b64)[jj++] = w ;
209 (*b64)[jj++] = x ;
210 (*b64)[jj++] = y ;
211 (*b64)[jj++] = z ; nn += 4 ;
212 }
213
214 if( nn > 0 ){
215 if( ncrlf == 2 ) (*b64)[jj++] = B64_EOL1 ;
216 (*b64)[jj++] = B64_EOL2 ;
217 }
218
219 *b64 = (byte *) realloc( *b64 , sizeof(byte)*jj ) ;
220 *nb64 = jj ;
221 return ;
222 }
223