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