1 /*
2     Copyright (C) 2000 Masanao Izumo <mo@goice.co.jp>
3 
4     This program is free software; you can redistribute it and/or modify
5     it under the terms of the GNU General Public License as published by
6     the Free Software Foundation; either version 2 of the License, or
7     (at your option) any later version.
8 
9     This program is distributed in the hope that it will be useful,
10     but WITHOUT ANY WARRANTY; without even the implied warranty of
11     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12     GNU General Public License for more details.
13 
14     You should have received a copy of the GNU General Public License
15     along with this program; if not, write to the Free Software
16     Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
17 */
18 
19 #include "config.h"
20 #include <stdio.h>
21 #include <stdlib.h>
22 #ifndef NO_STRING_H
23 #include <string.h>
24 #else
25 #include <strings.h>
26 #endif
27 #include "libarc/url.h"
28 
29 #define DECODEBUFSIZ 255 /* Must be power of 3 */
30 
31 typedef struct _URL_b64decode
32 {
33     char common[sizeof(struct _URL)];
34     URL reader;
35     long rpos;
36     int beg, end, eof, eod;
37     unsigned char decodebuf[DECODEBUFSIZ];
38     int autoclose;
39 } URL_b64decode;
40 
41 static long url_b64decode_read(URL url, void *buff, long n);
42 static int  url_b64decode_fgetc(URL url);
43 static long url_b64decode_tell(URL url);
44 static void url_b64decode_close(URL url);
45 
url_b64decode_open(URL reader,int autoclose)46 URL url_b64decode_open(URL reader, int autoclose)
47 {
48     URL_b64decode *url;
49 
50     url = (URL_b64decode *)alloc_url(sizeof(URL_b64decode));
51     if(url == NULL)
52     {
53 	if(autoclose)
54 	    url_close(reader);
55 	url_errno = errno;
56 	return NULL;
57     }
58 
59     /* common members */
60     URLm(url, type)      = URL_b64decode_t;
61     URLm(url, url_read)  = url_b64decode_read;
62     URLm(url, url_gets)  = NULL;
63     URLm(url, url_fgetc) = url_b64decode_fgetc;
64     URLm(url, url_seek)  = NULL;
65     URLm(url, url_tell)  = url_b64decode_tell;
66     URLm(url, url_close) = url_b64decode_close;
67 
68     /* private members */
69     url->reader = reader;
70     url->rpos = 0;
71     url->beg = 0;
72     url->end = 0;
73     url->eof = url->eod = 0;
74     memset(url->decodebuf, 0, sizeof(url->decodebuf));
75     url->autoclose = autoclose;
76 
77     return (URL)url;
78 }
79 
b64getchar(URL reader)80 static int b64getchar(URL reader)
81 {
82     int c;
83     static int b64_decode_table[256] =
84     {
85 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
86 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 62, 0, 0,
87 	0, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 0, 0, 0, EOF, 0, 0, 0,
88 	0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19,
89 	20, 21, 22, 23, 24, 25, 0, 0, 0, 0, 0, 0, 26, 27, 28, 29, 30, 31, 32,
90 	33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49,
91 	50, 51, 0, 0, 0, 0, 0
92     };
93 
94     do
95     {
96 	if((c = url_getc(reader)) == EOF)
97 	    return EOF;
98     } while(c == '\r' || c == '\n');
99     return b64_decode_table[c];
100 }
101 
b64decode(URL_b64decode * urlp)102 static int b64decode(URL_b64decode *urlp)
103 {
104     int c1, c2, c3, c4;
105     int n;
106     unsigned char *p;
107     URL url;
108 
109     if(urlp->eod)
110     {
111 	urlp->eof = 1;
112 	return 1;
113     }
114 
115     p = urlp->decodebuf;
116     url = urlp->reader;
117     n = 0;
118     while(n < DECODEBUFSIZ)
119     {
120 	if((c1 = b64getchar(url)) == EOF)
121 	{
122 	    urlp->eod = 1;
123 	    break;
124 	}
125 	if((c2 = b64getchar(url)) == EOF)
126 	{
127 	    urlp->eod = 1;
128 	    break;
129 	}
130 	p[n++] = ((c1 << 2) | ((c2 & 0x30) >> 4));
131 
132 	if((c3 = b64getchar(url)) == EOF)
133 	{
134 	    urlp->eod = 1;
135 	    break;
136 	}
137 	p[n++] = (((c2 & 0xf) << 4) | ((c3 & 0x3c) >> 2));
138 
139 	if((c4 = b64getchar(url)) == EOF)
140 	{
141 	    urlp->eod = 1;
142 	    break;
143 	}
144         p[n++] = (((c3 & 0x03) << 6) | c4);
145     }
146 
147     urlp->rpos += urlp->beg;
148     urlp->beg = 0;
149     urlp->end = n;
150 
151     if(n == 0)
152     {
153 	urlp->eof = 1;
154 	return 1;
155     }
156 
157     return 0;
158 }
159 
url_b64decode_read(URL url,void * buff,long size)160 static long url_b64decode_read(URL url, void *buff, long size)
161 {
162     URL_b64decode *urlp = (URL_b64decode *)url;
163     unsigned char *p = (unsigned char *)buff;
164     long n;
165 
166     if(urlp->eof)
167 	return 0;
168 
169     n = 0;
170     while(n < size)
171     {
172 	int i;
173 
174 	if(urlp->beg == urlp->end)
175 	    if(b64decode(urlp))
176 		break;
177 	i = urlp->end - urlp->beg;
178 	if(i > size - n)
179 	    i = size - n;
180 	memcpy(p + n, urlp->decodebuf + urlp->beg, i);
181 	n += i;
182 	urlp->beg += i;
183     }
184     return n;
185 }
186 
url_b64decode_fgetc(URL url)187 static int url_b64decode_fgetc(URL url)
188 {
189     URL_b64decode *urlp = (URL_b64decode *)url;
190 
191     if(urlp->eof)
192 	return EOF;
193     if(urlp->beg == urlp->end)
194 	if(b64decode(urlp))
195 	    return EOF;
196 
197     return (int)urlp->decodebuf[urlp->beg++];
198 }
199 
url_b64decode_tell(URL url)200 static long url_b64decode_tell(URL url)
201 {
202     URL_b64decode *urlp = (URL_b64decode *)url;
203 
204     return urlp->rpos + urlp->beg;
205 }
206 
url_b64decode_close(URL url)207 static void url_b64decode_close(URL url)
208 {
209     URL_b64decode *urlp = (URL_b64decode *)url;
210 
211     if(urlp->autoclose)
212 	url_close(urlp->reader);
213     free(url);
214 }
215 
216 #ifdef B64DECODE_MAIN
main(int argc,char ** argv)217 void main(int argc, char** argv)
218 {
219     URL b64decoder;
220     char buff[256], *filename;
221     int c;
222 
223     if(argc != 2)
224     {
225 	fprintf(stderr, "Usage: %s b64-filename\n", argv[0]);
226 	exit(1);
227     }
228     filename = argv[1];
229 
230     if((b64decoder = url_file_open(filename)) == NULL)
231     {
232 	perror(argv[1]);
233 	url_close(b64decoder);
234 	exit(1);
235     }
236 
237     b64decoder = url_b64decode_open(b64decoder, 1);
238 #if B64DECODE_MAIN
239     while((c = url_getc(b64decoder)) != EOF)
240 	putchar(c);
241 #else
242     while((c = url_read(b64decoder, buff, sizeof(buff))) > 0)
243 	write(1, buff, c);
244 #endif
245     url_close(b64decoder);
246     exit(0);
247 }
248 
249 #endif /* B64DECODE_MAIN */
250