Windows2003-3790/inetcore/wininet/http/hashgen/hashgen.cpp
2020-09-30 16:53:55 +02:00

571 lines
20 KiB
C++

/*++
Copyright (c) 1998 Microsoft Corporation
Module Name:
hashgen.cpp
Abstract:
Table Generator for hhead.cxx, which contains all known HTTP headers for wininet project.
This is also the location where all known HTTP headers must be added.
Author:
Arthur Bierer (arthurbi) 12-Jan-1998
Revision History:
--*/
//
// Instructions for adding new HTTP header:
// 1. Update wininet.w and rebuild wininet.h with new HTTP_QUERY_ code
// 2. Add/Edit header to this file/program, hashgen.cpp with the
// new header string (see Items[] array below)
// 3. Compile new hashgen.exe, Execute with -o, write down a good seed
// note that this may take all night to find a good seed which
// give a nice smaller table size. (note this can be skipped if
// you just need a quick table for dev purposes)
// 4. Re-Execute hashgen.exe with -b# set with your seed to generate
// hhead.cxx
// 5. Transfer new hhead.cxx file to wininet\http
// 6. Update const defines MAX_HEADER_HASH_SIZE and HEADER_HASH_SEED
// from new hhead.cxx to wininet\http\headers.h
// 7. Transfer and checkin hashgen.cpp, wininet.w, headers,h, hhead.cxx
// in their appropriate directories.
//
//
// Includes...
//
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <search.h>
#include <wininet.h>
//
// macros
//
#define IS_ARG(c) ((c) == '-')
#define DIM(x) (sizeof(x) / sizeof(x[0]))
#define ENUMDEF(x, y) ,x, #x, #y
#define OUTPUT_CODE_FILE "hhead.cxx"
#define MAX_SIZE_HASHARRAY_TO_ATTEMPT 600
#define UNKNOWN_HASH_ENTRY 0 // character to put in array when when its not valid
//
// Items - This is the array that must be edited for Wininet to process new
// HTTP headers
//
// Things to keep in mind before you add to this array
// 1. Headers are Alphatized for convience sake
// 2. All NULL entries MUST be at the end of the array
// 3. All HTTP_QUERY_* codes in wininet.h MUST have an entry even if they are not strings
// 4. Entries are as follows:
// header string, HTTP_QUERY_* code in wininet.h, flags used in wininet\http\query.cxx
// 5. All entries must be in lowercase.
//
struct Item
{
char *ptok;
DWORD id;
char *pidName;
char *pFlagsName;
} Items[] =
{
{ "Accept" ENUMDEF(HTTP_QUERY_ACCEPT, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Accept-Charset" ENUMDEF(HTTP_QUERY_ACCEPT_CHARSET, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Accept-Encoding" ENUMDEF(HTTP_QUERY_ACCEPT_ENCODING, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Accept-Language" ENUMDEF(HTTP_QUERY_ACCEPT_LANGUAGE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Accept-Ranges" ENUMDEF(HTTP_QUERY_ACCEPT_RANGES, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Age" ENUMDEF(HTTP_QUERY_AGE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Allow" ENUMDEF(HTTP_QUERY_ALLOW, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Authorization" ENUMDEF(HTTP_QUERY_AUTHORIZATION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Cache-Control" ENUMDEF(HTTP_QUERY_CACHE_CONTROL, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Connection" ENUMDEF(HTTP_QUERY_CONNECTION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Base" ENUMDEF(HTTP_QUERY_CONTENT_BASE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Description" ENUMDEF(HTTP_QUERY_CONTENT_DESCRIPTION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Disposition" ENUMDEF(HTTP_QUERY_CONTENT_DISPOSITION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Encoding" ENUMDEF(HTTP_QUERY_CONTENT_ENCODING, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Id" ENUMDEF(HTTP_QUERY_CONTENT_ID, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Language" ENUMDEF(HTTP_QUERY_CONTENT_LANGUAGE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Length" ENUMDEF(HTTP_QUERY_CONTENT_LENGTH, (HTTP_QUERY_FLAG_REQUEST_HEADERS | HTTP_QUERY_FLAG_NUMBER)) },
{ "Content-Location" ENUMDEF(HTTP_QUERY_CONTENT_LOCATION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Md5" ENUMDEF(HTTP_QUERY_CONTENT_MD5, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Range" ENUMDEF(HTTP_QUERY_CONTENT_RANGE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Transfer-Encoding" ENUMDEF(HTTP_QUERY_CONTENT_TRANSFER_ENCODING, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Content-Type" ENUMDEF(HTTP_QUERY_CONTENT_TYPE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Cookie" ENUMDEF(HTTP_QUERY_COOKIE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Cost" ENUMDEF(HTTP_QUERY_COST, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Date" ENUMDEF(HTTP_QUERY_DATE, (HTTP_QUERY_FLAG_REQUEST_HEADERS | HTTP_QUERY_FLAG_SYSTEMTIME)) },
{ "Derived-From" ENUMDEF(HTTP_QUERY_DERIVED_FROM, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Etag" ENUMDEF(HTTP_QUERY_ETAG, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Expect" ENUMDEF(HTTP_QUERY_EXPECT, (HTTP_QUERY_FLAG_REQUEST_HEADERS | HTTP_QUERY_FLAG_SYSTEMTIME)) },
{ "Expires" ENUMDEF(HTTP_QUERY_EXPIRES, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Forwarded" ENUMDEF(HTTP_QUERY_FORWARDED, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "From" ENUMDEF(HTTP_QUERY_FROM, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Host" ENUMDEF(HTTP_QUERY_HOST, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "If-Modified-Since" ENUMDEF(HTTP_QUERY_IF_MODIFIED_SINCE, (HTTP_QUERY_FLAG_REQUEST_HEADERS | HTTP_QUERY_FLAG_SYSTEMTIME)) },
{ "If-Match" ENUMDEF(HTTP_QUERY_IF_MATCH, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "If-None-Match" ENUMDEF(HTTP_QUERY_IF_NONE_MATCH, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "If-Range" ENUMDEF(HTTP_QUERY_IF_RANGE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "If-Unmodified-Since" ENUMDEF(HTTP_QUERY_IF_UNMODIFIED_SINCE, (HTTP_QUERY_FLAG_REQUEST_HEADERS | HTTP_QUERY_FLAG_SYSTEMTIME)) },
{ "Last-Modified" ENUMDEF(HTTP_QUERY_LAST_MODIFIED, (HTTP_QUERY_FLAG_REQUEST_HEADERS | HTTP_QUERY_FLAG_SYSTEMTIME)) },
{ "Link" ENUMDEF(HTTP_QUERY_LINK, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Location" ENUMDEF(HTTP_QUERY_LOCATION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Mime-Version" ENUMDEF(HTTP_QUERY_MIME_VERSION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Max-Forwards" ENUMDEF(HTTP_QUERY_MAX_FORWARDS, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Message-id" ENUMDEF(HTTP_QUERY_MESSAGE_ID, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Ms-Echo-Request" ENUMDEF(HTTP_QUERY_ECHO_REQUEST, 0) },
{ "Ms-Echo-Reply" ENUMDEF(HTTP_QUERY_ECHO_REPLY, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Orig-Uri" ENUMDEF(HTTP_QUERY_ORIG_URI, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Pragma" ENUMDEF(HTTP_QUERY_PRAGMA, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Proxy-Authenticate" ENUMDEF(HTTP_QUERY_PROXY_AUTHENTICATE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Proxy-Authorization" ENUMDEF(HTTP_QUERY_PROXY_AUTHORIZATION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Proxy-Connection" ENUMDEF(HTTP_QUERY_PROXY_CONNECTION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Proxy-Support" ENUMDEF(HTTP_QUERY_PROXY_SUPPORT, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Public" ENUMDEF(HTTP_QUERY_PUBLIC, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Range" ENUMDEF(HTTP_QUERY_RANGE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Referer" ENUMDEF(HTTP_QUERY_REFERER, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Refresh" ENUMDEF(HTTP_QUERY_REFRESH, 0) },
{ "Retry-After" ENUMDEF(HTTP_QUERY_RETRY_AFTER, (HTTP_QUERY_FLAG_REQUEST_HEADERS | HTTP_QUERY_FLAG_SYSTEMTIME)) },
{ "Server" ENUMDEF(HTTP_QUERY_SERVER, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Set-Cookie" ENUMDEF(HTTP_QUERY_SET_COOKIE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Title" ENUMDEF(HTTP_QUERY_TITLE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Transfer-Encoding" ENUMDEF(HTTP_QUERY_TRANSFER_ENCODING, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Unless-Modified-Since" ENUMDEF(HTTP_QUERY_UNLESS_MODIFIED_SINCE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Upgrade" ENUMDEF(HTTP_QUERY_UPGRADE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Uri" ENUMDEF(HTTP_QUERY_URI, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "User-Agent" ENUMDEF(HTTP_QUERY_USER_AGENT, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Vary" ENUMDEF(HTTP_QUERY_VARY, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Via" ENUMDEF(HTTP_QUERY_VIA, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Warning" ENUMDEF(HTTP_QUERY_WARNING, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "WWW-Authenticate" ENUMDEF(HTTP_QUERY_WWW_AUTHENTICATE, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "Authentication-Info" ENUMDEF(HTTP_QUERY_AUTHENTICATION_INFO, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "PassportURLs" ENUMDEF(HTTP_QUERY_PASSPORT_URLS, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ "PassportConfig" ENUMDEF(HTTP_QUERY_PASSPORT_CONFIG, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
// NULL strs must be in end of array
{ NULL ENUMDEF(HTTP_QUERY_VERSION, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ NULL ENUMDEF(HTTP_QUERY_STATUS_CODE, HTTP_QUERY_FLAG_NUMBER) },
{ NULL ENUMDEF(HTTP_QUERY_STATUS_TEXT, 0) },
{ NULL ENUMDEF(HTTP_QUERY_RAW_HEADERS, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ NULL ENUMDEF(HTTP_QUERY_RAW_HEADERS_CRLF, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ NULL ENUMDEF(HTTP_QUERY_REQUEST_METHOD, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ NULL ENUMDEF(HTTP_QUERY_ECHO_HEADERS, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
{ NULL ENUMDEF(HTTP_QUERY_ECHO_HEADERS_CRLF, HTTP_QUERY_FLAG_REQUEST_HEADERS) },
};
//
// Declarations of common strings used in creating output "C" file
//
char szFileHeader[] =
{"/*++\n\n"
"Copyright (c) 1997 Microsoft Corporation\n\n"
"Module Name:\n\n"
" "
OUTPUT_CODE_FILE
"\n\n"
"Abstract:\n\n"
" This file contains autogenerated table values of a perfect hash function\n"
" DO NOT, DO NOT EDIT THIS FILE, TO ADD HEADERS SEE hashgen.cpp\n"
" Contents:\n"
" GlobalKnownHeaders\n"
" GlobalHeaderHashs\n\n"
"Author:\n\n"
" Arthur Bierer (arthurbi) 19-Dec-1997 (AND) my code generator[hashgen.exe]\n\n"
"Revision History:\n\n"
"--*/\n\n\n" };
char szComment1[] = {
"//\n"
"// GlobalHeaderHashs - array of precalculated hashes on case-sensetive set of known headers.\n"
"// This array must be used with the same hash function used to generate it.\n"
"// Note, all entries in this array are biased (++'ed) by 1 from HTTP_QUERY_ manifests in wininet.h.\n"
"// 0-ed entries indicate error values\n"
"//\n\n" };
char szComment2[] = {
"//\n"
"// GlobalKnownHeaders - array of HTTP request and response headers that we understand.\n"
"// This array must be in the same order as the HTTP_QUERY_ manifests in WININET.H\n"
"//\n\n"
"#define HEADER_ENTRY(String, Flags, HashVal) String, sizeof(String) - 1, Flags, HashVal\n\n" };
char szDef1[] = {
"#ifdef HEADER_HASH_SEED\n"
"#if (HEADER_HASH_SEED != %u)\n"
"#error HEADER_HASH_SEED has not been updated in the header file, please copy this number to the header\n"
"#endif\n"
"#else\n"
"#define HEADER_HASH_SEED %u\n"
"#endif\n\n" };
char szDef2[] = {
"#ifdef MAX_HEADER_HASH_SIZE\n"
"#if (MAX_HEADER_HASH_SIZE != %u)\n"
"#error MAX_HEADER_HASH_SIZE has not been updated in the header file, please copy this number to the header\n"
"#endif\n"
"#else\n"
"#define MAX_HEADER_HASH_SIZE %u\n"
"#endif\n\n" };
char szDef3[] = {
"#ifdef HTTP_QUERY_MAX\n"
"#if (HTTP_QUERY_MAX != %u)\n"
"#error HTTP_QUERY_MAX is not the same as the value used in wininet.h, this indicates mismatched headers, see hashgen.cpp\n"
"#endif\n"
"#endif\n\n" };
char szIncludes[] = {
"#include <wininetp.h>\n"
"#include \"httpp.h\"\n\n" };
//
// Hash - function used to create table,
// THIS FUNCTION MUST BE THE SAME AS THE ONE USED in WININET
//
DWORD Hash(char *pszName, DWORD j, DWORD seed)
{
DWORD hash = seed;
while (*pszName)
{
hash += (hash << 5) + *pszName++;
}
return (j==0) ? hash : hash % j;
}
//
// CompareItems - a util function for qsort-ing by ID for table creation
// in the output file
//
int __cdecl CompareItems (const void *elem1, const void *elem2 )
{
const struct Item *pItem1, *pItem2;
pItem1 = (struct Item *) elem1;
pItem2 = (struct Item *) elem2;
if ( pItem1->id < pItem2->id )
{
return -1;
}
else if ( pItem1->id > pItem2->id )
{
return 1;
}
return 0;
}
//
// usage() - print out our usage instructions to command line
//
void usage() {
fprintf(stderr,
"\n"
"usage: hashgen [-m[#]] [-b[#]] [-t[#]] [-o] [-p<path>] [-f<filename>]\n"
"\n"
"where: -m[#] = Max hash table size to test with, default = 600\n"
" -b[#] = Starting hash seed, default = 0\n"
" -t[#] = Threshold of table size to halt search at, default = 200\n"
" -o = Enable optimal exhaustive search mode (can take 24+ hrs)\n"
" -p = Path used for output generation\n"
" -f = Output filename, \"hhead.cxx\" is assumed\n"
"\n"
"Instructions for adding new HTTP header:\n"
"\t1. Update wininet.w and rebuild wininet.h with new HTTP_QUERY_ code\n"
"\t2. Add/Edit this file/program, hashgen.cpp with the new header string\n"
"\t3. Compile/Execute new hashgen.exe with -o, write down a good seed\n"
"\t4. Re-Execute hashgen.exe with -b# set with your seed to generate\n"
"\t hhead.cxx\n"
"\t5. Transfer new hhead.cxx file to wininet\\http\n"
"\t6. Update const defines MAX_HEADER_HASH_SIZE and HEADER_HASH_SEED\n"
"\t from new hhead.cxx to wininet\\http\\headers.h\n"
"\t7. Transfer and checkin hashgen.cpp, wininet.w, headers,h, hhead.cxx\n"
);
exit(1);
}
//
// MakeMeLower - Makes a lower case string using a static 255 byte array
//
LPSTR
MakeMeLower(
IN LPSTR lpszMixedCaseStr
)
{
static CHAR szLowerCased[256];
if ( lstrlen(lpszMixedCaseStr) > 255 )
{
fprintf(stderr, "Internal error: an HTTP header is too long\n\n");
return szLowerCased;
}
lstrcpy( szLowerCased, lpszMixedCaseStr );
CharLower(szLowerCased);
return szLowerCased;
}
//
// main - where it all gets done !!!!
//
void
__cdecl
//_CRTAPI1
main(
int argc,
char * argv[]
)
{
DWORD nMax = MAX_SIZE_HASHARRAY_TO_ATTEMPT;
DWORD dwBestNumber = 0, dwBestSeed = 0 /*349160*/ /*4458*//*202521*/;
DWORD dwSearchThreshold = 200;
BOOL bFoundOne = FALSE;
BOOL bFindOptimalSeed = FALSE;
LPSTR szPath = "";
LPSTR szFileName = OUTPUT_CODE_FILE;
DWORD i, j, k;
DWORD dwValidStringsInArray = 0;
DWORD *pHash = new DWORD[nMax];
for (--argc, ++argv; argc; --argc, ++argv) {
if (IS_ARG(**argv)) {
switch (*++*argv) {
case '?':
usage();
break;
case 'm':
nMax = (DWORD)atoi(++*argv);
break;
case 'b':
dwBestSeed = (DWORD)atoi(++*argv);
break;
case 't':
dwSearchThreshold = (DWORD)atoi(++*argv);
break;
case 'p':
szPath = ++*argv;
break;
case 'f':
szFileName = ++*argv;
break;
case 'o':
bFindOptimalSeed = TRUE;
break;
default:
fprintf(stderr,"error: unrecognized command line flag: '%c'\n", **argv);
usage();
}
} else {
fprintf(stderr,"error: unrecognized command line argument: \"%s\"\n", *argv);
usage();
}
}
//
// Let the Work begin...
//
dwBestNumber = nMax;
if (bFindOptimalSeed)
{
printf("This will take a while, perhaps all night(consider a Ctrl-C)...\n");
}
for (i = 0; i < DIM(Items); i++ )
{
if ( Items[i].ptok )
dwValidStringsInArray++;
}
for (i = dwBestSeed; i < (~0); i++)
{
//printf("%d,\n", i);
for (j = dwValidStringsInArray; j < nMax; j++)
{
memset (pHash, UNKNOWN_HASH_ENTRY, nMax * sizeof(DWORD));
for (k = 0; k < dwValidStringsInArray; k++)
{
DWORD HashNow = Hash(MakeMeLower(Items[k].ptok), j, i) /*% j(table_size), i(seed)*/;
if ( HashNow > j )
{
fprintf(stderr, "Error, Error - exceed table size, bad hash alg\n");
break;
}
if (pHash[HashNow] != UNKNOWN_HASH_ENTRY)
break;
else
{
pHash[HashNow] = Items[k].id+1;
}
}
if ( k == dwValidStringsInArray )
{
//printf( "Found one with hash_size=%d, seed=%u...\n", j,i );
bFoundOne = TRUE;
goto found_one;
}
}
found_one:
if ( bFoundOne )
{
if (j < dwBestNumber)
{
dwBestNumber = j;
dwBestSeed = i;
printf("Found a New One, hashtable_size=%d, seed=%u...\n", j ,i);
if ( !bFindOptimalSeed && dwBestNumber < dwSearchThreshold )
{
goto stop_search;
}
}
bFoundOne = FALSE;
}
}
stop_search:
if ( dwBestNumber < nMax && dwBestNumber == j)
{
printf("Generating %s which contains, perfect hash for known headers\n", OUTPUT_CODE_FILE);
FILE *f;
CHAR szOutputFileAndPath[512];
strcpy(szOutputFileAndPath, szPath);
strcat(szOutputFileAndPath, szFileName);
f = fopen(szOutputFileAndPath, "w");
if ( f == NULL )
{
fprintf(stderr, "Err: Could Not Open %s for writing\n", szOutputFileAndPath);
exit(-1);
}
fprintf(f, szFileHeader); // print header
fprintf(f, szIncludes); // includes
fprintf(f, szDef1, dwBestSeed, dwBestSeed);
fprintf(f, szDef2, dwBestNumber, dwBestNumber);
fprintf(f, szDef3, HTTP_QUERY_MAX);
fprintf(f, szComment1); // print comment
if ( dwBestNumber < 255 )
{
fprintf(f, "const BYTE GlobalHeaderHashs[MAX_HEADER_HASH_SIZE] = {\n");
}
else
{
fprintf(f, "const WORD GlobalHeaderHashs[MAX_HEADER_HASH_SIZE] = {\n");
}
DWORD col = 0;
//
// spit our Nicely calculated perfect hash table..
//
for ( i = 0; i < dwBestNumber; i++ )
{
col++;
if ( col == 1 )
{
fprintf(f, " ");
}
fprintf(f, "%3u, ", (BYTE) pHash[i]);
if ( col == 6 )
{
fprintf(f, "\n");
col = 0;
}
}
fprintf(f, "\n };\n\n");
//
// Now spit our KnownHeader array...
//
qsort(Items, DIM(Items), sizeof(Items[0]), CompareItems);
fprintf(f, szComment2);
if ( DIM(Items) != (HTTP_QUERY_MAX+1) )
{
fprintf(stderr, "ERROR, HTTP_QUERY_MAX the wrong size,( different wininet.h's? )\n");
return;
}
fprintf(f, "const struct KnownHeaderType GlobalKnownHeaders[HTTP_QUERY_MAX+1] = {\n");
for (j = 0; j < DIM(Items); j++)
{
char szBuffer[256];
DWORD dwHash = 0;
sprintf(szBuffer, " HEADER_ENTRY(\"%s\",", (Items[j].ptok ? Items[j].ptok : "\0"));
if ( Items[j].ptok )
{
dwHash = Hash(MakeMeLower(Items[j].ptok), 0, dwBestSeed);
}
fprintf(f, "%-45s %s, 0x%X),\n", szBuffer, Items[j].pFlagsName, dwHash);
}
fprintf(f," };\n\n\n");
fclose(f);
}
else
{
fprintf(stderr, "Error, could not find an ideal number\n");
}
}