1 /* @(#)p_block.c 1.30 19/04/03 J. Schilling from cdparanoia-III-alpha9.8 */
2 #include <schily/mconfig.h>
3 #ifndef lint
4 static UConst char sccsid[] =
5 "@(#)p_block.c 1.30 19/04/03 J. Schilling from cdparanoia-III-alpha9.8";
6
7 #endif
8 /*
9 * CopyPolicy: GNU Lesser General Public License v2.1 applies
10 * Copyright (C) 1997-2001,2008 by Monty (xiphmont@mit.edu)
11 * Copyright (C) 2002-2019 by J. Schilling
12 */
13 #include <schily/stdlib.h>
14 #include <schily/standard.h>
15 #include <schily/utypes.h>
16 #include <schily/string.h>
17 #include "p_block.h"
18 #include "cdda_paranoia.h"
19 #include "pmalloc.h"
20
21 EXPORT linked_list *new_list __PR((void *(*newp) (void),
22 void (*freep) (void *)));
23 EXPORT linked_element *add_elem __PR((linked_list * l, void *elem));
24 EXPORT linked_element *new_elem __PR((linked_list * list));
25 EXPORT void free_elem __PR((linked_element * e,
26 int free_ptr));
27 EXPORT void free_list __PR((linked_list * list,
28 int free_ptr));
29 EXPORT void *get_elem __PR((linked_element * e));
30 EXPORT linked_list *copy_list __PR((linked_list * list));
31 LOCAL c_block *i_cblock_constructor __PR((void));
32 EXPORT void i_cblock_destructor __PR((c_block * c));
33 EXPORT c_block *new_c_block __PR((cdrom_paranoia * p));
34 EXPORT void free_c_block __PR((c_block * c));
35 LOCAL v_fragment *i_vfragment_constructor __PR((void));
36 LOCAL void i_v_fragment_destructor __PR((v_fragment * v));
37 EXPORT v_fragment *new_v_fragment __PR((cdrom_paranoia * p,
38 c_block * one,
39 long begin, long end, int last));
40 EXPORT void free_v_fragment __PR((v_fragment * v));
41 EXPORT c_block *c_first __PR((cdrom_paranoia * p));
42 EXPORT c_block *c_last __PR((cdrom_paranoia * p));
43 EXPORT c_block *c_next __PR((c_block * c));
44 EXPORT c_block *c_prev __PR((c_block * c));
45 EXPORT v_fragment *v_first __PR((cdrom_paranoia * p));
46 EXPORT v_fragment *v_last __PR((cdrom_paranoia * p));
47 EXPORT v_fragment *v_next __PR((v_fragment * v));
48 EXPORT v_fragment *v_prev __PR((v_fragment * v));
49 EXPORT void recover_cache __PR((cdrom_paranoia * p));
50 EXPORT Int16_t *v_buffer __PR((v_fragment * v));
51 EXPORT c_block *c_alloc __PR((Int16_t * vector,
52 long begin, long size));
53 EXPORT void c_set __PR((c_block * v, long begin));
54 EXPORT void c_remove __PR((c_block * v,
55 long cutpos, long cutsize));
56 EXPORT void c_overwrite __PR((c_block * v,
57 long pos, Int16_t * b,
58 long size));
59 EXPORT void c_append __PR((c_block * v,
60 Int16_t * vector, long size));
61 EXPORT void c_removef __PR((c_block * v, long cut));
62 EXPORT void i_paranoia_firstlast __PR((cdrom_paranoia * p));
63 EXPORT cdrom_paranoia *paranoia_init __PR((void * d, int nsectors,
64 long (*d_read) __PR((void *d, void *buffer,
65 long beginsector,
66 long sectors)),
67 long (*d_disc_firstsector) __PR((void *d)),
68 long (*d_disc_lastsector) __PR((void *d)),
69 int (*d_tracks) __PR((void *d)),
70 long (*d_track_firstsector) __PR((void *d, int track)),
71 long (*d_track_lastsector) __PR((void *d, int track)),
72 int (*d_sector_gettrack) __PR((void *d, long sector)),
73 int (*d_track_audiop) __PR((void *d, int track))));
74
75 EXPORT linked_list *
76 new_list(newp, freep)
77 void *(*newp) __PR((void));
78 void (*freep) __PR((void *));
79 {
80 linked_list *ret = _pcalloc(1, sizeof (linked_list));
81
82 DBG_MALLOC_MARK(ret);
83 ret->new_poly = newp;
84 ret->free_poly = freep;
85 return (ret);
86 }
87
88 EXPORT linked_element *
add_elem(l,elem)89 add_elem(l, elem)
90 linked_list *l;
91 void *elem;
92 {
93
94 linked_element *ret = _pcalloc(1, sizeof (linked_element));
95
96 DBG_MALLOC_MARK(ret);
97 ret->stamp = l->current++;
98 ret->ptr = elem;
99 ret->list = l;
100
101 if (l->head)
102 l->head->prev = ret;
103 else
104 l->tail = ret;
105 ret->next = l->head;
106 ret->prev = NULL;
107 l->head = ret;
108 l->active++;
109
110 return (ret);
111 }
112
113 EXPORT linked_element *
new_elem(list)114 new_elem(list)
115 linked_list *list;
116 {
117 void *new = list->new_poly();
118
119 return (add_elem(list, new));
120 }
121
122 EXPORT void
free_elem(e,free_ptr)123 free_elem(e, free_ptr)
124 linked_element *e;
125 int free_ptr;
126 {
127 linked_list *l = e->list;
128
129 if (free_ptr)
130 l->free_poly(e->ptr);
131
132 if (e == l->head)
133 l->head = e->next;
134 if (e == l->tail)
135 l->tail = e->prev;
136
137 if (e->prev)
138 e->prev->next = e->next;
139 if (e->next)
140 e->next->prev = e->prev;
141
142 l->active--;
143 _pfree(e);
144 }
145
146 EXPORT void
free_list(list,free_ptr)147 free_list(list, free_ptr)
148 linked_list *list;
149 int free_ptr;
150 {
151 while (list->head)
152 free_elem(list->head, free_ptr);
153 _pfree(list);
154 }
155
156 EXPORT void *
get_elem(e)157 get_elem(e)
158 linked_element *e;
159 {
160 return (e->ptr);
161 }
162
163 EXPORT linked_list *
copy_list(list)164 copy_list(list)
165 linked_list *list;
166 {
167 linked_list *new = new_list(list->new_poly, list->free_poly);
168 linked_element *i = list->tail;
169
170 while (i) {
171 add_elem(new, i->ptr);
172 i = i->prev;
173 }
174 return (new);
175 }
176
177 /**** C_block stuff ******************************************************/
178
179 #define vp_cblock_constructor_func ((void*(*)__PR((void)))i_cblock_constructor)
180 LOCAL c_block *
i_cblock_constructor()181 i_cblock_constructor()
182 {
183 c_block *ret = _pcalloc(1, sizeof (c_block));
184
185 DBG_MALLOC_MARK(ret);
186 return (ret);
187 }
188
189 #define vp_cblock_destructor_func ((void(*)__PR((void*)))i_cblock_destructor)
190 EXPORT void
i_cblock_destructor(c)191 i_cblock_destructor(c)
192 c_block *c;
193 {
194 if (c) {
195 if (c->vector)
196 _pfree(c->vector);
197 if (c->flags)
198 _pfree(c->flags);
199 c->e = NULL;
200 _pfree(c);
201 }
202 }
203
204 EXPORT c_block *
new_c_block(p)205 new_c_block(p)
206 cdrom_paranoia *p;
207 {
208 linked_element *e = new_elem(p->cache);
209 c_block *c = e->ptr;
210
211 c->e = e;
212 c->p = p;
213 return (c);
214 }
215
216 EXPORT void
free_c_block(c)217 free_c_block(c)
218 c_block *c;
219 {
220 /*
221 * also rid ourselves of v_fragments that reference this block
222 */
223 v_fragment *v = v_first(c->p);
224
225 while (v) {
226 v_fragment *next = v_next(v);
227
228 if (v->one == c)
229 free_v_fragment(v);
230 v = next;
231 }
232
233 free_elem(c->e, 1);
234 }
235
236 #define vp_vfragment_constructor_func ((void*(*)__PR((void)))i_vfragment_constructor)
237 LOCAL v_fragment *
i_vfragment_constructor()238 i_vfragment_constructor()
239 {
240 v_fragment *ret = _pcalloc(1, sizeof (v_fragment));
241
242 DBG_MALLOC_MARK(ret);
243 return (ret);
244 }
245
246 #define vp_v_fragment_destructor_func ((void(*)__PR((void*)))i_v_fragment_destructor)
247 LOCAL void
i_v_fragment_destructor(v)248 i_v_fragment_destructor(v)
249 v_fragment *v;
250 {
251 _pfree(v);
252 }
253
254 EXPORT v_fragment *
new_v_fragment(p,one,begin,end,last)255 new_v_fragment(p, one, begin, end, last)
256 cdrom_paranoia *p;
257 c_block *one;
258 long begin;
259 long end;
260 int last;
261 {
262 linked_element *e = new_elem(p->fragments);
263 v_fragment *b = e->ptr;
264
265 b->e = e;
266 b->p = p;
267
268 b->one = one;
269 b->begin = begin;
270 b->vector = one->vector + begin - one->begin;
271 b->size = end - begin;
272 b->lastsector = last;
273
274 return (b);
275 }
276
277 EXPORT void
free_v_fragment(v)278 free_v_fragment(v)
279 v_fragment *v;
280 {
281 free_elem(v->e, 1);
282 }
283
284 EXPORT c_block *
c_first(p)285 c_first(p)
286 cdrom_paranoia *p;
287 {
288 if (p->cache->head)
289 return (p->cache->head->ptr);
290 return (NULL);
291 }
292
293 EXPORT c_block*
c_last(p)294 c_last(p)
295 cdrom_paranoia *p;
296 {
297 if (p->cache->tail)
298 return (p->cache->tail->ptr);
299 return (NULL);
300 }
301
302 EXPORT c_block *
c_next(c)303 c_next(c)
304 c_block *c;
305 {
306 if (c->e->next)
307 return (c->e->next->ptr);
308 return (NULL);
309 }
310
311 EXPORT c_block *
c_prev(c)312 c_prev(c)
313 c_block *c;
314 {
315 if (c->e->prev)
316 return (c->e->prev->ptr);
317 return (NULL);
318 }
319
320 EXPORT v_fragment *
v_first(p)321 v_first(p)
322 cdrom_paranoia *p;
323 {
324 if (p->fragments->head) {
325 return (p->fragments->head->ptr);
326 }
327 return (NULL);
328 }
329
330 EXPORT v_fragment *
v_last(p)331 v_last(p)
332 cdrom_paranoia *p;
333 {
334 if (p->fragments->tail)
335 return (p->fragments->tail->ptr);
336 return (NULL);
337 }
338
339 EXPORT v_fragment *
v_next(v)340 v_next(v)
341 v_fragment *v;
342 {
343 if (v->e->next)
344 return (v->e->next->ptr);
345 return (NULL);
346 }
347
348 EXPORT v_fragment *
v_prev(v)349 v_prev(v)
350 v_fragment *v;
351 {
352 if (v->e->prev)
353 return (v->e->prev->ptr);
354 return (NULL);
355 }
356
357 EXPORT void
recover_cache(p)358 recover_cache(p)
359 cdrom_paranoia *p;
360 {
361 linked_list *l = p->cache;
362
363 /*
364 * Are we at/over our allowed cache size?
365 */
366 while (l->active > p->cache_limit) {
367 /*
368 * cull from the tail of the list
369 */
370 free_c_block(c_last(p));
371 }
372
373 }
374
375 EXPORT Int16_t *
v_buffer(v)376 v_buffer(v)
377 v_fragment *v;
378 {
379 if (!v->one)
380 return (NULL);
381 if (!cv(v->one))
382 return (NULL);
383 return (v->vector);
384 }
385
386 /*
387 * alloc a c_block not on a cache list
388 */
389 EXPORT c_block *
c_alloc(vector,begin,size)390 c_alloc(vector, begin, size)
391 Int16_t *vector;
392 long begin;
393 long size;
394 {
395 c_block *c = _pcalloc(1, sizeof (c_block));
396
397 DBG_MALLOC_MARK(c);
398 c->vector = vector;
399 c->begin = begin;
400 c->size = size;
401 return (c);
402 }
403
404 EXPORT void
c_set(v,begin)405 c_set(v, begin)
406 c_block *v;
407 long begin;
408 {
409 v->begin = begin;
410 }
411
412 /*
413 * pos here is vector position from zero
414 */
415 EXPORT void
c_insert(v,pos,b,size)416 c_insert(v, pos, b, size)
417 c_block *v;
418 long pos;
419 Int16_t *b;
420 long size;
421 {
422 int vs = cs(v);
423
424 if (pos < 0 || pos > vs)
425 return;
426
427 if (v->vector)
428 v->vector = _prealloc(v->vector, sizeof (Int16_t) * (size + vs));
429 else
430 v->vector = _pmalloc(sizeof (Int16_t) * size);
431
432 DBG_MALLOC_MARK(v->vector);
433 if (pos < vs)
434 memmove(v->vector + pos + size, v->vector + pos,
435 (vs - pos) * sizeof (Int16_t));
436 memcpy(v->vector + pos, b, size * sizeof (Int16_t));
437
438 v->size += size;
439 }
440
441 EXPORT void
c_remove(v,cutpos,cutsize)442 c_remove(v, cutpos, cutsize)
443 c_block *v;
444 long cutpos;
445 long cutsize;
446 {
447 int vs = cs(v);
448
449 if (cutpos < 0 || cutpos > vs)
450 return;
451 if (cutpos + cutsize > vs)
452 cutsize = vs - cutpos;
453 if (cutsize < 0)
454 cutsize = vs - cutpos;
455 if (cutsize < 1)
456 return;
457
458 memmove(v->vector + cutpos, v->vector + cutpos + cutsize,
459 (vs - cutpos - cutsize) * sizeof (Int16_t));
460
461 v->size -= cutsize;
462 }
463
464 EXPORT void
c_overwrite(v,pos,b,size)465 c_overwrite(v, pos, b, size)
466 c_block *v;
467 long pos;
468 Int16_t *b;
469 long size;
470 {
471 int vs = cs(v);
472
473 if (pos < 0)
474 return;
475 if (pos + size > vs)
476 size = vs - pos;
477
478 memcpy(v->vector + pos, b, size * sizeof (Int16_t));
479 }
480
481 EXPORT void
c_append(v,vector,size)482 c_append(v, vector, size)
483 c_block *v;
484 Int16_t *vector;
485 long size;
486 {
487 int vs = cs(v);
488
489 /*
490 * update the vector
491 */
492 if (v->vector)
493 v->vector = _prealloc(v->vector, sizeof (Int16_t) * (size + vs));
494 else
495 v->vector = _pmalloc(sizeof (Int16_t) * size);
496 DBG_MALLOC_MARK(v->vector);
497 memcpy(v->vector + vs, vector, sizeof (Int16_t) * size);
498
499 v->size += size;
500 }
501
502 EXPORT void
c_removef(v,cut)503 c_removef(v, cut)
504 c_block *v;
505 long cut;
506 {
507 c_remove(v, 0, cut);
508 v->begin += cut;
509 }
510
511
512
513 /*
514 * Initialization
515 */
516
517 /*
518 * Get the beginning and ending sector bounds given cursor position.
519 *
520 * There are a couple of subtle differences between this and the
521 * cdda_firsttrack_sector and cdda_lasttrack_sector. If the cursor is
522 * at a sector later than cdda_firsttrack_sector, that sector will be
523 * used. As for the difference between cdda_lasttrack_sector, if the CD
524 * is mixed and there is a data track after the cursor but before the
525 * last audio track, the end of the audio sector before that is used.
526 */
527 EXPORT void
i_paranoia_firstlast(p)528 i_paranoia_firstlast(p)
529 cdrom_paranoia *p;
530 {
531 int i;
532 void *d = p->d;
533
534 p->current_lastsector = -1;
535 for (i = p->d_sector_gettrack(d, p->cursor); i < p->d_tracks(d); i++)
536 if (!p->d_track_audiop(d, i))
537 p->current_lastsector = p->d_track_lastsector(d, i - 1);
538 if (p->current_lastsector == -1)
539 p->current_lastsector = p->d_disc_lastsector(d);
540
541 p->current_firstsector = -1;
542 for (i = p->d_sector_gettrack(d, p->cursor); i > 0; i--)
543 if (!p->d_track_audiop(d, i))
544 p->current_firstsector = p->d_track_firstsector(d, i + 1);
545 if (p->current_firstsector == -1)
546 p->current_firstsector = p->d_disc_firstsector(d);
547
548 }
549
550 EXPORT cdrom_paranoia *
paranoia_init(d,nsectors,d_read,d_disc_firstsector,d_disc_lastsector,d_tracks,d_track_firstsector,d_track_lastsector,d_sector_gettrack,d_track_audiop)551 paranoia_init(d, nsectors,
552 d_read,
553 d_disc_firstsector, d_disc_lastsector,
554 d_tracks,
555 d_track_firstsector, d_track_lastsector,
556 d_sector_gettrack, d_track_audiop)
557 void *d;
558 int nsectors;
559 long (*d_read) __PR((void *d, void *buffer,
560 long beginsector,
561 long sectors));
562 long (*d_disc_firstsector) __PR((void *d));
563 long (*d_disc_lastsector) __PR((void *d));
564 int (*d_tracks) __PR((void *d));
565 long (*d_track_firstsector) __PR((void *d, int track));
566 long (*d_track_lastsector) __PR((void *d, int track));
567 int (*d_sector_gettrack) __PR((void *d, long sector));
568 int (*d_track_audiop) __PR((void *d, int track));
569 {
570 cdrom_paranoia *p = _pcalloc(1, sizeof (cdrom_paranoia));
571
572 DBG_MALLOC_MARK(p);
573 p->d_read = d_read;
574 p->d_disc_firstsector = d_disc_firstsector;
575 p->d_disc_lastsector = d_disc_lastsector;
576 p->d_tracks = d_tracks;
577 p->d_track_firstsector = d_track_firstsector;
578 p->d_track_lastsector = d_track_lastsector;
579 p->d_sector_gettrack = d_sector_gettrack;
580 p->d_track_audiop = d_track_audiop;
581
582 p->cache = new_list(vp_cblock_constructor_func,
583 vp_cblock_destructor_func);
584
585 p->fragments = new_list(vp_vfragment_constructor_func,
586 vp_v_fragment_destructor_func);
587
588 p->nsectors = nsectors;
589 p->sectsize = CD_FRAMESIZE_RAW;
590 p->sectwords = CD_FRAMESIZE_RAW/2;
591 p->readahead = CD_READAHEAD;
592 p->sortcache = sort_alloc(p->readahead * CD_FRAMEWORDS);
593 DBG_MALLOC_MARK(p->sortcache);
594 p->d = d;
595 p->mindynoverlap = MIN_SECTOR_EPSILON;
596 p->maxdynoverlap = MAX_SECTOR_OVERLAP * CD_FRAMEWORDS;
597 p->maxdynoverlap = (nsectors - 1) * CD_FRAMEWORDS;
598 p->dynoverlap = MAX_SECTOR_OVERLAP * CD_FRAMEWORDS;
599 p->cache_limit = JIGGLE_MODULO;
600 p->enable = PARANOIA_MODE_FULL;
601 p->cursor = p->d_disc_firstsector(d);
602 p->lastread = -1000000;
603
604 /*
605 * One last one... in case data and audio tracks are mixed...
606 */
607 i_paranoia_firstlast(p);
608
609 return (p);
610 }
611
612 EXPORT void
paranoia_dynoverlapset(p,minoverlap,maxoverlap)613 paranoia_dynoverlapset(p, minoverlap, maxoverlap)
614 cdrom_paranoia *p;
615 int minoverlap;
616 int maxoverlap;
617 {
618 if (minoverlap >= 0)
619 p->mindynoverlap = minoverlap;
620 if (maxoverlap > p->mindynoverlap)
621 p->maxdynoverlap = maxoverlap;
622
623 if (p->maxdynoverlap < p->mindynoverlap)
624 p->maxdynoverlap = p->mindynoverlap;
625
626 if (p->dynoverlap < p->mindynoverlap)
627 p->dynoverlap = p->mindynoverlap;
628 if (p->dynoverlap > p->maxdynoverlap)
629 p->dynoverlap = p->maxdynoverlap;
630 }
631