/* * This file has been modified for the cdrkit suite. * * The behaviour and appearence of the program code below can differ to a major * extent from the version distributed by the original author(s). * * For details, see Changelog file distributed with the cdrkit package. If you * received this file from another source then ask the distributing person for * a log of modifications. * */ /* @(#)p_block.c 1.19 04/02/23 J. Schilling from cdparanoia-III-alpha9.8 */ /* * Modifications to make the code portable Copyright (c) 2002 J. Schilling */ #include #include #include #include #include #include "p_block.h" #include "cdda_paranoia.h" #include "pmalloc.h" linked_list *new_list(void *(*newp) (void), void (*freep) (void *)); linked_element *add_elem(linked_list *l, void *elem); linked_element *new_elem(linked_list *list); void free_elem(linked_element *e, int free_ptr); void free_list(linked_list *list, int free_ptr); void *get_elem(linked_element *e); linked_list *copy_list(linked_list *list); static c_block *i_cblock_constructor(void); void i_cblock_destructor(c_block *c); c_block *new_c_block(cdrom_paranoia *p); void free_c_block(c_block *c); static v_fragment *i_vfragment_constructor(void); static void i_v_fragment_destructor(v_fragment *v); v_fragment *new_v_fragment(cdrom_paranoia *p, c_block *one, long begin, long end, int last); void free_v_fragment(v_fragment *v); c_block *c_first(cdrom_paranoia *p); c_block *c_last(cdrom_paranoia *p); c_block *c_next(c_block *c); c_block *c_prev(c_block *c); v_fragment *v_first(cdrom_paranoia *p); v_fragment *v_last(cdrom_paranoia *p); v_fragment *v_next(v_fragment *v); v_fragment *v_prev(v_fragment *v); void recover_cache(cdrom_paranoia *p); Int16_t *v_buffer(v_fragment *v); c_block *c_alloc(Int16_t *vector, long begin, long size); void c_set(c_block *v, long begin); void c_remove(c_block *v, long cutpos, long cutsize); void c_overwrite(c_block *v, long pos, Int16_t *b, long size); void c_append(c_block *v, Int16_t *vector, long size); void c_removef(c_block *v, long cut); void i_paranoia_firstlast(cdrom_paranoia *p); cdrom_paranoia *paranoia_init(void *d, int nsectors); linked_list *new_list(void *(*newp)(void), void (*freep)(void *)) { linked_list *ret = _pcalloc(1, sizeof (linked_list)); ret->new_poly = newp; ret->free_poly = freep; return (ret); } linked_element *add_elem(linked_list *l, void *elem) { linked_element *ret = _pcalloc(1, sizeof (linked_element)); ret->stamp = l->current++; ret->ptr = elem; ret->list = l; if (l->head) l->head->prev = ret; else l->tail = ret; ret->next = l->head; ret->prev = NULL; l->head = ret; l->active++; return (ret); } linked_element *new_elem(linked_list *list) { void *new = list->new_poly(); return (add_elem(list, new)); } void free_elem(linked_element *e, int free_ptr) { linked_list *l = e->list; if (free_ptr) l->free_poly(e->ptr); if (e == l->head) l->head = e->next; if (e == l->tail) l->tail = e->prev; if (e->prev) e->prev->next = e->next; if (e->next) e->next->prev = e->prev; l->active--; _pfree(e); } void free_list(linked_list *list, int free_ptr) { while (list->head) free_elem(list->head, free_ptr); _pfree(list); } void *get_elem(linked_element *e) { return (e->ptr); } linked_list *copy_list(linked_list *list) { linked_list *new = new_list(list->new_poly, list->free_poly); linked_element *i = list->tail; while (i) { add_elem(new, i->ptr); i = i->prev; } return (new); } /**** C_block stuff ******************************************************/ #define vp_cblock_constructor_func ((void*(*)(void))i_cblock_constructor) static c_block *i_cblock_constructor() { c_block *ret = _pcalloc(1, sizeof (c_block)); return (ret); } #define vp_cblock_destructor_func ((void(*)(void*))i_cblock_destructor) void i_cblock_destructor(c_block *c) { if (c) { if (c->vector) _pfree(c->vector); if (c->flags) _pfree(c->flags); c->e = NULL; _pfree(c); } } c_block *new_c_block(cdrom_paranoia *p) { linked_element *e = new_elem(p->cache); c_block *c = e->ptr; c->e = e; c->p = p; return (c); } void free_c_block(c_block *c) { /* * also rid ourselves of v_fragments that reference this block */ v_fragment *v = v_first(c->p); while (v) { v_fragment *next = v_next(v); if (v->one == c) free_v_fragment(v); v = next; } free_elem(c->e, 1); } #define vp_vfragment_constructor_func ((void*(*)(void))i_vfragment_constructor) static v_fragment *i_vfragment_constructor() { v_fragment *ret = _pcalloc(1, sizeof (v_fragment)); return (ret); } #define vp_v_fragment_destructor_func ((void(*)(void*))i_v_fragment_destructor) static void i_v_fragment_destructor(v_fragment *v) { _pfree(v); } v_fragment *new_v_fragment(cdrom_paranoia *p, c_block *one, long begin, long end, int last) { linked_element *e = new_elem(p->fragments); v_fragment *b = e->ptr; b->e = e; b->p = p; b->one = one; b->begin = begin; b->vector = one->vector + begin - one->begin; b->size = end - begin; b->lastsector = last; return (b); } void free_v_fragment(v_fragment *v) { free_elem(v->e, 1); } c_block *c_first(cdrom_paranoia *p) { if (p->cache->head) return (p->cache->head->ptr); return (NULL); } c_block* c_last(cdrom_paranoia *p) { if (p->cache->tail) return (p->cache->tail->ptr); return (NULL); } c_block *c_next(c_block *c) { if (c->e->next) return (c->e->next->ptr); return (NULL); } c_block *c_prev(c_block *c) { if (c->e->prev) return (c->e->prev->ptr); return (NULL); } v_fragment *v_first(cdrom_paranoia *p) { if (p->fragments->head) { return (p->fragments->head->ptr); } return (NULL); } v_fragment *v_last(cdrom_paranoia *p) { if (p->fragments->tail) return (p->fragments->tail->ptr); return (NULL); } v_fragment *v_next(v_fragment *v) { if (v->e->next) return (v->e->next->ptr); return (NULL); } v_fragment *v_prev(v_fragment *v) { if (v->e->prev) return (v->e->prev->ptr); return (NULL); } void recover_cache(cdrom_paranoia *p) { linked_list *l = p->cache; /* * Are we at/over our allowed cache size? */ while (l->active > p->cache_limit) { /* * cull from the tail of the list */ free_c_block(c_last(p)); } } Int16_t *v_buffer(v_fragment *v) { if (!v->one) return (NULL); if (!cv(v->one)) return (NULL); return (v->vector); } /* * alloc a c_block not on a cache list */ c_block *c_alloc(Int16_t *vector, long begin, long size) { c_block *c = _pcalloc(1, sizeof (c_block)); c->vector = vector; c->begin = begin; c->size = size; return (c); } void c_set(c_block *v, long begin) { v->begin = begin; } /* * pos here is vector position from zero */ void c_insert(c_block *v, long pos, Int16_t *b, long size) { int vs = cs(v); if (pos < 0 || pos > vs) return; if (v->vector) v->vector = _prealloc(v->vector, sizeof (Int16_t) * (size + vs)); else v->vector = _pmalloc(sizeof (Int16_t) * size); if (pos < vs) memmove(v->vector + pos + size, v->vector + pos, (vs - pos) * sizeof (Int16_t)); memcpy(v->vector + pos, b, size * sizeof (Int16_t)); v->size += size; } void c_remove(c_block *v, long cutpos, long cutsize) { int vs = cs(v); if (cutpos < 0 || cutpos > vs) return; if (cutpos + cutsize > vs) cutsize = vs - cutpos; if (cutsize < 0) cutsize = vs - cutpos; if (cutsize < 1) return; memmove(v->vector + cutpos, v->vector + cutpos + cutsize, (vs - cutpos - cutsize) * sizeof (Int16_t)); v->size -= cutsize; } void c_overwrite(c_block *v, long pos, Int16_t *b, long size) { int vs = cs(v); if (pos < 0) return; if (pos + size > vs) size = vs - pos; memcpy(v->vector + pos, b, size * sizeof (Int16_t)); } void c_append(c_block *v, Int16_t *vector, long size) { int vs = cs(v); /* * update the vector */ if (v->vector) v->vector = _prealloc(v->vector, sizeof (Int16_t) * (size + vs)); else v->vector = _pmalloc(sizeof (Int16_t) * size); memcpy(v->vector + vs, vector, sizeof (Int16_t) * size); v->size += size; } void c_removef(c_block *v, long cut) { c_remove(v, 0, cut); v->begin += cut; } /* * Initialization */ void i_paranoia_firstlast(cdrom_paranoia *p) { int i; void *d = p->d; p->current_lastsector = -1; for (i = cdda_sector_gettrack(d, p->cursor); i < cdda_tracks(d); i++) if (!cdda_track_audiop(d, i)) p->current_lastsector = cdda_track_lastsector(d, i - 1); if (p->current_lastsector == -1) p->current_lastsector = cdda_disc_lastsector(d); p->current_firstsector = -1; for (i = cdda_sector_gettrack(d, p->cursor); i > 0; i--) if (!cdda_track_audiop(d, i)) p->current_firstsector = cdda_track_firstsector(d, i + 1); if (p->current_firstsector == -1) p->current_firstsector = cdda_disc_firstsector(d); } cdrom_paranoia *paranoia_init(void *d, int nsectors) { cdrom_paranoia *p = _pcalloc(1, sizeof (cdrom_paranoia)); p->cache = new_list(vp_cblock_constructor_func, vp_cblock_destructor_func); p->fragments = new_list(vp_vfragment_constructor_func, vp_v_fragment_destructor_func); p->nsectors = nsectors; p->readahead = 150; p->sortcache = sort_alloc(p->readahead * CD_FRAMEWORDS); p->d = d; p->mindynoverlap = MIN_SECTOR_EPSILON; p->maxdynoverlap = MAX_SECTOR_OVERLAP * CD_FRAMEWORDS; p->maxdynoverlap = (nsectors - 1) * CD_FRAMEWORDS; p->dynoverlap = MAX_SECTOR_OVERLAP * CD_FRAMEWORDS; p->cache_limit = JIGGLE_MODULO; p->enable = PARANOIA_MODE_FULL; p->cursor = cdda_disc_firstsector(d); p->lastread = -1000000; /* * One last one... in case data and audio tracks are mixed... */ i_paranoia_firstlast(p); return (p); } void paranoia_dynoverlapset(cdrom_paranoia *p, int minoverlap, int maxoverlap) { if (minoverlap >= 0) p->mindynoverlap = minoverlap; if (maxoverlap > minoverlap) p->maxdynoverlap = maxoverlap; if (p->maxdynoverlap < p->mindynoverlap) p->maxdynoverlap = p->mindynoverlap; }