#include "config.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
#include "librsync.h"
#include "job.h"
#include "stream.h"
#include "trace.h"
#include "util.h"
void rs_scoop_input(rs_job_t *job, size_t len)
{
rs_buffers_t *stream = job->stream;
size_t tocopy;
assert(len > job->scoop_avail);
if (job->scoop_alloc < len) {
rs_byte_t *newbuf;
size_t newsize;
for (newsize = 64; newsize < len; newsize <<= 1) ;
newbuf = rs_alloc(newsize, "scoop buffer");
if (job->scoop_avail)
memcpy(newbuf, job->scoop_next, job->scoop_avail);
if (job->scoop_buf)
free(job->scoop_buf);
job->scoop_buf = job->scoop_next = newbuf;
rs_trace("resized scoop buffer to " FMT_SIZE " bytes from " FMT_SIZE "",
newsize, job->scoop_alloc);
job->scoop_alloc = newsize;
} else if (job->scoop_buf != job->scoop_next) {
rs_trace("moving scoop " FMT_SIZE " bytes to reuse " FMT_SIZE " bytes",
job->scoop_avail, (size_t)(job->scoop_next - job->scoop_buf));
memmove(job->scoop_buf, job->scoop_next, job->scoop_avail);
job->scoop_next = job->scoop_buf;
}
tocopy = len - job->scoop_avail;
if (tocopy > stream->avail_in)
tocopy = stream->avail_in;
assert(tocopy + job->scoop_avail <= job->scoop_alloc);
memcpy(job->scoop_next + job->scoop_avail, stream->next_in, tocopy);
rs_trace("accepted " FMT_SIZE " bytes from input to scoop", tocopy);
job->scoop_avail += tocopy;
stream->next_in += tocopy;
stream->avail_in -= tocopy;
}
void rs_scoop_advance(rs_job_t *job, size_t len)
{
rs_buffers_t *stream = job->stream;
if (job->scoop_avail) {
rs_trace("advance over " FMT_SIZE " bytes from scoop", len);
assert(len <= job->scoop_avail);
job->scoop_avail -= len;
job->scoop_next += len;
} else {
rs_trace("advance over " FMT_SIZE " bytes from input buffer", len);
assert(len <= stream->avail_in);
stream->avail_in -= len;
stream->next_in += len;
}
}
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) {
*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) {
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) {
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) {
rs_trace("reached end of input stream");
return RS_INPUT_ENDED;
} else {
rs_trace("blocked with insufficient input data");
return RS_BLOCKED;
}
}
rs_result rs_scoop_read(rs_job_t *job, size_t len, void **ptr)
{
rs_result result;
result = rs_scoop_readahead(job, len, ptr);
if (result == RS_DONE)
rs_scoop_advance(job, len);
return result;
}
rs_result rs_scoop_read_rest(rs_job_t *job, size_t *len, void **ptr)
{
rs_buffers_t *stream = job->stream;
*len = job->scoop_avail + stream->avail_in;
if (*len)
return rs_scoop_read(job, *len, ptr);
else if (stream->eof_in)
return RS_INPUT_ENDED;
else
return RS_BLOCKED;
}
size_t rs_scoop_total_avail(rs_job_t *job)
{
return job->scoop_avail + job->stream->avail_in;
}