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 typedef struct _URL_cgiesc
30 {
31 char common[sizeof(struct _URL)];
32 URL reader;
33 long rpos;
34 int beg, end, eod, eof;
35 unsigned char cnvbuf[1024];
36 int decode;
37 int autoclose;
38 } URL_cgiesc;
39
40 static long url_cgiesc_read(URL url, void *buff, long n);
41 static int url_cgiesc_fgetc(URL url);
42 static long url_cgiesc_tell(URL url);
43 static void url_cgiesc_close(URL url);
44
url_cgiesc_open(URL reader,int type,int autoclose)45 static URL url_cgiesc_open(URL reader, int type, int autoclose)
46 {
47 URL_cgiesc *url;
48
49 url = (URL_cgiesc *)alloc_url(sizeof(URL_cgiesc));
50 if(url == NULL)
51 {
52 if(autoclose)
53 url_close(reader);
54 url_errno = errno;
55 return NULL;
56 }
57
58 /* common members */
59 URLm(url, type) = type;
60 URLm(url, url_read) = url_cgiesc_read;
61 URLm(url, url_gets) = NULL;
62 URLm(url, url_fgetc) = url_cgiesc_fgetc;
63 URLm(url, url_seek) = NULL;
64 URLm(url, url_tell) = url_cgiesc_tell;
65 URLm(url, url_close) = url_cgiesc_close;
66
67 /* private members */
68 url->reader = reader;
69 url->rpos = 0;
70 url->beg = 0;
71 url->end = 0;
72 url->eod = 0;
73 url->eof = 0;
74 memset(url->cnvbuf, 0, sizeof(url->cnvbuf));
75 url->decode = (type == URL_cgi_unescape_t);
76 url->autoclose = autoclose;
77
78 return (URL)url;
79 }
80
url_cgi_escape_open(URL reader,int autoclose)81 URL url_cgi_escape_open(URL reader, int autoclose)
82 {
83 return url_cgiesc_open(reader, URL_cgi_escape_t, autoclose);
84 }
85
url_cgi_unescape_open(URL reader,int autoclose)86 URL url_cgi_unescape_open(URL reader, int autoclose)
87 {
88 return url_cgiesc_open(reader, URL_cgi_unescape_t, autoclose);
89 }
90
fillbuff(URL_cgiesc * urlp)91 static int fillbuff(URL_cgiesc *urlp)
92 {
93 URL reader;
94 int c, n;
95 unsigned char *p = urlp->cnvbuf;
96 static char *cgi_encode_table =
97 "000102030405060708090A0B0C0D0E0F101112131415161718191A1B1C1D1E1F"
98 "\000\0002122232425262728292A2B2C\000\000\000\0002F\000\000\000\000"
99 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
100 "3A3B3C3D3E3F40\000\000\000\000\000\000\000\000\000\000\000\000\000"
101 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
102 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
103 "\000\000\000\000\000\000\0005B5C5D5E\000\00060\000\000\000\000\000"
104 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
105 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000\000"
106 "\000\000\000\000\000\000\000\000\000\000\000\000\000\000\0007B7C"
107 "7D7E7F808182838485868788898A8B8C8D8E8F909192939495969798999A9B9C"
108 "9D9E9FA0A1A2A3A4A5A6A7A8A9AAABACADAEAFB0B1B2B3B4B5B6B7B8B9BABBBC"
109 "BDBEBFC0C1C2C3C4C5C6C7C8C9CACBCCCDCECFD0D1D2D3D4D5D6D7D8D9DADBDC"
110 "DDDEDFE0E1E2E3E4E5E6E7E8E9EAEBECEDEEEFF0F1F2F3F4F5F6F7F8F9FAFBFC"
111 "FDFEFF";
112 static char hex_decode[256] =
113 {
114 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
115 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
116 0, 0, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 0, 0, 0, 0, 0, 0, 0, 10, 11, 12,
117 13, 14, 15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
118 0, 0, 0, 0, 0, 0, 0, 10, 11, 12, 13, 14, 15
119 };
120
121 if(urlp->eod)
122 {
123 urlp->eof = 1;
124 return 1;
125 }
126
127 reader = urlp->reader;
128 n = 0;
129
130 if(urlp->decode)
131 {
132 while(n < sizeof(urlp->cnvbuf))
133 {
134 if((c = url_getc(reader)) == EOF)
135 {
136 urlp->eod = 1;
137 break;
138 }
139 if(c == '+')
140 c = ' ';
141 else if(c == '%')
142 {
143 int c1, c2;
144
145 if((c1 = url_getc(reader)) == EOF)
146 {
147 urlp->eod = 1;
148 break;
149 }
150 if((c2 = url_getc(reader)) == EOF)
151 {
152 urlp->eod = 1;
153 break;
154 }
155 c1 = hex_decode[c1];
156 c2 = hex_decode[c2];
157 c = (c1 << 4 | c2);
158 }
159 p[n++] = c;
160 }
161 }
162 else
163 {
164 char *esp;
165 while(n < sizeof(urlp->cnvbuf) - 2)
166 {
167 if((c = url_getc(reader)) == EOF)
168 {
169 urlp->eod = 1;
170 break;
171 }
172 if(c == ' ')
173 p[n++] = '+';
174 else
175 {
176 esp = cgi_encode_table + 2 * c;
177 if(esp[0] == '\0')
178 p[n++] = c;
179 else
180 {
181 p[n++] = '%';
182 p[n++] = esp[0];
183 p[n++] = esp[1];
184 }
185 }
186 }
187 }
188
189 urlp->rpos += urlp->beg;
190 urlp->beg = 0;
191 urlp->end = n;
192
193 if(n == 0)
194 {
195 urlp->eof = 1;
196 return 1;
197 }
198 return 0;
199 }
200
url_cgiesc_read(URL url,void * buff,long size)201 static long url_cgiesc_read(URL url, void *buff, long size)
202 {
203 URL_cgiesc *urlp = (URL_cgiesc *)url;
204 unsigned char *p = (unsigned char *)buff;
205 long n;
206
207 if(urlp->eof)
208 return 0;
209
210 n = 0;
211 while(n < size)
212 {
213 int i;
214
215 if(urlp->beg == urlp->end)
216 if(fillbuff(urlp))
217 break;
218 i = urlp->end - urlp->beg;
219 if(i > size - n)
220 i = size - n;
221 memcpy(p + n, urlp->cnvbuf + urlp->beg, i);
222 n += i;
223 urlp->beg += i;
224 }
225 return n;
226 }
227
url_cgiesc_fgetc(URL url)228 static int url_cgiesc_fgetc(URL url)
229 {
230 URL_cgiesc *urlp = (URL_cgiesc *)url;
231
232 if(urlp->eof)
233 return EOF;
234 if(urlp->beg == urlp->end)
235 if(fillbuff(urlp))
236 return EOF;
237
238 return (int)urlp->cnvbuf[urlp->beg++];
239 }
240
url_cgiesc_tell(URL url)241 static long url_cgiesc_tell(URL url)
242 {
243 URL_cgiesc *urlp = (URL_cgiesc *)url;
244
245 return urlp->rpos + urlp->beg;
246 }
247
url_cgiesc_close(URL url)248 static void url_cgiesc_close(URL url)
249 {
250 URL_cgiesc *urlp = (URL_cgiesc *)url;
251
252 if(urlp->autoclose)
253 url_close(urlp->reader);
254 free(url);
255 }
256
257 #ifdef CGIESC_MAIN
main(int argc,char ** argv)258 void main(int argc, char** argv)
259 {
260 URL url;
261 char buff[256], *filename;
262 int c, decode;
263
264 if(argc != 2)
265 {
266 fprintf(stderr, "Usage: %s filename\n", argv[0]);
267 exit(1);
268 }
269
270 if(strstr(argv[0], "unescape"))
271 decode = 0;
272 else
273 decode = 1;
274 filename = argv[1];
275
276 if((url = url_file_open(filename)) == NULL)
277 {
278 perror(argv[1]);
279 exit(1);
280 }
281
282 if(decode)
283 url = url_cgi_unescape_open(url, 1);
284 else
285 url = url_cgi_escape_open(url, 1);
286
287 #if CGIESC_MAIN
288 while((c = url_getc(url)) != EOF)
289 putchar(c);
290 #else
291 while((c = url_read(url, buff, sizeof(buff))) > 0)
292 write(1, buff, c);
293 #endif
294 url_close(url);
295 exit(0);
296 }
297
298 #endif /* CGIESC_MAIN */
299