Imported Upstream version 1.1.11
[platform/upstream/cdrkit.git] / libparanoia / p_block.c
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
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
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
92 linked_element *new_elem(linked_list *list)
93 {
94         void            *new = list->new_poly();
95
96         return (add_elem(list, new));
97 }
98
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
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
127 void *get_elem(linked_element *e)
128 {
129         return (e->ptr);
130 }
131
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)
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)
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
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
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)
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)
204 static void i_v_fragment_destructor(v_fragment *v)
205 {
206         _pfree(v);
207 }
208
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
227 void free_v_fragment(v_fragment *v)
228 {
229         free_elem(v->e, 1);
230 }
231
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
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
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
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
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
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
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
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
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
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  */
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
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  */
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
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
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
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
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  */
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
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
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 }