213cy / war3map

2 stars 0 forks source link

暴雪hash 和 jass中的 StringHash #1

Open 213cy opened 7 years ago

213cy commented 7 years ago

2楼是 用 C 实现的 MPQ's hash table
https://sfsrealm.hopto.org/inside_mopaq/chapter2.htm 3楼是 用 C++ 实现的 native StringHash takes string s returns integer
https://github.com/actboy168/YDWE/blob/master/Development/Core/ydwar3/warcraft3/detail/string_hash.cpp

213cy commented 7 years ago
// Blizzard MPQ hash
#include <stdio.h>

    void prepareCryptTable();
void displayCryptTable();
unsigned long HashString(char *lpszFileName, unsigned long dwHashType);
void displayHash(char *lpszFileName);

unsigned long cryptTable[0x500];

int main () {
    int len;

    len = sizeof cryptTable;
    printf("Length: 0x%04x\n", len/8);  

    prepareCryptTable();
    //displayCryptTable();

    displayHash("arr\\units.dat");
    //4108764829  0xf4e6c69d  arr\units.dat
    displayHash("unit\\neutral\\acritter.grp");
    //2724227059  0xa26067f3  unit\neutral\acritter.grp
    displayHash("udg_OSP");
    displayHash("saber碎片:");
    return 1;
}
void displayHash(char *lpszFileName)
{
    unsigned long r;
    r = HashString(lpszFileName, 0);
    printf("%u  0x%x  %s\n", r,  r ,lpszFileName);
}

void displayCryptTable(){
    int len;
    len = sizeof cryptTable;
    printf("Length: %d --- 0x%04x\n", len/8, len/8);

    int i,j,k;
    for (i = 0; i < 5; i++ ){
        k = 0x10*i;
        //      printf("%#x ", k );
        for (j = 1; j < 0x11; j++ ,k++){
            //printf("%4d",  k );
            printf("0x%08x ",  cryptTable[k] );
        }
        printf("\n" );
    }

    cryptTable[25] = 0;
    printf("Length: %d --- 0x%04x\n\n", sizeof cryptTable /8, sizeof cryptTable /8);
}

void prepareCryptTable()
{
    unsigned long seed = 0x00100001, index1 = 0, index2 = 0, i;

    for(index1 = 0; index1 < 0x100; index1++)
    {
        for(index2 = index1, i = 0; i < 5; i++, index2 += 0x100)
        {
            unsigned long temp1, temp2;

            seed = (seed * 125 + 3) % 0x2AAAAB;
            temp1 = (seed & 0xFFFF) << 0x10;

            seed = (seed * 125 + 3) % 0x2AAAAB;
            temp2 = (seed & 0xFFFF);

            cryptTable[index2] = (temp1 | temp2);
        }
    }
}

unsigned long HashString(char *lpszFileName, unsigned long dwHashType)
{
    unsigned char *key = (unsigned char *)lpszFileName;
    unsigned long seed1 = 0x7FED7FED, seed2 = 0xEEEEEEEE;
    int ch;

    while(*key != 0)
    {
        ch = toupper(*key++);
        seed1 = cryptTable[(dwHashType << 8) + ch] ^ (seed1 + seed2);
        seed2 = ch + seed1 + seed2 + (seed2 << 5) + 3;
    }
    return seed1;
}
213cy commented 4 years ago
//warcraft3 map jass stringhash

#include <stdint.h>
    #include <stdlib.h>
    #include <iostream>

    using namespace std;

namespace detail {
    // #define uint32_t unsigned int
    #define STRING_TO_LONG(s) (*((s) + 0) + ((*((s) + 1) + ((*((s) + 2) + (*((s) + 3) << 8)) << 8)) << 8))

