#ifdef _WIN64 #define FMT64 "%016I64X" #else #ifdef __unix #define FMT64 "%016lX" #else #define FMT64 "%016llX" #endif #endif #include #include #include #include typedef uint8_t u8; typedef uint32_t u32; typedef uint64_t u64; const u64 table[16] = { // magic numbers for each possible value of a nybble. 0x486E26EEDCAA16B3, 0xE1918EEF202DAFDB, 0x341C7DC71C365303, 0x40EF2D3765FD5E49, 0xD6057177904ECE93, 0x1C38024F98FD323B, 0xE3061AE7A39B0FA1, 0x9797F25FE4444563, 0xCD2EC20C8DC1B898, 0x31759633799A306D, 0x8C2063852E6E9627, 0x79237D9973922C66, 0x8728628D28628824, 0x8F1F7E9625887795, 0x296E3281389C0D60, 0x6F4893CA61636542 }; u64 wc3hash(const char *key, size_t len, u64 hash, bool isPath) { // technically there doesn't seem to be a // length argument in the original function, // I'm just adding it so you can hash strings with '\0' in them. if (key == NULL) return 0; if (hash == 0) hash = 0x7FED7FED7FED7FED; u64 state = 0xEEEEEEEEEEEEEEEE; for (size_t i = 0; i < len; i++) { u8 v; if (isPath) { char c = key[i]; if (c >= 'a' && c <= 'z') c -= 'a' - 'A'; // uppercase if (c == '/') c = '\\'; // DOS-style paths v = (u8)c; } else { v = (u8)key[i]; } hash += state; hash ^= table[v >> 4] + table[v & 0xF]; state += state << 5; state += hash + v + 3; } if (hash == 0) return 1; return hash; } u64 wc3hashC(const char *key) { // simple interface that only takes a null-terminated string. return wc3hash(key, strlen(key), 0, true); } int main(int argc, char **argv) { if (argc == 1) { const char str[] = "IseeDeadPeople"; u64 hash = wc3hashC(str); fprintf(stderr, FMT64 " should equal 701EA16D47F385FC\n", hash); return hash != 0x701EA16D47F385FC; } for (int i = 1; i < argc; i++) { u64 hash = wc3hashC(argv[i]); u32 hash32 = (hash >> 32) ^ hash; printf(FMT64 "\t%08X\n", hash, hash32); } return 0; }