/* See LICENSE file for copyright and license details. */
#include "common.h"
size_t
inithashers(struct algorithm *algorithms, size_t nalgorithms)
{
size_t i;
for (i = 0; i < nalgorithms;) {
if (libhashsum_init_hasher_from_string(&algorithms[i].hasher, algorithms[i].algostr)) {
weprintf("%s:", algorithms[i].algostr);
free(algorithms[i].result);
/* keep order */
memmove(&algorithms[i], &algorithms[i + 1U], (--nalgorithms - i) * sizeof(*algorithms));
} else {
algorithms[i].offset = 0;
i++;
}
}
return nalgorithms;
}
void
destroyhashers(struct algorithm *algorithms, size_t nalgorithms)
{
size_t i;
for (i = 0; i < nalgorithms; i++)
if (algorithms[i].hasher.destroy)
algorithms[i].hasher.destroy(&algorithms[i].hasher);
}
static void
process(struct algorithm *algorithm, struct global_data *global)
{
size_t r;
r = algorithm->hasher.process(&algorithm->hasher,
&global->buffer->buf[algorithm->offset],
global->buffer->ready - algorithm->offset);
algorithm->offset += r;
}
static void
finalise(struct algorithm *algorithm, struct global_data *global)
{
if (algorithm->hasher.finalise_const(&algorithm->hasher, &global->buffer->buf[algorithm->offset],
global->buffer->ready - algorithm->offset, 0))
abort();
format_result(algorithm, global->file, global->format, global->hexinput);
}
int
calculate(const char *file, struct barrier_group *group, struct global_data *global)
{
int fd, is_new_fd, r, ret = -1, saved_errno;
const char *fname;
global->nalgorithms = inithashers(global->algorithms, global->nalgorithms);
if (!global->nalgorithms)
return 0;
fd = openfile(file, &is_new_fd, &fname);
if (fd < 0)
return -1;
global->buffer->ready = 0;
global->buffer->procoff = 0;
global->buffer->offset = 0;
while (!(r = feedbuffer(fd, global->buffer, fname))) {
if (!global->hexinput) {
global->buffer->ready = global->buffer->offset;
global->buffer->procoff = global->buffer->offset;
} else {
if (unhex(global->buffer)) {
weprintf("%s: not a hexadecimal file", fname);
errno = 0;
goto fail;
}
}
barriersend(group, global, &process);
shiftbuffer(global->algorithms, global->nalgorithms, global->buffer);
}
if (r < 0)
goto fail;
barriersend(group, global, &finalise);
ret = 0;
fail:
saved_errno = errno;
destroyhashers(global->algorithms, global->nalgorithms);
if (is_new_fd)
close(fd);
errno = saved_errno;
return ret;
}