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 
23 #include "libarc/url.h"
24 #include "libarc/memb.h"
25 
26 typedef struct _URL_cache
27 {
28     char common[sizeof(struct _URL)];
29     URL reader;
30     int memb_ok;
31     MemBuffer b;
32     long pos;
33     int autoclose;
34 } URL_cache;
35 
36 static long url_cache_read(URL url, void *buff, long n);
37 static int url_cache_fgetc(URL url);
38 static long url_cache_seek(URL url, long offset, int whence);
39 static long url_cache_tell(URL url);
40 static void url_cache_close(URL url);
41 
url_cache_open(URL url,int autoclose)42 URL url_cache_open(URL url, int autoclose)
43 {
44     URL_cache *urlp;
45 
46     if(url->type == URL_cache_t && autoclose)
47     {
48 	if(((URL_cache *)url)->memb_ok)
49 	    delete_memb(&((URL_cache *)url)->b);
50 	urlp = (URL_cache *)url;
51 	url = urlp->reader;
52     }
53     else
54     {
55 	if((urlp = (URL_cache *)alloc_url(sizeof(URL_cache))) == NULL)
56 	{
57 	    if(autoclose)
58 		url_close(url);
59 	    return NULL;
60 	}
61     }
62 
63     /* common members */
64     URLm(urlp, type)	  = URL_cache_t;
65     URLm(urlp, url_read)  = url_cache_read;
66     URLm(urlp, url_gets)  = NULL;
67     URLm(urlp, url_fgetc) = url_cache_fgetc;
68     URLm(urlp, url_seek)  = url_cache_seek;
69     URLm(urlp, url_tell)  = url_cache_tell;
70     URLm(urlp, url_close) = url_cache_close;
71 
72     /* private members */
73     urlp->reader = url;
74     urlp->memb_ok = 1;
75     init_memb(&urlp->b);
76     urlp->pos = 0;
77     urlp->autoclose = autoclose;
78 
79     return (URL)urlp;
80 }
81 
url_cache_disable(URL url)82 void url_cache_disable(URL url)
83 {
84     if(url->type == URL_cache_t)
85 	url->url_seek = NULL;
86 }
87 
url_cache_detach(URL url)88 void url_cache_detach(URL url)
89 {
90     if(url != NULL && url->type == URL_cache_t)
91     {
92 	URL_cache *urlp = (URL_cache *)url;
93 	if(urlp->autoclose && urlp->reader != NULL)
94 	    url_close(urlp->reader);
95 	urlp->reader = NULL;
96     }
97 }
98 
url_cache_read(URL url,void * buff,long n)99 static long url_cache_read(URL url, void *buff, long n)
100 {
101     URL_cache *urlp = (URL_cache *)url;
102     MemBuffer *b = &urlp->b;
103 
104     if(!urlp->memb_ok)
105     {
106 	if(urlp->reader == NULL)
107 	    return 0;
108 	n = url_read(urlp->reader, buff, n);
109 	if(n > 0)
110 	    urlp->pos += n;
111 	return n;
112     }
113 
114     if(urlp->pos < b->total_size)
115     {
116 	if(n > b->total_size - urlp->pos)
117 	    n = b->total_size - urlp->pos;
118 	urlp->pos += read_memb(b, buff, n);
119 	return n;
120     }
121 
122     if(url->url_seek == NULL)
123     {
124 	delete_memb(b);
125 	urlp->memb_ok = 0;
126 	if(urlp->reader == NULL)
127 	    return 0;
128 	n = url_read(urlp->reader, buff, n);
129 	if(n > 0)
130 	    urlp->pos += n;
131 	return n;
132     }
133 
134     if(urlp->reader == NULL)
135 	return 0;
136     n = url_read(urlp->reader, buff, n);
137     if(n > 0)
138     {
139 	push_memb(b, buff, n);
140 	b->cur = b->tail;
141 	b->cur->pos = b->cur->size;
142 	urlp->pos += n;
143     }
144     return n;
145 }
146 
url_cache_fgetc(URL url)147 static int url_cache_fgetc(URL url)
148 {
149     URL_cache *urlp = (URL_cache *)url;
150     MemBuffer *b = &urlp->b;
151     char c;
152     int i;
153 
154     if(!urlp->memb_ok)
155     {
156 	if(urlp->reader == NULL)
157 	    return EOF;
158 	if((i = url_getc(urlp->reader)) == EOF)
159 	    return EOF;
160 	urlp->pos++;
161 	return i;
162     }
163 
164     if(urlp->pos < b->total_size)
165     {
166 	read_memb(b, &c, 1);
167 	urlp->pos++;
168 	return (int)(unsigned char)c;
169     }
170 
171     if(url->url_seek == NULL)
172     {
173 	delete_memb(b);
174 	urlp->memb_ok = 0;
175 	if(urlp->reader == NULL)
176 	    return EOF;
177 	if((i = url_getc(urlp->reader)) == EOF)
178 	    return EOF;
179 	urlp->pos++;
180 	return i;
181     }
182 
183     if(urlp->reader == NULL)
184 	return EOF;
185     if((i = url_getc(urlp->reader)) == EOF)
186 	return EOF;
187     c = (char)i;
188     push_memb(b, &c, 1);
189     b->cur = b->tail;
190     b->cur->pos = b->cur->size;
191     urlp->pos++;
192     return i;
193 }
194 
url_cache_seek(URL url,long offset,int whence)195 static long url_cache_seek(URL url, long offset, int whence)
196 {
197     URL_cache *urlp = (URL_cache *)url;
198     MemBuffer *b = &urlp->b;
199     long ret, newpos, n, s;
200 
201     ret = urlp->pos;
202     switch(whence)
203     {
204       case SEEK_SET:
205 	newpos = offset;
206 	break;
207       case SEEK_CUR:
208 	newpos = ret + offset;
209 	break;
210       case SEEK_END:
211 	while(url_cache_fgetc(url) != EOF)
212 	    ;
213 	newpos = b->total_size + whence;
214 	break;
215       default:
216 	url_errno = errno = EPERM;
217 	return -1;
218     }
219     if(newpos < 0)
220 	newpos = 0;
221     n = newpos - ret;
222 
223     if(n < 0)
224     {
225 	rewind_memb(b);
226 	n = newpos;
227 	urlp->pos = 0;
228     }
229 
230     s = skip_read_memb(b, n);
231     urlp->pos += s;
232     while(s++ < n && url_cache_fgetc(url) != EOF)
233 	;
234     return ret;
235 }
236 
url_cache_tell(URL url)237 static long url_cache_tell(URL url)
238 {
239     return ((URL_cache *)url)->pos;
240 }
241 
url_cache_close(URL url)242 static void url_cache_close(URL url)
243 {
244     URL_cache *urlp = (URL_cache *)url;
245     if(urlp->autoclose && urlp->reader != NULL)
246 	url_close(urlp->reader);
247     if(urlp->memb_ok)
248 	delete_memb(&urlp->b);
249     free(urlp);
250 }
251