This repository has been archived on 2025-05-24. You can view files and clone it, but cannot push or open issues or pull requests.
Files
libcdio-osx/lib/paranoia/paranoia.c
2005-10-23 12:17:30 +00:00

2002 lines
60 KiB
C

/*
$Id: paranoia.c,v 1.20 2005/10/23 12:17:30 rocky Exp $
Copyright (C) 2004, 2005 Rocky Bernstein <rocky@panix.com>
Copyright (C) 1998 Monty xiphmont@mit.edu
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/***
* Toplevel file for the paranoia abstraction over the cdda lib
*
***/
/* immediate todo:: */
/* Allow disabling of root fixups? */
/* Dupe bytes are creeping into cases that require greater overlap
than a single fragment can provide. We need to check against a
larger area* (+/-32 sectors of root?) to better eliminate
dupes. Of course this leads to other problems... Is it actually a
practically solvable problem? */
/* Bimodal overlap distributions break us. */
/* scratch detection/tolerance not implemented yet */
/***************************************************************
Da new shtick: verification now a two-step assymetric process.
A single 'verified/reconstructed' data segment cache, and then the
multiple fragment cache
verify a newly read block against previous blocks; do it only this
once. We maintain a list of 'verified sections' from these matches.
We then glom these verified areas into a new data buffer.
Defragmentation fixups are allowed here alone.
We also now track where read boundaries actually happened; do not
verify across matching boundaries.
**************************************************************/
/***************************************************************
Silence. "It's BAAAAAAaaack."
audio is now treated as great continents of values floating on a
mantle of molten silence. Silence is not handled by basic
verification at all; we simply anchor sections of nonzero audio to a
position and fill in everything else as silence. We also note the
audio that interfaces with silence; an edge must be 'wet'.
**************************************************************/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#ifdef HAVE_STDLIB_H
#include <stdlib.h>
#endif
#include <unistd.h>
#include <stdio.h>
#ifdef HAVE_STRING_H
#include <string.h>
#endif
#include <math.h>
#include <cdio/cdda.h>
#include "../cdda_interface/smallft.h"
#include "p_block.h"
#include <cdio/paranoia.h>
#include "overlap.h"
#include "gap.h"
#include "isort.h"
const char *paranoia_cb_mode2str[] = {
"read",
"verify",
"fixup edge",
"fixup atom",
"scratch",
"repair",
"skip",
"drift",
"backoff",
"overlap",
"fixup dropped",
"fixup duplicated",
"read error"
};
static inline long
re(root_block *root)
{
if (!root)return(-1);
if (!root->vector)return(-1);
return(ce(root->vector));
}
static inline long
rb(root_block *root)
{
if (!root)return(-1);
if (!root->vector)return(-1);
return(cb(root->vector));
}
static inline
long rs(root_block *root)
{
if (!root)return(-1);
if (!root->vector)return(-1);
return(cs(root->vector));
}
static inline int16_t *
rv(root_block *root){
if (!root)return(NULL);
if (!root->vector)return(NULL);
return(cv(root->vector));
}
#define rc(r) (r->vector)
/**
Flags indicating the status of a read samples.
Imagine the below enumeration values are #defines to be used in a
bitmask rather than distinct values of an enum.
The variable part of the declaration is trickery to force the enum
symbol values to be recorded in debug symbol tables. They are used
to allow one refer to the enumeration value names in a debugger
and in debugger expressions.
*/
enum {
FLAGS_EDGE =0x1, /**< first/last N words of frame */
FLAGS_UNREAD =0x2, /**< unread, hence missing and unmatchable */
FLAGS_VERIFIED=0x4 /**< block read and verified */
} paranoia_read_flags;
/**** matching and analysis code *****************************************/
/* ===========================================================================
* i_paranoia_overlap() (internal)
*
* This function is called when buffA[offsetA] == buffB[offsetB]. This
* function searches backward and forward to see how many consecutive
* samples also match.
*
* This function is called by do_const_sync() when we're not doing any
* verification. Its more complicated sibling is i_paranoia_overlap2.
*
* This function returns the number of consecutive matching samples.
* If (ret_begin) or (ret_end) are not NULL, it fills them with the
* offsets of the first and last matching samples in A.
*/
static inline long
i_paranoia_overlap(int16_t *buffA,int16_t *buffB,
long offsetA, long offsetB,
long sizeA,long sizeB,
long *ret_begin, long *ret_end)
{
long beginA=offsetA,endA=offsetA;
long beginB=offsetB,endB=offsetB;
/* Scan backward to extend the matching run in that direction. */
for(; beginA>=0 && beginB>=0; beginA--,beginB--)
if (buffA[beginA] != buffB[beginB]) break;
beginA++;
beginB++;
/* Scan forward to extend the matching run in that direction. */
for(; endA<sizeA && endB<sizeB; endA++,endB++)
if (buffA[endA] != buffB[endB]) break;
/* Return the result of our search. */
if (ret_begin) *ret_begin = beginA;
if (ret_end) *ret_end = endA;
return (endA-beginA);
}
/* ===========================================================================
* i_paranoia_overlap2() (internal)
*
* This function is called when buffA[offsetA] == buffB[offsetB]. This
* function searches backward and forward to see how many consecutive
* samples also match.
*
* This function is called by do_const_sync() when we're verifying the
* data coming off the CD. Its less complicated sibling is
* i_paranoia_overlap, which is a good place to look to see the simplest
* outline of how this function works.
*
* This function returns the number of consecutive matching samples.
* If (ret_begin) or (ret_end) are not NULL, it fills them with the
* offsets of the first and last matching samples in A.
*/
static inline long
i_paranoia_overlap2(int16_t *buffA,int16_t *buffB,
unsigned char *flagsA, unsigned char *flagsB,
long offsetA, long offsetB,
long sizeA,long sizeB,
long *ret_begin, long *ret_end)
{
long beginA=offsetA, endA=offsetA;
long beginB=offsetB, endB=offsetB;
/* Scan backward to extend the matching run in that direction. */
for (; beginA>=0 && beginB>=0; beginA--,beginB--) {
if (buffA[beginA] != buffB[beginB]) break;
/* don't allow matching across matching sector boundaries */
/* Stop if both samples were at the edges of a low-level read.
* ???: What implications does this have?
* ???: Why do we include the first sample for which this is true?
*/
if ((flagsA[beginA]&flagsB[beginB]&FLAGS_EDGE)) {
beginA--;
beginB--;
break;
}
/* don't allow matching through known missing data */
if ((flagsA[beginA]&FLAGS_UNREAD) || (flagsB[beginB]&FLAGS_UNREAD))
break;
}
beginA++;
beginB++;
/* Scan forward to extend the matching run in that direction. */
for (; endA<sizeA && endB<sizeB; endA++,endB++) {
if (buffA[endA] != buffB[endB]) break;
/* don't allow matching across matching sector boundaries */
/* Stop if both samples were at the edges of a low-level read.
* ???: What implications does this have?
* ???: Why do we not stop if endA == beginA?
*/
if ((flagsA[endA]&flagsB[endB]&FLAGS_EDGE) && endA!=beginA){
break;
}
/* don't allow matching through known missing data */
if ((flagsA[endA]&FLAGS_UNREAD) || (flagsB[endB]&FLAGS_UNREAD))
break;
}
/* Return the result of our search. */
if (ret_begin) *ret_begin = beginA;
if (ret_end) *ret_end = endA;
return (endA-beginA);
}
/* ===========================================================================
* do_const_sync() (internal)
*
* This function is called when samples A[posA] == B[posB]. It tries to
* build a matching run from that point, looking forward and backward to
* see how many consecutive samples match. Since the starting samples
* might only be coincidentally identical, we only consider the run to
* be a true match if it's longer than MIN_WORDS_SEARCH.
*
* This function returns the length of the run if a matching run was found,
* or 0 otherwise. If a matching run was found, (begin) and (end) are set
* to the absolute positions of the beginning and ending samples of the
* run in A, and (offset) is set to the jitter between the c_blocks.
* (I.e., offset indicates the distance between what A considers sample N
* on the CD and what B considers sample N.)
*/
static inline long int
do_const_sync(c_block_t *A,
sort_info_t *B, unsigned char *flagB,
long posA, long posB,
long *begin, long *end, long *offset)
{
unsigned char *flagA=A->flags;
long ret=0;
/* If we're doing any verification whatsoever, we have flags and will
* take them into account. Otherwise, we just do the simple equality
* test for samples on both sides of the initial match.
*/
if (flagB==NULL)
ret=i_paranoia_overlap(cv(A), iv(B), posA, posB,
cs(A), is(B), begin, end);
else
if ((flagB[posB]&FLAGS_UNREAD)==0)
ret=i_paranoia_overlap2(cv(A), iv(B), flagA, flagB,
posA, posB, cs(A), is(B),
begin, end);
/* Small matching runs could just be coincidental. We only consider this
* a real match if it's long enough.
*/
if (ret > MIN_WORDS_SEARCH) {
*offset=+(posA+cb(A))-(posB+ib(B));
/* ???: Contrary to the original comment, this appears to be relative to
* A, not B.
*/
*begin+=cb(A);
*end+=cb(A);
return(ret);
}
return(0);
}
/* ===========================================================================
* try_sort_sync() (internal)
*
* Starting from the sample in B with the absolute position (post), look
* for a matching run in A. This search will look in A for a first
* matching sample within (p->dynoverlap) samples around (post). If it
* finds one, it will then determine how many consecutive samples match
* both A and B from that point, looking backwards and forwards. If
* this search produces a matching run longer than MIN_WORDS_SEARCH, we
* consider it a match.
*
* When used by stage 1, the "post" is planted with respect to the old
* c_block being compare to the new c_block. In stage 2, the "post" is
* planted with respect to the verified root.
*
* This function returns 1 if a match is found and 0 if not. When a match
* is found, (begin) and (end) are set to the boundaries of the run, and
* (offset) is set to the difference in position of the run in A and B.
* (begin) and (end) are the absolute positions of the samples in
* A. (offset) counts from B's frame of reference. I.e., an offset of
* -2 would mean that A's absolute 3 is equivalent to B's 5.
*/
/* post is w.r.t. B. in stage one, we post from old. In stage 2 we
post from root. Begin, end, offset count from B's frame of
reference */
static inline long int
try_sort_sync(cdrom_paranoia_t *p,
sort_info_t *A, unsigned char *Aflags,
c_block_t *B,
long int post,
long int *begin,
long int *end,
long *offset,
void (*callback)(long int, paranoia_cb_mode_t))
{
long int dynoverlap=p->dynoverlap;
sort_link_t *ptr=NULL;
unsigned char *Bflags=B->flags;
/* block flag matches 0x02 (unmatchable) */
if (Bflags==NULL || (Bflags[post-cb(B)]&FLAGS_UNREAD)==0){
/* always try absolute offset zero first! */
{
long zeropos=post-ib(A);
if (zeropos>=0 && zeropos<is(A)) {
/* Before we bother with the search for a matching samples,
* we check the simple case. If there's no jitter at all
* (i.e. the absolute positions of A's and B's samples are
* consistent), A's sample at (post) should be identical
* to B's sample at the same position.
*/
if ( cv(B)[post-cb(B)] == iv(A)[zeropos] ) {
/* The first sample matched, now try to grow the matching run
* in both directions. We only consider it a match if more
* than MIN_WORDS_SEARCH consecutive samples match.
*/
if (do_const_sync(B, A, Aflags,
post-cb(B), zeropos,
begin, end, offset) ) {
/* ???: To be studied. */
offset_add_value(p,&(p->stage1),*offset,callback);
return(1);
}
}
}
}
} else
return(0);
/* If the samples with the same absolute position didn't match, it's
* either a bad sample, or the two c_blocks are jittered with respect
* to each other. Now we search through A for samples that do have
* the same value as B's post. The search looks from first to last
* occurrence witin (dynoverlap) samples of (post).
*/
ptr=sort_getmatch(A,post-ib(A),dynoverlap,cv(B)[post-cb(B)]);
while (ptr){
/* We've found a matching sample, so try to grow the matching run in
* both directions. If we find a long enough run (longer than
* MIN_WORDS_SEARCH), we've found a match.
*/
if (do_const_sync(B,A,Aflags,
post-cb(B),ipos(A,ptr),
begin,end,offset)){
/* ???: To be studied. */
offset_add_value(p,&(p->stage1),*offset,callback);
return(1);
}
/* The matching sample was just a fluke -- there weren't enough adjacent
* samples that matched to consider a matching run. So now we check
* for the next occurrence of that value in A.
*/
ptr=sort_nextmatch(A,ptr);
}
/* We didn't find any matches. */
*begin=-1;
*end=-1;
*offset=-1;
return(0);
}
/* ===========================================================================
* STAGE 1 MATCHING
*
* ???: Insert high-level explanation here.
* ===========================================================================
*/
/* Top level of the first stage matcher */
/* We match each analysis point of new to the preexisting blocks
recursively. We can also optionally maintain a list of fragments of
the preexisting block that didn't match anything, and match them back
afterward. */
#define OVERLAP_ADJ (MIN_WORDS_OVERLAP/2-1)
/* ===========================================================================
* stage1_matched() (internal)
*
* This function is called whenever stage 1 verification finds two identical
* runs of samples from different reads. The runs must be more than
* MIN_WORDS_SEARCH samples long. They may be jittered (i.e. their absolute
* positions on the CD may not match due to inaccurate seeking) with respect
* to each other, but they have been verified to have no dropped samples
* within them.
*
* This function provides feedback via the callback mechanism and marks the
* runs as verified. The details of the marking are somehwat subtle and
* are described near the relevant code.
*
* Subsequent portions of the stage 1 code will build a verified fragment
* from this run. The verified fragment will eventually be merged
* into the verified root (and its absolute position determined) in
* stage 2.
*/
static inline void
stage1_matched(c_block_t *old, c_block_t *new,
long matchbegin,long matchend,
long matchoffset,
void (*callback)(long int, paranoia_cb_mode_t))
{
long i;
long oldadjbegin=matchbegin-cb(old);
long oldadjend=matchend-cb(old);
long newadjbegin=matchbegin-matchoffset-cb(new);
long newadjend=matchend-matchoffset-cb(new);
/* Provide feedback via the callback about the samples we've just
* verified.
*
* ???: How can matchbegin ever be < cb(old)?
*
* ???: Why do edge samples get logged only when there's jitter
* between the matched runs (matchoffset != 0)?
*/
if ( matchbegin-matchoffset<=cb(new)
|| matchbegin<=cb(old)
|| (new->flags[newadjbegin]&FLAGS_EDGE)
|| (old->flags[oldadjbegin]&FLAGS_EDGE) ) {
if ( matchoffset && callback )
(*callback)(matchbegin,PARANOIA_CB_FIXUP_EDGE);
} else
if (callback)
(*callback)(matchbegin,PARANOIA_CB_FIXUP_ATOM);
if ( matchend-matchoffset>=ce(new) ||
(new->flags[newadjend]&FLAGS_EDGE) ||
matchend>=ce(old) ||
(old->flags[oldadjend]&FLAGS_EDGE) ) {
if ( matchoffset && callback )
(*callback)(matchend,PARANOIA_CB_FIXUP_EDGE);
} else
if (callback)
(*callback)(matchend, PARANOIA_CB_FIXUP_ATOM);
/* Mark verified samples as "verified," but trim the verified region
* by OVERLAP_ADJ samples on each side. There are several significant
* implications of this trimming:
*
* 1) Why we trim at all: We have to trim to distinguish between two
* adjacent verified runs and one long verified run. We encounter this
* situation when samples have been dropped:
*
* matched portion of read 1 ....)(.... matched portion of read 1
* read 2 adjacent run .....)(..... read 2 adjacent run
* ||
* dropped samples in read 2
*
* So at this point, the fact that we have two adjacent runs means
* that we have not yet verified that the two runs really are adjacent.
* (In fact, just the opposite: there are two runs because they were
* matched by separate runs, indicating that some samples didn't match
* across the length of read 2.)
*
* If we verify that they are actually adjacent (e.g. if the two runs
* are simply a result of matching runs from different reads, not from
* dropped samples), we will indeed mark them as one long merged run.
*
* 2) Why we trim by this amount: We want to ensure that when we
* verify the relationship between these two runs, we do so with
* an overlapping fragment at least OVERLAP samples long. Following
* from the above example:
*
* (..... matched portion of read 3 .....)
* read 2 adjacent run .....)(..... read 2 adjacent run
*
* Assuming there were no dropped samples between the adjacent runs,
* the matching portion of read 3 will need to be at least OVERLAP
* samples long to mark the two runs as one long verified run.
* If there were dropped samples, read 3 wouldn't match across the
* two runs, proving our caution worthwhile.
*
* 3) Why we partially discard the work we've done: We don't.
* When subsequently creating verified fragments from this run,
* we compensate for this trimming. Thus the verified fragment will
* contain the full length of verified samples. Only the c_blocks
* will reflect this trimming.
*
* ???: The comment below indicates that the sort cache is updated in
* some way, but this does not appear to be the case.
*/
/* Mark the verification flags. Don't mark the first or
last OVERLAP/2 elements so that overlapping fragments
have to overlap by OVERLAP to actually merge. We also
remove elements from the sort such that later sorts do
not have to sift through already matched data */
newadjbegin+=OVERLAP_ADJ;
newadjend-=OVERLAP_ADJ;
for(i=newadjbegin;i<newadjend;i++)
new->flags[i]|=FLAGS_VERIFIED; /* mark verified */
oldadjbegin+=OVERLAP_ADJ;
oldadjend-=OVERLAP_ADJ;
for(i=oldadjbegin;i<oldadjend;i++)
old->flags[i]|=FLAGS_VERIFIED; /* mark verified */
}
/* ===========================================================================
* i_iterate_stage1 (internal)
*
* This function is called by i_stage1() to compare newly read samples with
* previously read samples, searching for contiguous runs of identical
* samples. Matching runs indicate that at least two reads of the CD
* returned identical data, with no dropped samples in that run.
* The runs may be jittered (i.e. their absolute positions on the CD may
* not be accurate due to inaccurate seeking) at this point. Their
* positions will be determined in stage 2.
*
* This function compares the new c_block (which has been indexed in
* p->sortcache) to a previous c_block. It is called for each previous
* c_block. It searches for runs of identical samples longer than
* MIN_WORDS_SEARCH. Samples in matched runs are marked as verified.
*
* Subsequent stage 1 code builds verified fragments from the runs of
* verified samples. These fragments are merged into the verified root
* in stage 2.
*
* This function returns the number of distinct runs verified in the new
* c_block when compared against this old c_block.
*/
static long int
i_iterate_stage1(cdrom_paranoia_t *p, c_block_t *old, c_block_t *new,
void(*callback)(long int, paranoia_cb_mode_t))
{
long matchbegin = -1;
long matchend = -1;
long matchoffset;
/* ???: Why do we limit our search only to the samples with overlapping
* absolute positions? It could be because it eliminates some further
* bounds checking.
*
* Why do we "no longer try to spread the ... search" as mentioned below?
*/
/* we no longer try to spread the stage one search area by dynoverlap */
long searchend = min(ce(old), ce(new));
long searchbegin = max(cb(old), cb(new));
long searchsize = searchend-searchbegin;
sort_info_t *i = p->sortcache;
long ret = 0;
long int j;
long tried = 0;
long matched = 0;
if (searchsize<=0)
return(0);
/* match return values are in terms of the new vector, not old */
/* ???: Why 23? */
for (j=searchbegin; j<searchend; j+=23) {
/* Skip past any samples verified in previous comparisons to
* other old c_blocks. Also, obviously, don't bother verifying
* unread/unmatchable samples.
*/
if ((new->flags[j-cb(new)] & (FLAGS_VERIFIED|FLAGS_UNREAD)) == 0) {
tried++;
/* Starting from the sample in the old c_block with the absolute
* position j, look for a matching run in the new c_block. This
* search will look a certain distance around j, and if successful
* will extend the matching run as far backward and forward as
* it can.
*
* The search will only return 1 if it finds a matching run long
* enough to be deemed significant.
*/
if (try_sort_sync(p, i, new->flags, old, j,
&matchbegin, &matchend, &matchoffset,
callback) == 1) {
matched+=matchend-matchbegin;
/* purely cosmetic: if we're matching zeros, don't use the
callback because they will appear to be all skewed */
{
long j = matchbegin-cb(old);
long end = matchend-cb(old);
for (; j<end; j++) if (cv(old)[j]!=0) break;
/* Mark the matched samples in both c_blocks as verified.
* In reality, not all the samples are marked. See
* stage1_matched() for details.
*/
if (j<end) {
stage1_matched(old,new,matchbegin,matchend,matchoffset,callback);
} else {
stage1_matched(old,new,matchbegin,matchend,matchoffset,NULL);
}
}
ret++;
/* Skip past this verified run to look for more matches. */
if (matchend-1 > j)
j = matchend-1;
}
}
} /* end for */
#ifdef NOISY
fprintf(stderr,"iterate_stage1: search area=%ld[%ld-%ld] tried=%ld matched=%ld spans=%ld\n",
searchsize,searchbegin,searchend,tried,matched,ret);
#endif
return(ret);
}
/* ===========================================================================
* i_stage1() (internal)
*
* Compare newly read samples against previously read samples, searching
* for contiguous runs of identical samples. Matching runs indicate that
* at least two reads of the CD returned identical data, with no dropped
* samples in that run. The runs may be jittered (i.e. their absolute
* positions on the CD may not be accurate due to inaccurate seeking) at
* this point. Their positions will be determined in stage 2.
*
* This function compares a new c_block against all other c_blocks in memory,
* searching for sufficiently long runs of identical samples. Since each
* c_block represents a separate call to read_c_block, this ensures that
* multiple reads have returned identical data. (Additionally, read_c_block
* varies the reads so that multiple reads are unlikely to produce identical
* errors, so any matches between reads are considered verified. See
* i_read_c_block for more details.)
*
* Each time we find such a run (longer than MIN_WORDS_SEARCH), we mark
* the samples as "verified" in both c_blocks. Runs of verified samples in
* the new c_block are promoted into verified fragments, which will later
* be merged into the verified root in stage 2.
*
* In reality, not all the verified samples are marked as "verified."
* See stage1_matched() for an explanation.
*
* This function returns the number of verified fragments created by the
* stage 1 matching.
*/
static long int
i_stage1(cdrom_paranoia_t *p, c_block_t *p_new,
void (*callback)(long int, paranoia_cb_mode_t))
{
long size=cs(p_new);
c_block_t *ptr=c_last(p);
int ret=0;
long int begin=0;
long int end;
/* We're going to be comparing the new c_block against the other
* c_blocks in memory. Initialize the "sort cache" index to allow
* for fast searching through the new c_block. (The index will
* actually be built the first time we search.)
*/
if (ptr)
sort_setup( p->sortcache, cv(p_new), &cb(p_new), cs(p_new), cb(p_new),
ce(p_new) );
/* Iterate from oldest to newest c_block, comparing the new c_block
* to each, looking for a sufficiently long run of identical samples
* (longer than MIN_WORDS_SEARCH), which will be marked as "verified"
* in both c_blocks.
*
* Since the new c_block is already in the list (at the head), don't
* compare it against itself.
*/
while ( ptr && ptr != p_new ) {
if (callback)
(*callback)(cb(p_new), PARANOIA_CB_VERIFY);
i_iterate_stage1(p,ptr,p_new,callback);
ptr=c_prev(ptr);
}
/* parse the verified areas of p_new into v_fragments */
/* Find each run of contiguous verified samples in the new c_block
* and create a verified fragment from each run.
*/
begin=0;
while (begin<size) {
for ( ; begin < size; begin++)
if (p_new->flags[begin]&FLAGS_VERIFIED) break;
for (end=begin; end < size; end++)
if ((p_new->flags[end]&FLAGS_VERIFIED)==0) break;
if (begin>=size) break;
ret++;
/* We create a new verified fragment from the contiguous run
* of verified samples.
*
* We expand the "verified" range by OVERLAP_ADJ on each side
* to compensate for trimming done to the verified range by
* stage1_matched(). The samples were actually verified, and
* hence belong in the verified fragment. See stage1_matched()
* for an explanation of the trimming.
*/
new_v_fragment(p,p_new,cb(p_new)+max(0,begin-OVERLAP_ADJ),
cb(p_new)+min(size,end+OVERLAP_ADJ),
(end+OVERLAP_ADJ>=size && p_new->lastsector));
begin=end;
}
/* Return the number of distinct verified fragments we found with
* stage 1 matching.
*/
return(ret);
}
/* ===========================================================================
* STAGE 2 MATCHING
*
* ???: Insert high-level explanation here.
* ===========================================================================
*/
typedef struct sync_result {
long offset;
long begin;
long end;
} sync_result_t;
/* Reconcile v_fragments to root buffer. Free if matched, fragment/fixup root
if necessary.
Do *not* match using zero posts
*/
static long int
i_iterate_stage2(cdrom_paranoia_t *p,
v_fragment_t *v,
sync_result_t *r,
void(*callback)(long int, paranoia_cb_mode_t))
{
root_block *root=&(p->root);
long matchbegin=-1,matchend=-1,offset;
long fbv,fev;
#ifdef NOISY
fprintf(stderr,"Stage 2 search: fbv=%ld fev=%ld\n",fb(v),fe(v));
#endif
if (min(fe(v) + p->dynoverlap,re(root)) -
max(fb(v) - p->dynoverlap,rb(root)) <= 0)
return(0);
if (callback)
(*callback)(fb(v), PARANOIA_CB_VERIFY);
/* just a bit of v; determine the correct area */
fbv = max(fb(v), rb(root)-p->dynoverlap);
/* we want to avoid zeroes */
while (fbv<fe(v) && fv(v)[fbv-fb(v)]==0)
fbv++;
if (fbv == fe(v))
return(0);
fev = min(min(fbv+256, re(root)+p->dynoverlap), fe(v));
{
/* spread the search area a bit. We post from root, so containment
must strictly adhere to root */
long searchend=min(fev+p->dynoverlap,re(root));
long searchbegin=max(fbv-p->dynoverlap,rb(root));
sort_info_t *i=p->sortcache;
long j;
sort_setup(i, fv(v), &fb(v), fs(v), fbv, fev);
for(j=searchbegin; j<searchend; j+=23){
while (j<searchend && rv(root)[j-rb(root)]==0)j++;
if (j==searchend) break;
if (try_sort_sync(p, i, NULL, rc(root), j,
&matchbegin,&matchend,&offset,callback)){
r->begin=matchbegin;
r->end=matchend;
r->offset=-offset;
if (offset)if (callback)(*callback)(r->begin,PARANOIA_CB_FIXUP_EDGE);
return(1);
}
}
}
return(0);
}
/* simple test for a root vector that ends in silence*/
static void
i_silence_test(root_block *root)
{
int16_t *vec=rv(root);
long end=re(root)-rb(root)-1;
long j;
for(j=end-1;j>=0;j--)
if (vec[j]!=0) break;
if (j<0 || end-j>MIN_SILENCE_BOUNDARY) {
if (j<0)j=0;
root->silenceflag=1;
root->silencebegin=rb(root)+j;
if (root->silencebegin<root->returnedlimit)
root->silencebegin=root->returnedlimit;
}
}
/* match into silence vectors at offset zero if at all possible. This
also must be called with vectors in ascending begin order in case
there are nonzero islands */
static long int
i_silence_match(root_block *root, v_fragment_t *v,
void(*callback)(long int, paranoia_cb_mode_t))
{
cdrom_paranoia_t *p=v->p;
int16_t *vec=fv(v);
long end=fs(v),begin;
long j;
/* does this vector begin wet? */
if (end<MIN_SILENCE_BOUNDARY) return(0);
for(j=0;j<end;j++)
if (vec[j]!=0) break;
if (j<MIN_SILENCE_BOUNDARY) return(0);
j+=fb(v);
/* is the new silent section ahead of the end of the old by <
p->dynoverlap? */
if (fb(v)>=re(root) && fb(v)-p->dynoverlap<re(root)){
/* extend the zeroed area of root */
long addto = fb(v) + MIN_SILENCE_BOUNDARY - re(root);
int16_t *vec = calloc(addto, sizeof(int16_t));
c_append(rc(root), vec, addto);
free(vec);
}
/* do we have an 'effortless' overlap? */
begin = max(fb(v),root->silencebegin);
end = min(j,re(root));
if (begin<end){
/* don't use it unless it will extend... */
if (fe(v)>re(root)){
long int voff = begin-fb(v);
c_remove(rc(root),begin-rb(root),-1);
c_append(rc(root),vec+voff,fs(v)-voff);
}
offset_add_value(p,&p->stage2,0,callback);
} else {
if (j<begin){
/* OK, we'll have to force it a bit as the root is jittered
forward */
long voff = j - fb(v);
/* don't use it unless it will extend... */
if (begin+fs(v)-voff>re(root)) {
c_remove(rc(root),root->silencebegin-rb(root),-1);
c_append(rc(root),vec+voff,fs(v)-voff);
}
offset_add_value(p,&p->stage2,end-begin,callback);
} else
return(0);
}
/* test the new root vector for ending in silence */
root->silenceflag = 0;
i_silence_test(root);
if (v->lastsector) root->lastsector=1;
free_v_fragment(v);
return(1);
}
static long int
i_stage2_each(root_block *root, v_fragment_t *v,
void(*callback)(long int, paranoia_cb_mode_t))
{
cdrom_paranoia_t *p=v->p;
long dynoverlap=p->dynoverlap/2*2;
if (!v || !v->one) return(0);
if (!rv(root)){
return(0);
} else {
sync_result_t r;
if (i_iterate_stage2(p,v,&r,callback)){
long int begin=r.begin-rb(root);
long int end=r.end-rb(root);
long int offset=r.begin+r.offset-fb(v)-begin;
long int temp;
c_block_t *l=NULL;
/* we have a match! We don't rematch off rift, we chase the
match all the way to both extremes doing rift analysis. */
#ifdef NOISY
fprintf(stderr,"Stage 2 match\n");
#endif
/* chase backward */
/* note that we don't extend back right now, only forward. */
while ((begin+offset>0 && begin>0)){
long matchA=0,matchB=0,matchC=0;
long beginL=begin+offset;
if (l==NULL){
int16_t *buff=malloc(fs(v)*sizeof(int16_t));
l=c_alloc(buff,fb(v),fs(v));
memcpy(buff,fv(v),fs(v)*sizeof(int16_t));
}
i_analyze_rift_r(rv(root),cv(l),
rs(root),cs(l),
begin-1,beginL-1,
&matchA,&matchB,&matchC);
#ifdef NOISY
fprintf(stderr,"matching rootR: matchA:%ld matchB:%ld matchC:%ld\n",
matchA,matchB,matchC);
#endif
if (matchA){
/* a problem with root */
if (matchA>0){
/* dropped bytes; add back from v */
if (callback)
(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED);
if (rb(root)+begin<p->root.returnedlimit)
break;
else{
c_insert(rc(root),begin,cv(l)+beginL-matchA,
matchA);
offset-=matchA;
begin+=matchA;
end+=matchA;
}
} else {
/* duplicate bytes; drop from root */
if (callback)
(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED);
if (rb(root)+begin+matchA<p->root.returnedlimit)
break;
else{
c_remove(rc(root),begin+matchA,-matchA);
offset-=matchA;
begin+=matchA;
end+=matchA;
}
}
} else if (matchB){
/* a problem with the fragment */
if (matchB>0){
/* dropped bytes */
if (callback)
(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DROPPED);
c_insert(l,beginL,rv(root)+begin-matchB,
matchB);
offset+=matchB;
} else {
/* duplicate bytes */
if (callback)
(*callback)(begin+rb(root)-1,PARANOIA_CB_FIXUP_DUPED);
c_remove(l,beginL+matchB,-matchB);
offset+=matchB;
}
} else if (matchC){
/* Uhh... problem with both */
/* Set 'disagree' flags in root */
if (rb(root)+begin-matchC<p->root.returnedlimit)
break;
c_overwrite(rc(root),begin-matchC,
cv(l)+beginL-matchC,matchC);
} else {
/* do we have a mismatch due to silence beginning/end case? */
/* in the 'chase back' case, we don't do anything. */
/* Did not determine nature of difficulty...
report and bail */
/*RRR(*callback)(post,PARANOIA_CB_XXX);*/
break;
}
/* not the most efficient way, but it will do for now */
beginL=begin+offset;
i_paranoia_overlap(rv(root),cv(l),
begin,beginL,
rs(root),cs(l),
&begin,&end);
}
/* chase forward */
temp=l ? cs(l) : fs(v);
while (end+offset<temp && end<rs(root)){
long matchA=0,matchB=0,matchC=0;
long beginL=begin+offset;
long endL=end+offset;
if (l==NULL){
int16_t *buff=malloc(fs(v)*sizeof(int16_t));
l=c_alloc(buff,fb(v),fs(v));
memcpy(buff,fv(v),fs(v)*sizeof(int16_t));
}
i_analyze_rift_f(rv(root),cv(l),
rs(root),cs(l),
end,endL,
&matchA,&matchB,&matchC);
#ifdef NOISY
fprintf(stderr,"matching rootF: matchA:%ld matchB:%ld matchC:%ld\n",
matchA,matchB,matchC);
#endif
if (matchA){
/* a problem with root */
if (matchA>0){
/* dropped bytes; add back from v */
if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED);
if (end+rb(root)<p->root.returnedlimit)
break;
c_insert(rc(root),end,cv(l)+endL,matchA);
} else {
/* duplicate bytes; drop from root */
if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED);
if (end+rb(root)<p->root.returnedlimit)
break;
c_remove(rc(root),end,-matchA);
}
} else if (matchB){
/* a problem with the fragment */
if (matchB>0){
/* dropped bytes */
if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DROPPED);
c_insert(l,endL,rv(root)+end,matchB);
} else {
/* duplicate bytes */
if (callback)(*callback)(end+rb(root),PARANOIA_CB_FIXUP_DUPED);
c_remove(l,endL,-matchB);
}
} else if (matchC){
/* Uhh... problem with both */
/* Set 'disagree' flags in root */
if (end+rb(root)<p->root.returnedlimit)
break;
c_overwrite(rc(root),end,cv(l)+endL,matchC);
} else {
analyze_rift_silence_f(rv(root),cv(l),
rs(root),cs(l),
end,endL,
&matchA,&matchB);
if (matchA){
/* silence in root */
/* Can only do this if we haven't already returned data */
if (end+rb(root)>=p->root.returnedlimit){
c_remove(rc(root),end,-1);
}
} else if (matchB){
/* silence in fragment; lose it */
if (l)i_cblock_destructor(l);
free_v_fragment(v);
return(1);
} else {
/* Could not determine nature of difficulty...
report and bail */
/*RRR(*callback)(post,PARANOIA_CB_XXX);*/
}
break;
}
/* not the most efficient way, but it will do for now */
i_paranoia_overlap(rv(root),cv(l),
begin,beginL,
rs(root),cs(l),
NULL,&end);
}
/* if this extends our range, let's glom */
{
long sizeA=rs(root);
long sizeB;
long vecbegin;
int16_t *vector;
if (l){
sizeB=cs(l);
vector=cv(l);
vecbegin=cb(l);
} else {
sizeB=fs(v);
vector=fv(v);
vecbegin=fb(v);
}
if (sizeB-offset>sizeA || v->lastsector){
if (v->lastsector){
root->lastsector=1;
}
if (end<sizeA)c_remove(rc(root),end,-1);
if (sizeB-offset-end)c_append(rc(root),vector+end+offset,
sizeB-offset-end);
i_silence_test(root);
/* add offset into dynoverlap stats */
offset_add_value(p,&p->stage2,offset+vecbegin-rb(root),callback);
}
}
if (l)i_cblock_destructor(l);
free_v_fragment(v);
return(1);
} else {
/* D'oh. No match. What to do with the fragment? */
if (fe(v)+dynoverlap<re(root) && !root->silenceflag){
/* It *should* have matched. No good; free it. */
free_v_fragment(v);
}
/* otherwise, we likely want this for an upcoming match */
/* we don't free the sort info (if it was collected) */
return(0);
}
}
}
static int
i_init_root(root_block *root, v_fragment_t *v,long int begin,
void(*callback)(long int, paranoia_cb_mode_t))
{
if (fb(v)<=begin && fe(v)>begin){
root->lastsector=v->lastsector;
root->returnedlimit=begin;
if (rv(root)){
i_cblock_destructor(rc(root));
rc(root)=NULL;
}
{
int16_t *buff=malloc(fs(v)*sizeof(int16_t));
memcpy(buff,fv(v),fs(v)*sizeof(int16_t));
root->vector=c_alloc(buff,fb(v),fs(v));
}
i_silence_test(root);
return(1);
} else
return(0);
}
static int
vsort(const void *a,const void *b)
{
return((*(v_fragment_t **)a)->begin-(*(v_fragment_t **)b)->begin);
}
static int
i_stage2(cdrom_paranoia_t *p, long int beginword, long int endword,
void (*callback)(long int, paranoia_cb_mode_t))
{
int flag=1,ret=0;
root_block *root=&(p->root);
#ifdef NOISY
fprintf(stderr,"Fragments:%ld\n",p->fragments->active);
fflush(stderr);
#endif
/* even when the 'silence flag' is lit, we try to do non-silence
matching in the event that there are still audio vectors with
content to be sunk before the silence */
while (flag) {
/* loop through all the current fragments */
v_fragment_t *first=v_first(p);
long active=p->fragments->active,count=0;
v_fragment_t **list = calloc(active, sizeof(v_fragment_t *));
while (first){
v_fragment_t *next=v_next(first);
list[count++]=first;
first=next;
}
flag=0;
if (count){
/* sorted in ascending order of beginning */
qsort(list,active,sizeof(v_fragment_t *),&vsort);
/* we try a nonzero based match even if in silent mode in
the case that there are still cached vectors to sink
behind continent->ocean boundary */
for(count=0;count<active;count++){
first=list[count];
if (first->one){
if (rv(root)==NULL){
if (i_init_root(&(p->root),first,beginword,callback)){
free_v_fragment(first);
flag=1;
ret++;
}
} else {
if (i_stage2_each(root,first,callback)){
ret++;
flag=1;
}
}
}
}
/* silence handling */
if (!flag && p->root.silenceflag){
for(count=0;count<active;count++){
first=list[count];
if (first->one){
if (rv(root)!=NULL){
if (i_silence_match(root,first,callback)){
ret++;
flag=1;
}
}
}
}
}
}
free(list);
}
return(ret);
}
static void
i_end_case(cdrom_paranoia_t *p,long endword,
void(*callback)(long int, paranoia_cb_mode_t))
{
root_block *root=&p->root;
/* have an 'end' flag; if we've just read in the last sector in a
session, set the flag. If we verify to the end of a fragment
which has the end flag set, we're done (set a done flag). Pad
zeroes to the end of the read */
if (root->lastsector==0)return;
if (endword<re(root))return;
{
long addto=endword-re(root);
char *temp=calloc(addto,sizeof(char)*2);
c_append(rc(root),(void *)temp,addto);
free(temp);
/* trash da cache */
paranoia_resetcache(p);
}
}
/* We want to add a sector. Look through the caches for something that
spans. Also look at the flags on the c_block... if this is an
obliterated sector, get a bit of a chunk past the obliteration. */
/* Not terribly smart right now, actually. We can probably find
*some* match with a cache block somewhere. Take it and continue it
through the skip */
static void
verify_skip_case(cdrom_paranoia_t *p,
void(*callback)(long int, paranoia_cb_mode_t))
{
root_block *root=&(p->root);
c_block_t *graft=NULL;
int vflag=0;
int gend=0;
long post;
#ifdef NOISY
fprintf(stderr,"\nskipping\n");
#endif
if (rv(root)==NULL){
post=0;
} else {
post=re(root);
}
if (post==-1)post=0;
if (callback)(*callback)(post,PARANOIA_CB_SKIP);
/* We want to add a sector. Look for a c_block that spans,
preferrably a verified area */
{
c_block_t *c=c_first(p);
while (c){
long cbegin=cb(c);
long cend=ce(c);
if (cbegin<=post && cend>post){
long vend=post;
if (c->flags[post-cbegin]&FLAGS_VERIFIED){
/* verified area! */
while (vend<cend && (c->flags[vend-cbegin]&FLAGS_VERIFIED))vend++;
if (!vflag || vend>vflag){
graft=c;
gend=vend;
}
vflag=1;
} else {
/* not a verified area */
if (!vflag){
while (vend<cend && (c->flags[vend-cbegin]&FLAGS_VERIFIED)==0)vend++;
if (graft==NULL || gend>vend){
/* smallest unverified area */
graft=c;
gend=vend;
}
}
}
}
c=c_next(c);
}
if (graft){
long cbegin=cb(graft);
long cend=ce(graft);
while (gend<cend && (graft->flags[gend-cbegin]&FLAGS_VERIFIED))gend++;
gend=min(gend+OVERLAP_ADJ,cend);
if (rv(root)==NULL){
int16_t *buff=malloc(cs(graft));
memcpy(buff,cv(graft),cs(graft));
rc(root)=c_alloc(buff,cb(graft),cs(graft));
} else {
c_append(rc(root),cv(graft)+post-cbegin,
gend-post);
}
root->returnedlimit=re(root);
return;
}
}
/* No? Fine. Great. Write in some zeroes :-P */
{
void *temp=calloc(CDIO_CD_FRAMESIZE_RAW,sizeof(int16_t));
if (rv(root)==NULL){
rc(root)=c_alloc(temp,post,CDIO_CD_FRAMESIZE_RAW);
} else {
c_append(rc(root),temp,CDIO_CD_FRAMESIZE_RAW);
free(temp);
}
root->returnedlimit=re(root);
}
}
/**** toplevel ****************************************/
void
paranoia_free(cdrom_paranoia_t *p)
{
paranoia_resetall(p);
sort_free(p->sortcache);
free_list(p->cache, 1);
free_list(p->fragments, 1);
free(p);
}
void
paranoia_modeset(cdrom_paranoia_t *p, int enable)
{
p->enable=enable;
}
lsn_t
paranoia_seek(cdrom_paranoia_t *p, off_t seek, int mode)
{
long sector;
long ret;
switch(mode){
case SEEK_SET:
sector=seek;
break;
case SEEK_END:
sector=cdda_disc_lastsector(p->d)+seek;
break;
default:
sector=p->cursor+seek;
break;
}
if (cdda_sector_gettrack(p->d,sector)==-1)return(-1);
i_cblock_destructor(p->root.vector);
p->root.vector=NULL;
p->root.lastsector=0;
p->root.returnedlimit=0;
ret=p->cursor;
p->cursor=sector;
i_paranoia_firstlast(p);
/* Evil hack to fix pregap patch for NEC drives! To be rooted out in a10 */
p->current_firstsector=sector;
return(ret);
}
/* ===========================================================================
* read_c_block() (internal)
*
* This funtion reads many (p->readahead) sectors, encompassing at least
* the requested words.
*
* It returns a c_block which encapsulates these sectors' data and sector
* number. The sectors come come from multiple low-level read requests.
*
* This function reads many sectors in order to exhaust any caching on the
* drive itself, as caching would simply return the same incorrect data
* over and over. Paranoia depends on truly re-reading portions of the
* disc to make sure the reads are accurate and correct any inaccuracies.
*
* Which precise sectors are read varies ("jiggles") between calls to
* read_c_block, to prevent consistent errors across multiple reads
* from being misinterpreted as correct data.
*
* The size of each low-level read is determined by the underlying driver
* (p->d->nsectors), which allows the driver to specify how many sectors
* can be read in a single request. Historically, the Linux kernel could
* only read 8 sectors at a time, with likely dropped samples between each
* read request. Other operating systems may have different limitations.
*
* This function is called by paranoia_read_limited(), which breaks the
* c_block of read data into runs of samples that are likely to be
* contiguous, verifies them and stores them in verified fragments, and
* eventually merges the fragments into the verified root.
*
* This function returns the last c_block read or NULL on error.
*/
static c_block_t *
i_read_c_block(cdrom_paranoia_t *p,long beginword,long endword,
void(*callback)(long, paranoia_cb_mode_t))
{
/* why do it this way? We need to read lots of sectors to kludge
around stupid read ahead buffers on cheap drives, as well as avoid
expensive back-seeking. We also want to 'jiggle' the start address
to try to break borderline drives more noticeably (and make broken
drives with unaddressable sectors behave more often). */
long readat,firstread;
long totaltoread=p->readahead;
long sectatonce=p->d->nsectors;
long driftcomp=(float)p->dyndrift/CD_FRAMEWORDS+.5;
c_block_t *new=NULL;
root_block *root=&p->root;
int16_t *buffer=NULL;
unsigned char *flags=NULL;
long sofar;
long dynoverlap=(p->dynoverlap+CD_FRAMEWORDS-1)/CD_FRAMEWORDS;
long anyflag=0;
/* Calculate the first sector to read. This calculation takes
* into account the need to jitter the starting point of the read
* to reveal consistent errors as well as the low reliability of
* the edge words of a read.
*
* ???: Document more clearly how dynoverlap and MIN_SECTOR_BACKUP
* are calculated and used.
*/
/* What is the first sector to read? want some pre-buffer if
we're not at the extreme beginning of the disc */
if (p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){
/* we want to jitter the read alignment boundary */
long target;
if (rv(root)==NULL || rb(root)>beginword)
target=p->cursor-dynoverlap;
else
target=re(root)/(CD_FRAMEWORDS)-dynoverlap;
if (target+MIN_SECTOR_BACKUP>p->lastread && target<=p->lastread)
target=p->lastread-MIN_SECTOR_BACKUP;
/* we want to jitter the read alignment boundary, as some
drives, beginning from a specific point, will tend to
lose bytes between sectors in the same place. Also, as
our vectors are being made up of multiple reads, we want
the overlap boundaries to move.... */
readat=(target&(~((long)JIGGLE_MODULO-1)))+p->jitter;
if (readat>target)readat-=JIGGLE_MODULO;
p->jitter++;
if (p->jitter>=JIGGLE_MODULO)
p->jitter=0;
} else {
readat=p->cursor;
}
readat+=driftcomp;
/* Create a new, empty c_block and add it to the head of the
* list of c_blocks in memory. It will be empty until the end of
* this subroutine.
*/
if (p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)) {
flags=calloc(totaltoread*CD_FRAMEWORDS, 1);
new=new_c_block(p);
recover_cache(p);
} else {
/* in the case of root it's just the buffer */
paranoia_resetall(p);
new=new_c_block(p);
}
buffer=calloc(totaltoread*CDIO_CD_FRAMESIZE_RAW, 1);
sofar=0;
firstread=-1;
/* Issue each of the low-level reads until we've read enough sectors
* to exhaust the drive's cache.
*
* p->readahead = total number of sectors to read
* p->d->nsectors = number of sectors to read per request
*
* The driver determines this latter number, which is the maximum
* number of sectors the kernel can reliably read per request. In
* old Linux kernels, there was a hard limit of 8 sectors per read.
* While this limit has since been removed, certain motherboards
* can't handle DMA requests larger than 64K. And other operating
* systems may have similar limitations. So the method of splitting
* up reads is still useful.
*/
/* actual read loop */
while (sofar<totaltoread){
long secread=sectatonce; /* number of sectors to read this request */
long adjread=readat; /* first sector to read for this request */
long thisread; /* how many sectors were read this request */
/* don't under/overflow the audio session */
if (adjread<p->current_firstsector){
secread-=p->current_firstsector-adjread;
adjread=p->current_firstsector;
}
if (adjread+secread-1>p->current_lastsector)
secread=p->current_lastsector-adjread+1;
if (sofar+secread>totaltoread)secread=totaltoread-sofar;
if (secread>0){
if (firstread<0) firstread = adjread;
/* Issue the low-level read to the driver.
*/
thisread = cdda_read(p->d, buffer+sofar*CD_FRAMEWORDS, adjread, secread);
/* If the low-level read returned too few sectors, pad the result
* with null data and mark it as invalid (FLAGS_UNREAD). We pad
* because we're going to be appending further reads to the current
* c_block.
*
* ???: Why not re-read? It might be to keep you from getting
* hung up on a bad sector. Or it might be to avoid interrupting
* the streaming as much as possible.
*/
if ( thisread < secread) {
if (thisread<0) thisread=0;
/* Uhhh... right. Make something up. But don't make us seek
backward! */
if (callback)
(*callback)((adjread+thisread)*CD_FRAMEWORDS, PARANOIA_CB_READERR);
memset(buffer+(sofar+thisread)*CD_FRAMEWORDS,0,
CDIO_CD_FRAMESIZE_RAW*(secread-thisread));
if (flags)
memset(flags+(sofar+thisread)*CD_FRAMEWORDS, FLAGS_UNREAD,
CD_FRAMEWORDS*(secread-thisread));
}
if (thisread!=0)anyflag=1;
/* Because samples are likely to be dropped between read requests,
* mark the samples near the the boundaries of the read requests
* as suspicious (FLAGS_EDGE). This means that any span of samples
* against which these adjacent read requests are compared must
* overlap beyond the edges and into the more trustworthy data.
* Such overlapping spans are accordingly at least MIN_WORDS_OVERLAP
* words long (and naturally longer if any samples were dropped
* between the read requests).
*
* (EEEEE...overlapping span...EEEEE)
* (read 1 ...........EEEEE) (EEEEE...... read 2 ......EEEEE) ...
* dropped samples --^
*/
if (flags && sofar!=0){
/* Don't verify across overlaps that are too close to one
another */
int i=0;
for(i=-MIN_WORDS_OVERLAP/2;i<MIN_WORDS_OVERLAP/2;i++)
flags[sofar*CD_FRAMEWORDS+i]|=FLAGS_EDGE;
}
/* Move the read cursor ahead by the number of sectors we attempted
* to read.
*
* ???: Again, why not move it ahead by the number actually read?
*/
p->lastread=adjread+secread;
if (adjread+secread-1==p->current_lastsector)
new->lastsector=-1;
if (callback)(*callback)((adjread+secread-1)*CD_FRAMEWORDS,PARANOIA_CB_READ);
sofar+=secread;
readat=adjread+secread;
} else /* secread <= 0 */
if (readat<p->current_firstsector)
readat+=sectatonce; /* due to being before the readable area */
else
break; /* due to being past the readable area */
/* Keep issuing read requests until we've read enough sectors to
* exhaust the drive's cache.
*/
} /* end while */
/* If we managed to read any sectors at all (anyflag), fill in the
* previously allocated c_block with the read data. Otherwise, free
* our buffers, dispose of the c_block, and return NULL.
*/
if (anyflag) {
new->vector=buffer;
new->begin=firstread*CD_FRAMEWORDS-p->dyndrift;
new->size=sofar*CD_FRAMEWORDS;
new->flags=flags;
} else {
if (new)free_c_block(new);
free(buffer);
free(flags);
new=NULL;
}
return(new);
}
/** ==========================================================================
* cdio_paranoia_read(), cdio_paranoia_read_limited()
*
* These functions "read" the next sector of audio data and returns
* a pointer to a full sector of verified samples (2352 bytes).
*
* The returned buffer is *not* to be freed by the caller. It will
* persist only until the next call to paranoia_read() for this p
*/
int16_t *
cdio_paranoia_read(cdrom_paranoia_t *p,
void(*callback)(long, paranoia_cb_mode_t))
{
return paranoia_read_limited(p, callback, 20);
}
/* I added max_retry functionality this way in order to avoid
breaking any old apps using the nerw libs. cdparanoia 9.8 will
need the updated libs, but nothing else will require it. */
int16_t *
cdio_paranoia_read_limited(cdrom_paranoia_t *p,
void(*callback)(long int, paranoia_cb_mode_t),
int max_retries)
{
long int beginword = p->cursor*(CD_FRAMEWORDS);
long int endword = beginword+CD_FRAMEWORDS;
long int retry_count= 0;
long int lastend = -2;
root_block *root = &p->root;
if (beginword > p->root.returnedlimit)
p->root.returnedlimit=beginword;
lastend=re(root);
/* Since paranoia reads and verifies chunks of data at a time
* (which it needs to counteract dropped samples and inaccurate
* seeking), the requested samples may already be in memory,
* in the verified "root".
*
* The root is where paranoia stores samples that have been
* verified and whose position has been accurately determined.
*/
/* First, is the sector we want already in the root? */
while (rv(root)==NULL ||
rb(root)>beginword ||
(re(root)<endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS) &&
p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)) ||
re(root)<endword){
/* Nope; we need to build or extend the root verified range */
/* We may have already read the necessary samples and placed
* them into verified fragments, but not yet merged them into
* the verified root. We'll check that before we actually
* try to read data from the drive.
*/
if (p->enable&(PARANOIA_MODE_VERIFY|PARANOIA_MODE_OVERLAP)){
/* We need to make sure our memory consumption doesn't grow
* to the size of the whole CD. But at the same time, we
* need to hang onto some of the verified data (even perhaps
* data that's already been returned by paranoia_read()) in
* order to verify and accurately position future samples.
*
* Therefore, we free some of the verified data that we
* no longer need.
*/
i_paranoia_trim(p,beginword,endword);
recover_cache(p);
if (rb(root)!=-1 && p->root.lastsector)
i_end_case(p, endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
callback);
else
/* Merge as many verified fragments into the verified root
* as we need to satisfy the pending request. We may
* not have all the fragments we need, in which case we'll
* read data from the CD further below.
*/
i_stage2(p, beginword,
endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
callback);
} else
i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
callback); /* only trips if we're already done */
/* If we were able to fill the verified root with data already
* in memory, we don't need to read any more data from the drive.
*/
if (!(rb(root)==-1 || rb(root)>beginword ||
re(root)<endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)))
break;
/* Hmm, need more. Read another block */
{
/* Read many sectors, encompassing at least the requested words.
*
* The returned c_block encapsulates these sectors' data and
* sector number. The sectors come come from multiple low-level
* read requests, and words which were near the boundaries of
* those read requests are marked with FLAGS_EDGE.
*/
c_block_t *new=i_read_c_block(p,beginword,endword,callback);
if (new){
if (p->enable&(PARANOIA_MODE_OVERLAP|PARANOIA_MODE_VERIFY)){
/* If we need to verify these samples, send them to
* stage 1 verification, which will add verified samples
* to the set of verified fragments. Verified fragments
* will be merged into the verified root during stage 2
* overlap analysis.
*/
if (p->enable&PARANOIA_MODE_VERIFY)
i_stage1(p,new,callback);
/* If we're only doing overlapping reads (no stage 1
* verification), consider each low-level read in the
* c_block to be a verified fragment. We exclude the
* edges from these fragments to enforce the requirement
* that we overlap the reads by the minimum amount.
* These fragments will be merged into the verified
* root during stage 2 overlap analysis.
*/
else{
/* just make v_fragments from the boundary information. */
long begin=0,end=0;
while (begin<cs(new)){
while (end<cs(new) && (new->flags[begin]&FLAGS_EDGE))begin++;
end=begin+1;
while (end<cs(new) && (new->flags[end]&FLAGS_EDGE)==0)end++;
{
new_v_fragment(p,new,begin+cb(new),
end+cb(new),
(new->lastsector && cb(new)+end==ce(new)));
}
begin=end;
}
}
} else {
/* If we're not doing any overlapping reads or verification
* of data, skip over the stage 1 and stage 2 verification and
* promote this c_block directly to the current "verified" root.
*/
if (p->root.vector)i_cblock_destructor(p->root.vector);
free_elem(new->e,0);
p->root.vector=new;
i_end_case(p,endword+(MAX_SECTOR_OVERLAP*CD_FRAMEWORDS),
callback);
}
}
}
/* Are we doing lots of retries? **************************************/
/* ???: To be studied
*/
/* Check unaddressable sectors first. There's no backoff here;
jiggle and minimum backseek handle that for us */
if (rb(root)!=-1 && lastend+588<re(root)){ /* If we've not grown
half a sector */
lastend=re(root);
retry_count=0;
} else {
/* increase overlap or bail */
retry_count++;
/* The better way to do this is to look at how many actual
matches we're getting and what kind of gap */
if (retry_count%5==0){
if (p->dynoverlap==MAX_SECTOR_OVERLAP*CD_FRAMEWORDS ||
retry_count==max_retries){
if (!(p->enable&PARANOIA_MODE_NEVERSKIP))
verify_skip_case(p,callback);
retry_count=0;
} else {
if (p->stage1.offpoints!=-1){ /* hack */
p->dynoverlap*=1.5;
if (p->dynoverlap>MAX_SECTOR_OVERLAP*CD_FRAMEWORDS)
p->dynoverlap=MAX_SECTOR_OVERLAP*CD_FRAMEWORDS;
if (callback)
(*callback)(p->dynoverlap,PARANOIA_CB_OVERLAP);
}
}
}
}
/* Having read data from the drive and placed it into verified
* fragments, we now loop back to try to extend the root with
* the newly loaded data. Alternatively, if the root already
* contains the needed data, we'll just fall through.
*/
} /* end while */
p->cursor++;
/* Return a pointer into the verified root. Thus, the caller
* must NOT free the returned pointer!
*/
return(rv(root)+(beginword-rb(root)));
}
/* a temporary hack */
void
cdio_paranoia_overlapset(cdrom_paranoia_t *p, long int overlap)
{
p->dynoverlap=overlap*CD_FRAMEWORDS;
p->stage1.offpoints=-1;
}