static rs_result rs_delta_s_flush(rs_job_t *job) { rs_long_t match_pos; size_t match_len; rs_result result; rs_job_check(job); /* read the input into the scoop */ rs_getinput(job); /* output any pending output */ result=rs_tube_catchup(job); /* while output is not blocked and there is any remaining data */ while ((result==RS_DONE) && (job->scoop_pos < job->scoop_avail)) { /* check if this block matches */ if (rs_findmatch(job,&match_pos,&match_len)) { /* append the match and reset the weak_sum */ result=rs_appendmatch(job,match_pos,match_len); RollsumInit(&job->weak_sum); } else { /* rollout from weak_sum and append the miss byte */ RollsumRollout(&job->weak_sum,job->scoop_next[job->scoop_pos]); rs_trace("block reduced to %d", (int)job->weak_sum.count); result=rs_appendmiss(job,1); } } /* if we are not blocked, flush and set end statefn. */ if (result==RS_DONE) { result=rs_appendflush(job); job->statefn=rs_delta_s_end; } if (result==RS_DONE) { return RS_RUNNING; } return result; }
/** Read from scoop without advancing. * * Ask for LEN bytes of input from the stream. If that much data is available, * then return a pointer to it in PTR, advance the stream input pointer over * the data, and return RS_DONE. If there's not enough data, then accept * whatever is there into a buffer, advance over it, and return RS_BLOCKED. * * The data is not actually removed from the input, so this function lets you * do readahead. If you want to keep any of the data, you should also call * rs_scoop_advance() to skip over it. */ rs_result rs_scoop_readahead(rs_job_t *job, size_t len, void **ptr) { rs_buffers_t *stream = job->stream; rs_job_check(job); if (!job->scoop_avail && stream->avail_in >= len) { /* The scoop is empty and there's enough data in the input. */ *ptr = stream->next_in; rs_trace("got " FMT_SIZE " bytes direct from input", len); return RS_DONE; } else if (job->scoop_avail < len && stream->avail_in) { /* There is not enough data in the scoop. */ rs_trace("scoop has less than " FMT_SIZE " bytes, scooping from " FMT_SIZE " input bytes", len, stream->avail_in); rs_scoop_input(job, len); } if (job->scoop_avail >= len) { /* There is enough data in the scoop now. */ rs_trace("scoop has at least " FMT_SIZE " bytes, this is enough", job->scoop_avail); *ptr = job->scoop_next; return RS_DONE; } else if (stream->eof_in) { /* Not enough input data and at EOF. */ rs_trace("reached end of input stream"); return RS_INPUT_ENDED; } else { /* Not enough input data yet. */ rs_trace("blocked with insufficient input data"); return RS_BLOCKED; } }
/** * \brief Get a block of data if possible, and see if it matches. * * On each call, we try to process all of the input data available on the * scoop and input buffer. */ static rs_result rs_delta_s_scan(rs_job_t *job) { rs_long_t match_pos; size_t match_len; rs_result result; Rollsum test; rs_job_check(job); /* read the input into the scoop */ rs_getinput(job); /* output any pending output from the tube */ result=rs_tube_catchup(job); /* while output is not blocked and there is a block of data */ while ((result==RS_DONE) && ((job->scoop_pos + job->block_len) < job->scoop_avail)) { /* check if this block matches */ if (rs_findmatch(job,&match_pos,&match_len)) { /* append the match and reset the weak_sum */ result=rs_appendmatch(job,match_pos,match_len); RollsumInit(&job->weak_sum); } else { /* rotate the weak_sum and append the miss byte */ RollsumRotate(&job->weak_sum,job->scoop_next[job->scoop_pos], job->scoop_next[job->scoop_pos+job->block_len]); result=rs_appendmiss(job,1); if (rs_roll_paranoia) { RollsumInit(&test); RollsumUpdate(&test,job->scoop_next+job->scoop_pos, job->block_len); if (RollsumDigest(&test) != RollsumDigest(&job->weak_sum)) { rs_fatal("mismatch between rolled sum %#x and check %#x", (int)RollsumDigest(&job->weak_sum), (int)RollsumDigest(&test)); } } } } /* if we completed OK */ if (result==RS_DONE) { /* if we reached eof, we can flush the last fragment */ if (job->stream->eof_in) { job->statefn=rs_delta_s_flush; return RS_RUNNING; } else { /* we are blocked waiting for more data */ return RS_BLOCKED; } } return result; }
static rs_result rs_job_complete(rs_job_t *job, rs_result result) { rs_job_check(job); job->statefn = rs_job_s_complete; job->final_result = result; if (result != RS_DONE) { rs_error("%s job failed: %s", job->job_name, rs_strerror(result)); } else { rs_trace("%s job complete", job->job_name); } if (result == RS_DONE && !rs_tube_is_idle(job)) /* Processing is finished, but there is still some data * waiting to get into the output buffer. */ return RS_BLOCKED; else return result; }
static rs_result rs_job_work(rs_job_t *job, rs_buffers_t *buffers) { rs_result result; rs_job_check(job); if (!buffers) { rs_error("NULL buffer passed to rs_job_iter"); return RS_PARAM_ERROR; } job->stream = buffers; while (1) { result = rs_tube_catchup(job); if (result == RS_BLOCKED) return result; else if (result != RS_DONE) return rs_job_complete(job, result); if (job->statefn == rs_job_s_complete) { if (rs_tube_is_idle(job)) return RS_DONE; else return RS_BLOCKED; } else { result = job->statefn(job); if (result == RS_RUNNING) continue; else if (result == RS_BLOCKED) return result; else return rs_job_complete(job, result); } } /* TODO: Before returning, check that we actually made some * progress. If not, and we're not returning an error, this is a * bug. */ }