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