1 /*
2     TiMidity++ -- MIDI to WAVE converter and player
3     Copyright (C) 1999-2002 Masanao Izumo <mo@goice.co.jp>
4     Copyright (C) 1995 Tuukka Toivonen <tt@cgs.fi>
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19 
20 */
21 
22 #ifdef HAVE_CONFIG_H
23 #include "config.h"
24 #endif /* HAVE_CONFIG_H */
25 #include <stdio.h>
26 #include <stdlib.h>
27 #ifndef NO_STRING_H
28 #include <string.h>
29 #else
30 #include <strings.h>
31 #endif
32 #include "timidity.h"
33 #include "memb.h"
34 
init_memb(MemBuffer * b)35 void init_memb(MemBuffer *b)
36 {
37     memset(b, 0, sizeof(MemBuffer));
38 }
39 
delete_memb(MemBuffer * b)40 void delete_memb(MemBuffer *b)
41 {
42     reuse_mblock(&b->pool);
43     memset(b, 0, sizeof(MemBuffer));
44 }
45 
rewind_memb(MemBuffer * b)46 void rewind_memb(MemBuffer *b)
47 {
48     if(b->head != NULL)
49     {
50 	b->cur = b->head;
51 	b->cur->pos = 0;
52     }
53 }
54 
push_memb(MemBuffer * b,char * buff,long buff_size)55 void push_memb(MemBuffer *b, char *buff, long buff_size)
56 {
57     b->total_size += buff_size;
58     if(b->head == NULL)
59     {
60 	b->head = b->tail = b->cur =
61 	    (MemBufferNode *)new_segment(&b->pool, MIN_MBLOCK_SIZE);
62 	b->head->next = NULL;
63 	b->head->size = b->head->pos = 0;
64     }
65     while(buff_size > 0)
66     {
67 	long n;
68 	MemBufferNode *p;
69 
70 	p = b->tail;
71 	n = (long)(MEMBASESIZE - p->size);
72 	if(n == 0)
73 	{
74 	    p = (MemBufferNode *)new_segment(&b->pool, MIN_MBLOCK_SIZE);
75 	    b->tail->next = p;
76 	    b->tail = p;
77 	    p->next = NULL;
78 	    p->size = p->pos = 0;
79 	    n = MEMBASESIZE;
80 	}
81 	if(n > buff_size)
82 	    n = buff_size;
83 	memcpy(p->base + p->size, buff, n);
84 	p->size += n;
85 	buff_size -= n;
86 	buff += n;
87     }
88 }
89 
read_memb(MemBuffer * b,char * buff,long buff_size)90 long read_memb(MemBuffer *b, char *buff, long buff_size)
91 {
92     long n;
93 
94     if(b->head == NULL)
95 	return 0;
96     if(b->cur == NULL)
97 	rewind_memb(b);
98     if(b->cur->next == NULL && b->cur->pos == b->cur->size)
99 	return 0;
100 
101     n = 0;
102     while(n < buff_size)
103     {
104 	long i;
105 	MemBufferNode *p;
106 
107 	p = b->cur;
108 	if(p->pos == p->size)
109 	{
110 	    if(p->next == NULL)
111 		break;
112 	    b->cur = p->next;
113 	    b->cur->pos = 0;
114 	    continue;
115 	}
116 
117 	i = p->size - p->pos;
118 	if(i > buff_size - n)
119 	    i = buff_size - n;
120 	memcpy(buff + n, p->base + p->pos, i);
121 	n += i;
122 	p->pos += i;
123     }
124     return n;
125 }
126 
skip_read_memb(MemBuffer * b,long size)127 long skip_read_memb(MemBuffer *b, long size)
128 {
129     long n;
130 
131     if(size <= 0 || b->head == NULL)
132 	return 0;
133     if(b->cur == NULL)
134 	rewind_memb(b);
135     if(b->cur->next == NULL && b->cur->pos == b->cur->size)
136 	return 0;
137 
138     n = 0;
139     while(n < size)
140     {
141 	long i;
142 	MemBufferNode *p;
143 
144 	p = b->cur;
145 	if(p->pos == p->size)
146 	{
147 	    if(p->next == NULL)
148 		break;
149 	    b->cur = p->next;
150 	    b->cur->pos = 0;
151 	    continue;
152 	}
153 
154 	i = p->size - p->pos;
155 	if(i > size - n)
156 	    i = size - n;
157 	n += i;
158 	p->pos += i;
159     }
160     return n;
161 }
162 
163 typedef struct _URL_memb
164 {
165     char common[sizeof(struct _URL)];
166     MemBuffer *b;
167     long pos;
168     int autodelete;
169 } URL_memb;
170 
171 static long url_memb_read(URL url, void *buff, long n);
172 static int url_memb_fgetc(URL url);
173 static long url_memb_seek(URL url, long offset, int whence);
174 static long url_memb_tell(URL url);
175 static void url_memb_close(URL url);
176 
memb_open_stream(MemBuffer * b,int autodelete)177 URL memb_open_stream(MemBuffer *b, int autodelete)
178 {
179     URL_memb *url;
180 
181     url = (URL_memb *)alloc_url(sizeof(URL_memb));
182     if(url == NULL)
183     {
184 	if(autodelete)
185 	    delete_memb(b);
186 	url_errno = errno;
187 	return NULL;
188     }
189 
190     /* common members */
191     URLm(url, type)      = URL_extension_t;
192     URLm(url, url_read)  = url_memb_read;
193     URLm(url, url_gets)  = NULL;
194     URLm(url, url_fgetc) = url_memb_fgetc;
195     URLm(url, url_seek)  = url_memb_seek;
196     URLm(url, url_tell)  = url_memb_tell;
197     URLm(url, url_close) = url_memb_close;
198 
199     /* private members */
200     url->b = b;
201     url->pos = 0;
202     url->autodelete = autodelete;
203 
204     rewind_memb(b);
205     return (URL)url;
206 }
207 
url_memb_read(URL url,void * buff,long n)208 static long url_memb_read(URL url, void *buff, long n)
209 {
210     URL_memb *urlp = (URL_memb *)url;
211     if((n = read_memb(urlp->b, buff, n)) > 0)
212 	urlp->pos += n;
213     return n;
214 }
215 
url_memb_fgetc(URL url)216 static int url_memb_fgetc(URL url)
217 {
218     URL_memb *urlp = (URL_memb *)url;
219     MemBuffer *b = urlp->b;
220     MemBufferNode *p;
221 
222     p = b->cur;
223     if(p == NULL)
224 	return EOF;
225     while(p->pos == p->size)
226     {
227 	if(p->next == NULL)
228 	    return EOF;
229 	p = b->cur = p->next;
230 	p->pos = 0;
231     }
232     urlp->pos++;
233     return (int)((unsigned char *)p->base)[p->pos++];
234 }
235 
url_memb_seek(URL url,long offset,int whence)236 static long url_memb_seek(URL url, long offset, int whence)
237 {
238     URL_memb *urlp = (URL_memb *)url;
239     MemBuffer *b = urlp->b;
240     long ret, newpos = 0, n;
241 
242     ret = urlp->pos;
243     switch(whence)
244     {
245       case SEEK_SET:
246 	newpos = offset;
247 	break;
248       case SEEK_CUR:
249 	newpos = ret + offset;
250 	break;
251       case SEEK_END:
252 	newpos = b->total_size + offset;
253 	break;
254     }
255     if(newpos < 0)
256 	newpos = 0;
257     else if(newpos > b->total_size)
258 	newpos = b->total_size;
259     n = newpos - ret;
260     if(n < 0)
261     {
262 	rewind_memb(b);
263 	n = newpos;
264 	urlp->pos = 0;
265     }
266 
267     urlp->pos += skip_read_memb(b, n);
268     return ret;
269 }
270 
url_memb_tell(URL url)271 static long url_memb_tell(URL url)
272 {
273     return ((URL_memb *)url)->pos;
274 }
275 
url_memb_close(URL url)276 static void url_memb_close(URL url)
277 {
278     URL_memb *urlp = (URL_memb *)url;
279     if(urlp->autodelete)
280     {
281 	delete_memb(urlp->b);
282 	free(urlp->b);
283     }
284     free(url);
285 }
286