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