        #define T1(A, B, C)                  \
        (A) = ((C)>>13)^((A)-(B)-(C)); \
        (B) = ((A)<< 8)^((B)-(C)-(A)); \
        (C) = ((B)>>13)^((C)-(A)-(B)); \
        (A) = ((C)>>12)^((A)-(B)-(C)); \
        (B) = ((A)<<16)^((B)-(C)-(A)); \
        (C) = ((B)>> 5)^((C)-(A)-(B)); \
        (A) = ((C)>> 3)^((A)-(B)-(C)); \
        (B) = ((A)<<10)^((B)-(C)-(A)); \
        (C) = ((B)>>15)^((C)-(A)-(B)); \

        #define T2(A, B, C)                  \
        (C) = ((C)^((B)>>15))+(B)+(A); \
        (B) = ((B)^((A)<<10))+(A)+(C); \
        (A) = ((A)^((C)>> 3))+(C)+(B); \
        (C) = ((C)^((B)>> 5))+(B)+(A); \
        (B) = ((B)^((A)<<16))+(A)+(C); \
        (A) = ((A)^((C)>>12))+(C)+(B); \
        (C) = ((C)^((B)>>13))+(B)+(A); \
        (B) = ((B)^((A)<< 8))+(A)+(C); \
        (A) = ((A)^((C)>>13))+(C)+(B); \

        unsigned int string_hash_ex(const char* str, size_t size, uint32_t prev)
    {
        unsigned char* p = (unsigned char*)str;
        size_t len = size;

        uint32_t A = 0x9E3779B9;
        uint32_t B = 0x9E3779B9;
        uint32_t C = prev;

        if (len >= 12)
        {

            size_t step = len / 12;
            do
            {
                A += STRING_TO_LONG(p+0);
                B += STRING_TO_LONG(p+4);
                C += STRING_TO_LONG(p+8);

                T1(A, B, C);

                p += 12;
                len -= 12;

            }
            while (--step != 0);
        }

        C = C + size;

        switch (len)
        {

            case 11: C += p[10]<<24;
            case 10: C += p[9]<<16;
            case  9: C += p[8]<<8;
            case  8: B += p[7]<<24;
            case  7: B += p[6]<<16;
            case  6: B += p[5]<<8;
            case  5: B += p[4];
            case  4: A += p[3]<<24;
            case  3: A += p[2]<<16;
            case  2: A += p[1]<<8;
            case  1: A += p[0];

                break;
            default:
                break;
        }

        T1(A, B, C);

        return C;
    }
    #undef T1
        #undef T2
        #undef STRING_TO_LONG

        uint32_t string_hash(const char* str)
    {
        char buffer[0x400];
        size_t len = 0;

        while (str[len]  != '\0')
        {
            if (len >= 0x3FF) break;

            if ('a' <= str[len] && str[len] <= 'z') 
                buffer[len] = str[len] - 'a' + 'A';
            else if (str[len] == '/')
                buffer[len] = '\\';
            else
                buffer[len] = str[len];

            len++;
        }

        return string_hash_ex(buffer, len, 0);
    }

    void display_hash(const char* str)
    {
        int32_t hashValue = string_hash( str );

        cout.width(10);
        cout << dec ;
        cout <<  (unsigned int) hashValue << "  0x";

        cout.width(8);
        cout.fill('0');
        cout << hex;
        //  cout << showbase;
        cout << hashValue << "  ";

        cout << str << endl;    
    }

}

int main() {

    detail::display_hash("udg_OSP");
    //2007669754  0x77aa9bfa
    detail::display_hash("Trig_____________uActions");
    //1443748040  0x560dd8c8
    detail::display_hash("MOVE");

    detail::display_hash("aaaabbbbccccdez");
    detail::display_hash("aaaabbbbccccfgz");

    cout.width(10);
    cout << dec ;
    cout <<  (unsigned int) -1 << "  0x";

    cout.width(8);
    cout.fill('0');
    cout << hex;
    //  cout << showbase;
    cout << 123 << "  ";

    cout << "456" << endl;  

    return 0;
}