static void tt_finish(TTH_CONTEXT *ctx) { if (0 == ctx->n || ctx->block_fill > 1) { tt_block(ctx); } if (ctx->bpl > 1) { fileoffset_t n_blocks; unsigned depth; n_blocks = ctx->n; depth = ctx->depth; while (0 == (n_blocks & 1)) { n_blocks /= 2; depth--; } while (n_blocks > 1) { if (0 == (n_blocks & 1)) { tt_compose(ctx); } depth--; n_blocks = (n_blocks + 1) / 2; if (depth == ctx->good_depth) { g_assert(ctx->li < G_N_ELEMENTS(ctx->leaves)); ctx->leaves[ctx->li] = ctx->stack[ctx->si - 1]; ctx->li++; } } } ctx->stack[0] = tt_root_hash(ctx->leaves, ctx->li); ctx->flags |= TTH_F_FINISHED; }
char* tth(const char* filename, char **tthl, size_t *tthl_len) { char *tth = NULL; size_t numbytes; unsigned char root[24]; unsigned char *cur; TT_CONTEXT tt; unsigned char buf[1 + 256 * BLOCKSIZE]; struct stat sb; unsigned level; size_t leaf_blocksize; int fd = open(filename, O_RDONLY); if ((fd == -1) || ( fstat(fd, &sb) == -1)) { return NULL; } level = calc_block_level(sb.st_size, max_block_count); leaf_blocksize = 1 << (level+10); *tthl_len = 0; *tthl = NULL; tt_init(&tt, *tthl, level); tt.leaf = buf; buf[0] = '\0'; while ( (numbytes = read(fd, &buf[1], sizeof(buf) - 1) ) > 0) { tt.index = BLOCKSIZE; for (cur = &buf[1]; cur + BLOCKSIZE <= &buf[numbytes + 1]; cur += BLOCKSIZE) { tt.leaf = cur - 1; tt.leaf[0] = '\0'; tt_block(&tt); } tt.index = numbytes - (cur - &buf[1]); tt.leaf = cur - 1; tt.leaf[0] = '\0'; } close(fd); tt_digest(&tt, root); tth = base32_encode(root, sizeof(root)); return tth; }
void tt_update(TTH_CONTEXT *ctx, const void *data, size_t size) { const char *block = data; g_assert(ctx); g_assert(TTH_F_INITIALIZED & ctx->flags); g_assert(!(TTH_F_FINISHED & ctx->flags)); g_assert(size == 0 || NULL != data); while (size > 0) { size_t n = sizeof ctx->block.bytes - ctx->block_fill; n = MIN(n, size); memmove(&ctx->block.bytes[ctx->block_fill], block, n); ctx->block_fill += n; block += n; size -= n; if (sizeof ctx->block.bytes == ctx->block_fill) { tt_block(ctx); } } }