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_uudecode
30 {
31     char common[sizeof(struct _URL)];
32     URL reader;
33     long rpos;
34     int beg, end, eof;
35     unsigned char decodebuf[128];
36     int autoclose;
37 } URL_uudecode;
38 
39 static long url_uudecode_read(URL url, void *buff, long n);
40 static int  url_uudecode_fgetc(URL url);
41 static long url_uudecode_tell(URL url);
42 static void url_uudecode_close(URL url);
43 
url_uudecode_open(URL reader,int autoclose)44 URL url_uudecode_open(URL reader, int autoclose)
45 {
46     URL_uudecode *url;
47 
48     url = (URL_uudecode *)alloc_url(sizeof(URL_uudecode));
49     if(url == NULL)
50     {
51 	if(autoclose)
52 	    url_close(reader);
53 	url_errno = errno;
54 	return NULL;
55     }
56 
57     /* common members */
58     URLm(url, type)      = URL_uudecode_t;
59     URLm(url, url_read)  = url_uudecode_read;
60     URLm(url, url_gets)  = NULL;
61     URLm(url, url_fgetc) = url_uudecode_fgetc;
62     URLm(url, url_seek)  = NULL;
63     URLm(url, url_tell)  = url_uudecode_tell;
64     URLm(url, url_close) = url_uudecode_close;
65 
66     /* private members */
67     url->reader = reader;
68     url->rpos = 0;
69     url->beg = 0;
70     url->end = 0;
71     url->eof = 0;
72     memset(url->decodebuf, 0, sizeof(url->decodebuf));
73     url->autoclose = autoclose;
74 
75     return (URL)url;
76 }
77 
78 #define	DEC(c)	(((c) - ' ') & 077)		/* single character decode */
uudecodeline(URL_uudecode * urlp)79 static int uudecodeline(URL_uudecode *urlp)
80 {
81     unsigned char inbuf[BUFSIZ], *p, *q, ch;
82     int n;
83 
84     if(url_gets(urlp->reader, (char *)inbuf, sizeof(inbuf)) == NULL)
85     {
86 	urlp->eof = 1;
87 	return 1;
88     }
89 
90     if((n = DEC(*inbuf)) <= 0)
91     {
92 	urlp->eof = 1;
93 	return 1;
94     }
95 
96     if(uudecode_unquote_html)
97     {
98 	int i, j, len;
99 
100 	len = strlen((char *)inbuf);
101 	while(len > 0 &&
102 	      (inbuf[len - 1] == '\r' || inbuf[len - 1] == '\n' ||
103 	       inbuf[len - 1] == '\t' || inbuf[len - 1] == ' '))
104 	    inbuf[--len] = '\0';
105 	if(n * 4 != (len - 1) * 3)
106 	{
107 	    /* &lt;/&gt;/&amp; */
108 	    i = j = 0;
109 	    while(i < len - 3)
110 		if(inbuf[i] != '&')
111 		    inbuf[j++] = inbuf[i++];
112 		else
113 		{
114 		    i++;
115 		    if(strncmp((char *)inbuf + i, "lt;", 3) == 0)
116 		    {
117 			inbuf[j++] = '<';
118 			i += 3;
119 		    }
120 		    else if(strncmp((char *)inbuf + i, "gt;", 3) == 0)
121 		    {
122 			inbuf[j++] = '>';
123 			i += 3;
124 		    }
125 		    else if(strncmp((char *)inbuf + i, "amp;", 4) == 0)
126 		    {
127 			inbuf[j++] = '&';
128 			i += 4;
129 		    }
130 		    else
131 			inbuf[j++] = '&';
132 		}
133 	    while(i < len)
134 		inbuf[j++] = inbuf[i++];
135 	    inbuf[j++] = '\0';
136 	}
137     }
138 
139     p = inbuf + 1;
140     q = urlp->decodebuf;
141     for(; n > 0; p += 4, n -= 3)
142     {
143 	if(n >= 3)
144 	{
145 	    ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
146 	    *q++ = ch;
147 	    ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
148 	    *q++ = ch;
149 	    ch = DEC(p[2]) << 6 | DEC(p[3]);
150 	    *q++ = ch;
151 	}
152 	else
153 	{
154 	    if(n >= 1)
155 	    {
156 		ch = DEC(p[0]) << 2 | DEC(p[1]) >> 4;
157 		*q++ = ch;
158 	    }
159 	    if(n >= 2)
160 	    {
161 		ch = DEC(p[1]) << 4 | DEC(p[2]) >> 2;
162 		*q++ = ch;
163 	    }
164 	    if(n >= 3)
165 	    {
166 		ch = DEC(p[2]) << 6 | DEC(p[3]);
167 		*q++ = ch;
168 	    }
169 	}
170     }
171     urlp->rpos += urlp->beg;
172     urlp->beg = 0;
173     urlp->end = q - urlp->decodebuf;
174     return 0;
175 }
176 
url_uudecode_read(URL url,void * buff,long size)177 static long url_uudecode_read(URL url, void *buff, long size)
178 {
179     URL_uudecode *urlp = (URL_uudecode *)url;
180     unsigned char *p = (unsigned char *)buff;
181     long n;
182 
183     if(urlp->eof)
184 	return 0;
185 
186     n = 0;
187     while(n < size)
188     {
189 	int i;
190 
191 	if(urlp->beg == urlp->end)
192 	    if(uudecodeline(urlp))
193 		break;
194 	i = urlp->end - urlp->beg;
195 	if(i > size - n)
196 	    i = size - n;
197 	memcpy(p + n, urlp->decodebuf + urlp->beg, i);
198 	n += i;
199 	urlp->beg += i;
200     }
201     return n;
202 }
203 
url_uudecode_fgetc(URL url)204 static int url_uudecode_fgetc(URL url)
205 {
206     URL_uudecode *urlp = (URL_uudecode *)url;
207 
208     if(urlp->eof)
209 	return EOF;
210     if(urlp->beg == urlp->end)
211 	if(uudecodeline(urlp))
212 	    return EOF;
213 
214     return (int)urlp->decodebuf[urlp->beg++];
215 }
216 
url_uudecode_tell(URL url)217 static long url_uudecode_tell(URL url)
218 {
219     URL_uudecode *urlp = (URL_uudecode *)url;
220 
221     return urlp->rpos + urlp->beg;
222 }
223 
url_uudecode_close(URL url)224 static void url_uudecode_close(URL url)
225 {
226     URL_uudecode *urlp = (URL_uudecode *)url;
227 
228     if(urlp->autoclose)
229 	url_close(urlp->reader);
230     free(url);
231 }
232 
233 #ifdef UUDECODE_MAIN
main(int argc,char ** argv)234 void main(int argc, char** argv)
235 {
236     URL uudecoder;
237     char buff[256], *filename;
238     int c;
239 
240     if(argc != 2)
241     {
242 	fprintf(stderr, "Usage: %s uu-filename\n", argv[0]);
243 	exit(1);
244     }
245     filename = argv[1];
246 
247     if((uudecoder = url_file_open(filename)) == NULL)
248     {
249 	perror(argv[1]);
250 	exit(1);
251     }
252 
253     for(;;)
254     {
255 	if(url_readline(uudecoder, buff, sizeof(buff)) == EOF)
256 	{
257 	    fprintf(stderr, "%s: Not a hqx-file\n", filename);
258 	    url_close(uudecoder);
259 	    exit(1);
260 	}
261 	if(strncmp(buff, "begin ", 6) == 0)
262 	    break;
263     }
264 
265     uudecoder = url_uudecode_open(uudecoder, 1);
266 #if UUDECODE_MAIN
267     while((c = url_getc(uudecoder)) != EOF)
268 	putchar(c);
269 #else
270     while((c = url_read(uudecoder, buff, sizeof(buff))) > 0)
271 	write(1, buff, c);
272 #endif
273     url_close(uudecoder);
274     exit(0);
275 }
276 
277 #endif /* UUDECODE_MAIN */
278