1 /*
2 * This file has been modified for the cdrkit suite.
3 *
4 * The behaviour and appearence of the program code below can differ to a major
5 * extent from the version distributed by the original author(s).
6 *
7 * For details, see Changelog file distributed with the cdrkit package. If you
8 * received this file from another source then ask the distributing person for
9 * a log of modifications.
10 *
11 */
12
13 /* @(#)p_block.c 1.19 04/02/23 J. Schilling from cdparanoia-III-alpha9.8 */
14 /*
15 * Modifications to make the code portable Copyright (c) 2002 J. Schilling
16 */
17 #include <mconfig.h>
18 #include <stdxlib.h>
19 #include <standard.h>
20 #include <utypes.h>
21 #include <strdefs.h>
22 #include "p_block.h"
23 #include "cdda_paranoia.h"
24 #include "pmalloc.h"
25
26 linked_list *new_list(void *(*newp) (void), void (*freep) (void *));
27 linked_element *add_elem(linked_list *l, void *elem);
28 linked_element *new_elem(linked_list *list);
29 void free_elem(linked_element *e, int free_ptr);
30 void free_list(linked_list *list, int free_ptr);
31 void *get_elem(linked_element *e);
32 linked_list *copy_list(linked_list *list);
33 static c_block *i_cblock_constructor(void);
34 void i_cblock_destructor(c_block *c);
35 c_block *new_c_block(cdrom_paranoia *p);
36 void free_c_block(c_block *c);
37 static v_fragment *i_vfragment_constructor(void);
38 static void i_v_fragment_destructor(v_fragment *v);
39 v_fragment *new_v_fragment(cdrom_paranoia *p, c_block *one, long begin,
40 long end, int last);
41 void free_v_fragment(v_fragment *v);
42 c_block *c_first(cdrom_paranoia *p);
43 c_block *c_last(cdrom_paranoia *p);
44 c_block *c_next(c_block *c);
45 c_block *c_prev(c_block *c);
46 v_fragment *v_first(cdrom_paranoia *p);
47 v_fragment *v_last(cdrom_paranoia *p);
48 v_fragment *v_next(v_fragment *v);
49 v_fragment *v_prev(v_fragment *v);
50 void recover_cache(cdrom_paranoia *p);
51 Int16_t *v_buffer(v_fragment *v);
52 c_block *c_alloc(Int16_t *vector, long begin, long size);
53 void c_set(c_block *v, long begin);
54 void c_remove(c_block *v, long cutpos, long cutsize);
55 void c_overwrite(c_block *v, long pos, Int16_t *b, long size);
56 void c_append(c_block *v, Int16_t *vector, long size);
57 void c_removef(c_block *v, long cut);
58 void i_paranoia_firstlast(cdrom_paranoia *p);
59 cdrom_paranoia *paranoia_init(void *d, int nsectors);
60
61
new_list(void * (* newp)(void),void (* freep)(void *))62 linked_list *new_list(void *(*newp)(void), void (*freep)(void *))
63 {
64 linked_list *ret = _pcalloc(1, sizeof (linked_list));
65
66 ret->new_poly = newp;
67 ret->free_poly = freep;
68 return (ret);
69 }
70
add_elem(linked_list * l,void * elem)71 linked_element *add_elem(linked_list *l, void *elem)
72 {
73
74 linked_element *ret = _pcalloc(1, sizeof (linked_element));
75
76 ret->stamp = l->current++;
77 ret->ptr = elem;
78 ret->list = l;
79
80 if (l->head)
81 l->head->prev = ret;
82 else
83 l->tail = ret;
84 ret->next = l->head;
85 ret->prev = NULL;
86 l->head = ret;
87 l->active++;
88
89 return (ret);
90 }
91
new_elem(linked_list * list)92 linked_element *new_elem(linked_list *list)
93 {
94 void *new = list->new_poly();
95
96 return (add_elem(list, new));
97 }
98
free_elem(linked_element * e,int free_ptr)99 void free_elem(linked_element *e, int free_ptr)
100 {
101 linked_list *l = e->list;
102
103 if (free_ptr)
104 l->free_poly(e->ptr);
105
106 if (e == l->head)
107 l->head = e->next;
108 if (e == l->tail)
109 l->tail = e->prev;
110
111 if (e->prev)
112 e->prev->next = e->next;
113 if (e->next)
114 e->next->prev = e->prev;
115
116 l->active--;
117 _pfree(e);
118 }
119
free_list(linked_list * list,int free_ptr)120 void free_list(linked_list *list, int free_ptr)
121 {
122 while (list->head)
123 free_elem(list->head, free_ptr);
124 _pfree(list);
125 }
126
get_elem(linked_element * e)127 void *get_elem(linked_element *e)
128 {
129 return (e->ptr);
130 }
131
copy_list(linked_list * list)132 linked_list *copy_list(linked_list *list)
133 {
134 linked_list *new = new_list(list->new_poly, list->free_poly);
135 linked_element *i = list->tail;
136
137 while (i) {
138 add_elem(new, i->ptr);
139 i = i->prev;
140 }
141 return (new);
142 }
143
144 /**** C_block stuff ******************************************************/
145
146 #define vp_cblock_constructor_func ((void*(*)(void))i_cblock_constructor)
i_cblock_constructor()147 static c_block *i_cblock_constructor()
148 {
149 c_block *ret = _pcalloc(1, sizeof (c_block));
150
151 return (ret);
152 }
153
154 #define vp_cblock_destructor_func ((void(*)(void*))i_cblock_destructor)
i_cblock_destructor(c_block * c)155 void i_cblock_destructor(c_block *c)
156 {
157 if (c) {
158 if (c->vector)
159 _pfree(c->vector);
160 if (c->flags)
161 _pfree(c->flags);
162 c->e = NULL;
163 _pfree(c);
164 }
165 }
166
new_c_block(cdrom_paranoia * p)167 c_block *new_c_block(cdrom_paranoia *p)
168 {
169 linked_element *e = new_elem(p->cache);
170 c_block *c = e->ptr;
171
172 c->e = e;
173 c->p = p;
174 return (c);
175 }
176
free_c_block(c_block * c)177 void free_c_block(c_block *c)
178 {
179 /*
180 * also rid ourselves of v_fragments that reference this block
181 */
182 v_fragment *v = v_first(c->p);
183
184 while (v) {
185 v_fragment *next = v_next(v);
186
187 if (v->one == c)
188 free_v_fragment(v);
189 v = next;
190 }
191
192 free_elem(c->e, 1);
193 }
194
195 #define vp_vfragment_constructor_func ((void*(*)(void))i_vfragment_constructor)
i_vfragment_constructor()196 static v_fragment *i_vfragment_constructor()
197 {
198 v_fragment *ret = _pcalloc(1, sizeof (v_fragment));
199
200 return (ret);
201 }
202
203 #define vp_v_fragment_destructor_func ((void(*)(void*))i_v_fragment_destructor)
i_v_fragment_destructor(v_fragment * v)204 static void i_v_fragment_destructor(v_fragment *v)
205 {
206 _pfree(v);
207 }
208
new_v_fragment(cdrom_paranoia * p,c_block * one,long begin,long end,int last)209 v_fragment *new_v_fragment(cdrom_paranoia *p, c_block *one, long begin,
210 long end, int last)
211 {
212 linked_element *e = new_elem(p->fragments);
213 v_fragment *b = e->ptr;
214
215 b->e = e;
216 b->p = p;
217
218 b->one = one;
219 b->begin = begin;
220 b->vector = one->vector + begin - one->begin;
221 b->size = end - begin;
222 b->lastsector = last;
223
224 return (b);
225 }
226
free_v_fragment(v_fragment * v)227 void free_v_fragment(v_fragment *v)
228 {
229 free_elem(v->e, 1);
230 }
231
c_first(cdrom_paranoia * p)232 c_block *c_first(cdrom_paranoia *p)
233 {
234 if (p->cache->head)
235 return (p->cache->head->ptr);
236 return (NULL);
237 }
238
c_last(cdrom_paranoia * p)239 c_block* c_last(cdrom_paranoia *p)
240 {
241 if (p->cache->tail)
242 return (p->cache->tail->ptr);
243 return (NULL);
244 }
245
c_next(c_block * c)246 c_block *c_next(c_block *c)
247 {
248 if (c->e->next)
249 return (c->e->next->ptr);
250 return (NULL);
251 }
252
c_prev(c_block * c)253 c_block *c_prev(c_block *c)
254 {
255 if (c->e->prev)
256 return (c->e->prev->ptr);
257 return (NULL);
258 }
259
v_first(cdrom_paranoia * p)260 v_fragment *v_first(cdrom_paranoia *p)
261 {
262 if (p->fragments->head) {
263 return (p->fragments->head->ptr);
264 }
265 return (NULL);
266 }
267
v_last(cdrom_paranoia * p)268 v_fragment *v_last(cdrom_paranoia *p)
269 {
270 if (p->fragments->tail)
271 return (p->fragments->tail->ptr);
272 return (NULL);
273 }
274
v_next(v_fragment * v)275 v_fragment *v_next(v_fragment *v)
276 {
277 if (v->e->next)
278 return (v->e->next->ptr);
279 return (NULL);
280 }
281
v_prev(v_fragment * v)282 v_fragment *v_prev(v_fragment *v)
283 {
284 if (v->e->prev)
285 return (v->e->prev->ptr);
286 return (NULL);
287 }
288
recover_cache(cdrom_paranoia * p)289 void recover_cache(cdrom_paranoia *p)
290 {
291 linked_list *l = p->cache;
292
293 /*
294 * Are we at/over our allowed cache size?
295 */
296 while (l->active > p->cache_limit) {
297 /*
298 * cull from the tail of the list
299 */
300 free_c_block(c_last(p));
301 }
302
303 }
304
v_buffer(v_fragment * v)305 Int16_t *v_buffer(v_fragment *v)
306 {
307 if (!v->one)
308 return (NULL);
309 if (!cv(v->one))
310 return (NULL);
311 return (v->vector);
312 }
313
314 /*
315 * alloc a c_block not on a cache list
316 */
c_alloc(Int16_t * vector,long begin,long size)317 c_block *c_alloc(Int16_t *vector, long begin, long size)
318 {
319 c_block *c = _pcalloc(1, sizeof (c_block));
320
321 c->vector = vector;
322 c->begin = begin;
323 c->size = size;
324 return (c);
325 }
326
c_set(c_block * v,long begin)327 void c_set(c_block *v, long begin)
328 {
329 v->begin = begin;
330 }
331
332 /*
333 * pos here is vector position from zero
334 */
c_insert(c_block * v,long pos,Int16_t * b,long size)335 void c_insert(c_block *v, long pos, Int16_t *b, long size)
336 {
337 int vs = cs(v);
338
339 if (pos < 0 || pos > vs)
340 return;
341
342 if (v->vector)
343 v->vector = _prealloc(v->vector, sizeof (Int16_t) * (size + vs));
344 else
345 v->vector = _pmalloc(sizeof (Int16_t) * size);
346
347 if (pos < vs)
348 memmove(v->vector + pos + size, v->vector + pos,
349 (vs - pos) * sizeof (Int16_t));
350 memcpy(v->vector + pos, b, size * sizeof (Int16_t));
351
352 v->size += size;
353 }
354
c_remove(c_block * v,long cutpos,long cutsize)355 void c_remove(c_block *v, long cutpos, long cutsize)
356 {
357 int vs = cs(v);
358
359 if (cutpos < 0 || cutpos > vs)
360 return;
361 if (cutpos + cutsize > vs)
362 cutsize = vs - cutpos;
363 if (cutsize < 0)
364 cutsize = vs - cutpos;
365 if (cutsize < 1)
366 return;
367
368 memmove(v->vector + cutpos, v->vector + cutpos + cutsize,
369 (vs - cutpos - cutsize) * sizeof (Int16_t));
370
371 v->size -= cutsize;
372 }
373
c_overwrite(c_block * v,long pos,Int16_t * b,long size)374 void c_overwrite(c_block *v, long pos, Int16_t *b, long size)
375 {
376 int vs = cs(v);
377
378 if (pos < 0)
379 return;
380 if (pos + size > vs)
381 size = vs - pos;
382
383 memcpy(v->vector + pos, b, size * sizeof (Int16_t));
384 }
385
c_append(c_block * v,Int16_t * vector,long size)386 void c_append(c_block *v, Int16_t *vector, long size)
387 {
388 int vs = cs(v);
389
390 /*
391 * update the vector
392 */
393 if (v->vector)
394 v->vector = _prealloc(v->vector, sizeof (Int16_t) * (size + vs));
395 else
396 v->vector = _pmalloc(sizeof (Int16_t) * size);
397 memcpy(v->vector + vs, vector, sizeof (Int16_t) * size);
398
399 v->size += size;
400 }
401
c_removef(c_block * v,long cut)402 void c_removef(c_block *v, long cut)
403 {
404 c_remove(v, 0, cut);
405 v->begin += cut;
406 }
407
408
409
410 /*
411 * Initialization
412 */
i_paranoia_firstlast(cdrom_paranoia * p)413 void i_paranoia_firstlast(cdrom_paranoia *p)
414 {
415 int i;
416 void *d = p->d;
417
418 p->current_lastsector = -1;
419 for (i = cdda_sector_gettrack(d, p->cursor); i < cdda_tracks(d); i++)
420 if (!cdda_track_audiop(d, i))
421 p->current_lastsector = cdda_track_lastsector(d, i - 1);
422 if (p->current_lastsector == -1)
423 p->current_lastsector = cdda_disc_lastsector(d);
424
425 p->current_firstsector = -1;
426 for (i = cdda_sector_gettrack(d, p->cursor); i > 0; i--)
427 if (!cdda_track_audiop(d, i))
428 p->current_firstsector = cdda_track_firstsector(d, i + 1);
429 if (p->current_firstsector == -1)
430 p->current_firstsector = cdda_disc_firstsector(d);
431
432 }
433
paranoia_init(void * d,int nsectors)434 cdrom_paranoia *paranoia_init(void *d, int nsectors)
435 {
436 cdrom_paranoia *p = _pcalloc(1, sizeof (cdrom_paranoia));
437
438 p->cache = new_list(vp_cblock_constructor_func,
439 vp_cblock_destructor_func);
440
441 p->fragments = new_list(vp_vfragment_constructor_func,
442 vp_v_fragment_destructor_func);
443
444 p->nsectors = nsectors;
445 p->readahead = 150;
446 p->sortcache = sort_alloc(p->readahead * CD_FRAMEWORDS);
447 p->d = d;
448 p->mindynoverlap = MIN_SECTOR_EPSILON;
449 p->maxdynoverlap = MAX_SECTOR_OVERLAP * CD_FRAMEWORDS;
450 p->maxdynoverlap = (nsectors - 1) * CD_FRAMEWORDS;
451 p->dynoverlap = MAX_SECTOR_OVERLAP * CD_FRAMEWORDS;
452 p->cache_limit = JIGGLE_MODULO;
453 p->enable = PARANOIA_MODE_FULL;
454 p->cursor = cdda_disc_firstsector(d);
455 p->lastread = -1000000;
456
457 /*
458 * One last one... in case data and audio tracks are mixed...
459 */
460 i_paranoia_firstlast(p);
461
462 return (p);
463 }
464
paranoia_dynoverlapset(cdrom_paranoia * p,int minoverlap,int maxoverlap)465 void paranoia_dynoverlapset(cdrom_paranoia *p, int minoverlap, int maxoverlap)
466 {
467 if (minoverlap >= 0)
468 p->mindynoverlap = minoverlap;
469 if (maxoverlap > minoverlap)
470 p->maxdynoverlap = maxoverlap;
471
472 if (p->maxdynoverlap < p->mindynoverlap)
473 p->maxdynoverlap = p->mindynoverlap;
474 }
475