/*
 * 2008+ Copyright (c) Evgeniy Polyakov <johnpol@2ka.mipt.ru>
 * All rights reserved.
 *
 * 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.
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>

#define HASH_MULTIPLIER		33

static unsigned int djb2_hash(const void *input, const unsigned int size)
{
	const unsigned char *data = input;
	unsigned int i, hash;

	hash = 0;
	for (i=0; i<size; ++i) {
		hash *= HASH_MULTIPLIER;
		hash += data[i];
	}

	return hash;
}

static int djb_get_factor(unsigned int hash, unsigned char min)
{
	unsigned int p;
	int factor = 0;

	if (min)
		hash /= min;

	p = HASH_MULTIPLIER;
	while (hash >= p) {
		hash -= p;

		p *= HASH_MULTIPLIER;
		factor++;
	}

	return factor;
}

static unsigned int djb_get_char(unsigned int hash, int factor, unsigned char min,
		unsigned char *ch)
{
	unsigned int mult;
	int i;

	mult = min;
	if (!mult)
		mult = 1;

	for (i=0; i<factor; ++i)
		mult *= HASH_MULTIPLIER;

	i = 0;
	while (hash >= mult) {
		hash -= mult;
		i++;
	}

	if (min)
		i *= min;
	*ch = (unsigned char)i;

	return hash;
}

int main(int argc, char *argv[])
{
	unsigned char ch[7];
	unsigned int hash;
	int factor;
	unsigned int h;
	int i, j;
	unsigned char min, max;

	min = 0;
	max = 255;

	for (j=1; j<argc; ++j) {
		h = hash = strtoul(argv[j], NULL, 0);

		factor = djb_get_factor(hash, min);

		if (factor >= (signed)sizeof(ch)) {
			printf("Algorithm bug: hash: 0x%08x, factor: %d.\n", hash, factor);
			return -1;
		}

		i = 0;
		while (factor >= i) {
			h = djb_get_char(h, factor-i, min, &ch[i]);

			printf("%02x ", ch[i]);

			i++;
		}

		h = djb2_hash(ch, i);

		printf("hash: %08x, calc: %08x: %s\n", hash, h, (hash == h)?"MATCH":"FAILED");
	}

	return 0;
}

