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 BUFSIZ
30 
31 typedef struct _URL_qsdecode
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_qsdecode;
40 
41 static long url_qsdecode_read(URL url, void *buff, long n);
42 static int  url_qsdecode_fgetc(URL url);
43 static long url_qsdecode_tell(URL url);
44 static void url_qsdecode_close(URL url);
45 
url_qsdecode_open(URL reader,int autoclose)46 URL url_qsdecode_open(URL reader, int autoclose)
47 {
48     URL_qsdecode *url;
49 
50     url = (URL_qsdecode *)alloc_url(sizeof(URL_qsdecode));
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_qsdecode_t;
61     URLm(url, url_read)  = url_qsdecode_read;
62     URLm(url, url_gets)  = NULL;
63     URLm(url, url_fgetc) = url_qsdecode_fgetc;
64     URLm(url, url_seek)  = NULL;
65     URLm(url, url_tell)  = url_qsdecode_tell;
66     URLm(url, url_close) = url_qsdecode_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 
qsdecode(URL_qsdecode * urlp)80 static int qsdecode(URL_qsdecode *urlp)
81 {
82     int n;
83     unsigned char *p;
84     URL url;
85 
86     if(urlp->eod)
87     {
88 	urlp->eof = 1;
89 	return 1;
90     }
91 
92     p = urlp->decodebuf;
93     url = urlp->reader;
94     n = 0;
95     while(n < DECODEBUFSIZ)
96     {
97 	int c1, c2;
98 
99 	if((c1 = url_getc(url)) == EOF)
100 	    break;
101 	if(c1 != '=')
102 	{
103 	    p[n++] = c1;
104 	    continue;
105 	}
106 
107 	/* quoted character */
108       next_quote:
109 	if((c1 = url_getc(url)) == EOF)
110 	    break;
111 	if(c1 == '\n')
112 	    continue;
113 	if(c1 == '\r')
114 	{
115 	    if((c1 = url_getc(url)) == EOF)
116 		break;
117 	    if(c1 == '\n')
118 		continue;
119 	    if(c1 == '=')
120 		goto next_quote;
121 	    p[n++] = c1;
122 	    continue;
123 	}
124 	if((c2 = url_getc(url)) == EOF)
125 	    break;
126 	if('0' <= c1 && c1 <= '9')
127 	    c1 -= '0';
128 	else if('A' <= c1 && c1 <= 'F')
129 	    c1 -= 'A' - 10;
130 	else
131 	    c1 = 0;
132 	if('0' <= c2 && c2 <= '9')
133 	    c2 -= '0';
134 	else if('A' <= c2 && c2 <= 'F')
135 	    c2 -= 'A' - 10;
136 	else
137 	    c2 = 0;
138 	p[n++] = (c1 << 4 | c2);
139     }
140 
141     urlp->rpos += urlp->beg;
142     urlp->beg = 0;
143     urlp->end = n;
144 
145     if(n < DECODEBUFSIZ)
146 	urlp->eod = 1;
147 
148     if(n == 0)
149     {
150 	urlp->eof = 1;
151 	return 1;
152     }
153 
154 
155     return 0;
156 }
157 
url_qsdecode_read(URL url,void * buff,long size)158 static long url_qsdecode_read(URL url, void *buff, long size)
159 {
160     URL_qsdecode *urlp = (URL_qsdecode *)url;
161     unsigned char *p = (unsigned char *)buff;
162     long n;
163 
164     if(urlp->eof)
165 	return 0;
166 
167     n = 0;
168     while(n < size)
169     {
170 	int i;
171 
172 	if(urlp->beg == urlp->end)
173 	    if(qsdecode(urlp))
174 		break;
175 	i = urlp->end - urlp->beg;
176 	if(i > size - n)
177 	    i = size - n;
178 	memcpy(p + n, urlp->decodebuf + urlp->beg, i);
179 	n += i;
180 	urlp->beg += i;
181     }
182     return n;
183 }
184 
url_qsdecode_fgetc(URL url)185 static int url_qsdecode_fgetc(URL url)
186 {
187     URL_qsdecode *urlp = (URL_qsdecode *)url;
188 
189     if(urlp->eof)
190 	return EOF;
191     if(urlp->beg == urlp->end)
192 	if(qsdecode(urlp))
193 	    return EOF;
194 
195     return (int)urlp->decodebuf[urlp->beg++];
196 }
197 
url_qsdecode_tell(URL url)198 static long url_qsdecode_tell(URL url)
199 {
200     URL_qsdecode *urlp = (URL_qsdecode *)url;
201 
202     return urlp->rpos + urlp->beg;
203 }
204 
url_qsdecode_close(URL url)205 static void url_qsdecode_close(URL url)
206 {
207     URL_qsdecode *urlp = (URL_qsdecode *)url;
208 
209     if(urlp->autoclose)
210 	url_close(urlp->reader);
211     free(url);
212 }
213 
214 #ifdef QSDECODE_MAIN
main(int argc,char ** argv)215 void main(int argc, char** argv)
216 {
217     URL qsdecoder;
218     char buff[256], *filename;
219     int c;
220 
221     if(argc != 2)
222     {
223 	fprintf(stderr, "Usage: %s qs-filename\n", argv[0]);
224 	exit(1);
225     }
226     filename = argv[1];
227 
228     if((qsdecoder = url_file_open(filename)) == NULL)
229     {
230 	perror(argv[1]);
231 	url_close(qsdecoder);
232 	exit(1);
233     }
234 
235     qsdecoder = url_qsdecode_open(qsdecoder, 1);
236 #if QSDECODE_MAIN
237     while((c = url_getc(qsdecoder)) != EOF)
238 	putchar(c);
239 #else
240     while((c = url_read(qsdecoder, buff, sizeof(buff))) > 0)
241 	write(1, buff, c);
242 #endif
243     url_close(qsdecoder);
244     exit(0);
245 }
246 
247 #endif /* QSDECODE_MAIN */
248