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