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