253 lines
6.9 KiB
C
253 lines
6.9 KiB
C
//
|
|
// Copyright (c) Microsoft Corporation 1991-1993
|
|
//
|
|
// File: Hash.c
|
|
//
|
|
// Comments:
|
|
// This file contains functions that are roughly equivelent to the
|
|
// kernel atom function. There are two main differences. The first
|
|
// is that in 32 bit land the tables are maintined in our shared heap,
|
|
// which makes it shared between all of our apps. The second is that
|
|
// we can assocate a long pointer with each of the items, which in many
|
|
// cases allows us to keep from having to do a secondary lookup from
|
|
// a different table
|
|
//
|
|
// History:
|
|
// 09/08/93 - Created KurtE
|
|
//
|
|
//---------------------------------------------------------------------------
|
|
|
|
#ifdef STRICT
|
|
#undef STRICT
|
|
#endif
|
|
#define NO_SHELL_HEAP_ALLOCATOR //Kludge to get around new mem heaps in nt
|
|
|
|
#define NO_SHELL_VALIDATION
|
|
|
|
// to fix assert problem
|
|
#ifdef ASSERT
|
|
#undef ASSERT
|
|
#endif
|
|
|
|
#include "project.h"
|
|
#include "urlshell.h"
|
|
#include <platform.h>
|
|
|
|
|
|
//--------------------------------------------------------------------------
|
|
// First define a data structure to use to maintain the list
|
|
|
|
#define PRIME 37
|
|
|
|
// NOTE a PHASHITEM is defined as a LPCSTR externaly (for old code to work)
|
|
#undef PHASHITEM
|
|
typedef struct _HashItem FAR * PHASHITEM;
|
|
|
|
typedef struct _HashItem
|
|
{
|
|
PHASHITEM phiNext; //
|
|
UINT wCount; // Usage count
|
|
BYTE cbLen; // Length of name in characters.
|
|
char szName[1]; // name
|
|
} HASHITEM;
|
|
|
|
typedef struct _HashTable
|
|
{
|
|
UINT wBuckets; // Number of buckets
|
|
UINT wcbExtra; // Extra bytes per item
|
|
BOOL fUpperCase; // Uppercase names
|
|
PHASHITEM phiLast; // Pointer to the last item we worked with
|
|
PHASHITEM ahiBuckets[EMPTY_SIZE]; // Set of buckets for the table
|
|
} HASHTABLE, FAR * PHASHTABLE;
|
|
|
|
#define HIFROMSZ(sz) ((PHASHITEM)((BYTE*)(sz) - FIELDOFFSET(HASHITEM, szName)))
|
|
#define HIDATAPTR(sz) ((DWORD UNALIGNED *)((BYTE*)(sz) + HIFROMSZ(sz)->cbLen+1))
|
|
|
|
#define LOOKUPHASHITEM 0
|
|
#define ADDHASHITEM 1
|
|
#define DELETEHASHITEM 2
|
|
|
|
static PHASHTABLE g_pHashTable = NULL;
|
|
|
|
PHASHTABLE NEAR PASCAL GetGlobalHashTable();
|
|
|
|
//--------------------------------------------------------------------------
|
|
// This function looks up the name in the hash table and optionally does
|
|
// things like add it, or delete it.
|
|
//
|
|
|
|
//// FEATURE
|
|
// we will need to serialize this eventually.
|
|
|
|
LPCSTR NEAR PASCAL LookupItemInHashTable(PHASHTABLE pht, LPCSTR pszName, int iOp)
|
|
{
|
|
// First thing to do is calculate the hash value for the item
|
|
DWORD dwHash = 0;
|
|
UINT wBucket;
|
|
BYTE cbName = 0;
|
|
BYTE c;
|
|
PHASHITEM phi, phiPrev;
|
|
LPCSTR psz = pszName;
|
|
|
|
if (pht == NULL) {
|
|
pht = GetGlobalHashTable();
|
|
}
|
|
|
|
if (pht)
|
|
{
|
|
while (*psz)
|
|
{
|
|
// Same type of hash like HashItem manager
|
|
c = *psz++;
|
|
|
|
if (pht->fUpperCase && ( c >= 'a') && (c <= 'z'))
|
|
c = c - 'a' + 'A';
|
|
dwHash += (c << 1) + (c >> 1) + c;
|
|
cbName++;
|
|
ASSERT(cbName);
|
|
|
|
if (cbName == 0)
|
|
return(NULL); // Length to long!
|
|
}
|
|
|
|
// now search for the item in the buckets.
|
|
phiPrev = NULL;
|
|
ENTERCRITICAL;
|
|
phi = pht->ahiBuckets[wBucket = (UINT)(dwHash % pht->wBuckets)];
|
|
|
|
while (phi)
|
|
{
|
|
if (phi->cbLen == cbName)
|
|
{
|
|
if (pht->fUpperCase)
|
|
{
|
|
if (!lstrcmpi(pszName, phi->szName))
|
|
break; // Found match
|
|
}
|
|
else
|
|
{
|
|
if (!lstrcmp(pszName, phi->szName))
|
|
break; // Found match
|
|
}
|
|
}
|
|
phiPrev = phi; // Keep the previous item
|
|
phi = phi->phiNext;
|
|
}
|
|
|
|
//
|
|
// Sortof gross, but do the work here
|
|
//
|
|
switch (iOp)
|
|
{
|
|
case ADDHASHITEM:
|
|
if (phi)
|
|
{
|
|
// Simply increment the reference count
|
|
#ifdef HITTRACE
|
|
DebugMsg(DM_TRACE, "Add Hit on '%s'", pszName);
|
|
#endif
|
|
phi->wCount++;
|
|
}
|
|
else
|
|
{
|
|
#ifdef HITTRACE
|
|
DebugMsg(DM_TRACE, "Add MISS on '%s'", pszName);
|
|
#endif
|
|
// Not Found, try to allocate it out of the heap
|
|
phi = (PHASHITEM)Alloc(sizeof(HASHITEM) + cbName + pht->wcbExtra);
|
|
|
|
if (phi != NULL)
|
|
{
|
|
// Initialize it
|
|
phi->wCount = 1; // One use of it
|
|
phi->cbLen = cbName; // The length of it;
|
|
lstrcpy(phi->szName, pszName);
|
|
|
|
// And link it in to the right bucket
|
|
phi->phiNext = pht->ahiBuckets[wBucket];
|
|
pht->ahiBuckets[wBucket] = phi;
|
|
}
|
|
}
|
|
pht->phiLast = phi;
|
|
break;
|
|
|
|
case DELETEHASHITEM:
|
|
if (phi)
|
|
{
|
|
phi->wCount--;
|
|
if (phi->wCount == 0)
|
|
{
|
|
// Useage count went to zero so unlink it and delete it
|
|
if (phiPrev != NULL)
|
|
phiPrev->phiNext = phi->phiNext;
|
|
else
|
|
pht->ahiBuckets[wBucket] = phi->phiNext;
|
|
|
|
// And delete it
|
|
Free(phi);
|
|
|
|
phi = NULL;
|
|
}
|
|
}
|
|
|
|
case LOOKUPHASHITEM:
|
|
pht->phiLast = phi;
|
|
break;
|
|
}
|
|
|
|
LEAVECRITICAL;
|
|
}
|
|
else
|
|
{
|
|
phi = NULL;
|
|
}
|
|
|
|
// If find was passed in simply return it.
|
|
return phi ? (LPCSTR)phi->szName : NULL;
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
LPCSTR WINAPI AddHashItem(PHASHTABLE pht, LPCSTR lpszStr)
|
|
{
|
|
return LookupItemInHashTable(pht, lpszStr, ADDHASHITEM);
|
|
}
|
|
|
|
//--------------------------------------------------------------------------
|
|
|
|
LPCSTR WINAPI DeleteHashItem(PHASHTABLE pht, LPCSTR lpszStr)
|
|
{
|
|
return LookupItemInHashTable(pht, lpszStr, DELETEHASHITEM);
|
|
}
|
|
|
|
//======================================================================
|
|
|
|
PHASHTABLE WINAPI CreateHashItemTable(UINT wBuckets, UINT wExtra, BOOL fCaseSensitive)
|
|
{
|
|
PHASHTABLE pht;
|
|
|
|
if (wBuckets == 0)
|
|
wBuckets = 71;
|
|
|
|
pht = (PHASHTABLE)Alloc(sizeof(HASHTABLE) + wBuckets * sizeof(PHASHITEM));
|
|
|
|
if (pht) {
|
|
pht->fUpperCase = !fCaseSensitive;
|
|
pht->wBuckets = wBuckets;
|
|
pht->wcbExtra = wExtra;
|
|
}
|
|
|
|
return pht;
|
|
}
|
|
|
|
//======================================================================
|
|
|
|
PHASHTABLE NEAR PASCAL GetGlobalHashTable()
|
|
{
|
|
if (g_pHashTable == NULL) {
|
|
g_pHashTable = CreateHashItemTable(71, 0, FALSE);
|
|
}
|
|
return g_pHashTable;
|
|
}
|
|
|