Windows NT 4.0 source code leak
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

424 lines
9.5 KiB

#include "unimdm.h"
#include "mcxp.h"
#if 0
#include <windows.h>
#endif
#include <stdio.h>
#include <string.h>
#include "mt.h"
// #define SILENT
#ifdef SILENT
# define PRINTF0(_a) (0)
# define PRINTF1(_a,_b) (0)
# define PRINTF2(_a,_b,_c) (0)
# define PRINTF3(_a,_b,_c,_d) (0)
#else
#ifdef CONSOLE
# define PRINTF0(_a) printf(_a)
# define PRINTF1(_a,_b) printf((_a),(_b))
# define PRINTF2(_a,_b,_c) printf((_a),(_b),(_c))
# define PRINTF3(_a,_b,_c,_d) printf((_a),(_b),(_c),(_d))
#else
# define PRINTF0(_a) DPRINTF(_a)
# define PRINTF1(_a,_b) DPRINTF1((_a),(_b))
# define PRINTF2(_a,_b,_c) DPRINTF2((_a),(_b),(_c))
# define PRINTF3(_a,_b,_c,_d) DPRINTF3((_a),(_b),(_c),(_d))
#endif //!CONSOLE
#endif // !SILENT
// ======================== PRIVATES ===================================
#define ASSERT(_c) \
((_c) ? 0: printf("Assertion failed in %s:%d\n", __FILE__, __LINE__))
typedef struct _MNODE
{
MATCHREC mr;
struct _MNODE *pmnNext;
struct _MNODE *pmnCh;
} MNODE, *PMNODE;
PMNODE mn_create_raw_tree(PMATCHREC pmr, DWORD dwcmr);
BOOL mn_cook_tree (PMNODE pmn, DWORD dwMin);
void mn_free_tree (PMNODE pmn);
PMNODE mn_alloc (PMATCHREC pmr, PMNODE pmnNext);
void mn_free (PMNODE pmn);
void mn_dump_tree (PMNODE pmn, UINT uDepth, UINT uWidth);
DWORD mn_find_smallest(PMNODE pmn);
DWORD mn_find_match(PMNODE pmn, PMATCHREC pmr);
// ======================== PRIVATES (end) ===================================
HMATCHTREE mtCreateTree(PMATCHREC pmr, DWORD dwcmr)
{
PMNODE pmn = mn_create_raw_tree(pmr, dwcmr);
if (!mn_cook_tree(pmn, MAXDWORD))
{
mn_free_tree(pmn);
pmn=NULL;
}
return (DWORD) pmn;
}
void mtFreeTree(HMATCHTREE hmt)
{
PMNODE pmn = (PMNODE) hmt;
mn_free_tree(pmn); // NULL is a valid tree
}
// Returns one or more fMATCH_ flags.
// Searches through all its siblings as well...
// Recursive function, so keep locals to a minimum.
DWORD mtFindMatch(HMATCHTREE hmt, PMATCHREC pmr)
{
MATCHREC mr;
DWORD dwRet = 0;
if (!pmr) goto end;
mr = *pmr; // Structure copy.
dwRet = mn_find_match((PMNODE)hmt, &mr);
// mn_find_match trashes dwLen and cb fields of pmr, only pv field is valid
pmr->pv = mr.pv;
end:
return dwRet;
}
#ifdef DEBUG
void mtDumpTree(HMATCHTREE hmt)
{
PMNODE pmn = (PMNODE) hmt;
mn_dump_tree(pmn, 0, 0);
}
#endif // DEBUG
PMNODE mn_create_raw_tree(PMATCHREC pmr, DWORD dwcmr)
{
PMNODE pmnFirst=NULL;
for (;dwcmr--;pmr++)
{
PMNODE pmnTmp = mn_alloc(pmr, pmnFirst);
if (!pmnTmp) goto failure;
pmnFirst=pmnTmp;
}
goto end;
failure:
mn_free_tree(pmnFirst); // NULL is a valid tree to free
pmnFirst=NULL;
// FALL THROUGH
end:
return pmnFirst;
}
PMNODE mn_alloc(PMATCHREC pmr, PMNODE pmnNext)
{
PMNODE pmn = (pmr && pmr->pb && pmr->dwLen)
? LocalAlloc(LPTR, sizeof(MNODE)) : NULL;
if (pmn)
{
pmn->mr = *pmr; // structure copy.
pmn->pmnNext=pmnNext;
pmn->pmnCh=NULL;
}
return pmn;
}
void mn_free(PMNODE pmn)
{
if (pmn)
{
ASSERT(!pmn->pmnCh && !pmn->pmnNext);
LocalFree(pmn);
}
}
void mn_free_tree(PMNODE pmn)
{
if (pmn)
{
mn_free_tree(pmn->pmnCh); // recurse down
mn_free_tree(pmn->pmnNext); // recurse left
pmn->pmnNext=pmn->pmnCh=NULL;
mn_free(pmn);
}
}
BOOL mn_cook_tree(PMNODE pmn, DWORD dwMin)
{
// Find smallest string of me and siblings
if (dwMin==MAXDWORD) dwMin = mn_find_smallest(pmn);
if (!pmn) goto success;
// These are all serious problems -- so we assert on failure:
if (!dwMin || pmn->pmnCh || !pmn->mr.pb || (pmn->mr.dwLen<dwMin))
goto failure;
// Start my children's list by creating one if pmn->pb is longer
// than the minimum, in which case we also NULL pv, because pv should
// be NULL for internal (non-leaf) nodes.
if (pmn->mr.dwLen>dwMin)
{
MATCHREC mr;
mr.pb=pmn->mr.pb+dwMin;
mr.dwLen=pmn->mr.dwLen-dwMin;
mr.pv=pmn->mr.pv;
pmn->pmnCh = mn_alloc(&mr, NULL);
if (!pmn->pmnCh) goto failure;
pmn->mr.pv=NULL;
pmn->mr.dwLen=dwMin;
}
// Add to my children's list by converting those siblings which
// share my dwMin-sized prefix into my children. (Obviously) remove
// these siblings from the sibling list.
{
PMNODE pmnTmp = pmn;
while(pmnTmp->pmnNext)
{
PMNODE pmnTmp1 = pmnTmp->pmnNext;
if (pmnTmp1->mr.dwLen<dwMin || !pmnTmp1->mr.pb) goto failure;
if (!_strnicmp(pmn->mr.pb, pmnTmp1->mr.pb, dwMin))
{
// Found a prefix match -- remove from sibling list
// and add to child list if non-null
pmnTmp->pmnNext = pmnTmp1->pmnNext;
pmnTmp1->mr.dwLen-=dwMin;
pmnTmp1->mr.pb+=dwMin;
pmnTmp1->pmnNext=NULL;
// If nothing left to add -- we're at the end of pb --
// (leaf node) so we make pmn->pv non-NULL, and free pmnTmp1
// Otherwise we add it to pmn's child's list.
if (!pmnTmp1->mr.dwLen)
{
if (pmn->mr.pv) {PRINTF0("Warning: overriding pv!\n");}
pmn->mr.pv = pmnTmp1->mr.pv;
ASSERT(!pmnTmp1->pmnCh && !pmnTmp1->pmnNext);
mn_free(pmnTmp1);
}
else
{
pmnTmp1->pmnNext = pmn->pmnCh;
pmn->pmnCh=pmnTmp1;
}
}
else
{
pmnTmp = pmnTmp->pmnNext;
}
if (!pmnTmp) break;
}
}
// recurse down
if (!mn_cook_tree(pmn->pmnCh, MAXDWORD)) goto failure;
// recurse left
if (!mn_cook_tree(pmn->pmnNext, dwMin)) goto failure;
// FALL THROUGH
success:
return TRUE;
failure:
ASSERT(FALSE);
return FALSE;
}
DWORD mn_find_smallest(PMNODE pmn)
{
DWORD dw = MAXDWORD;
if (pmn)
{
dw = mn_find_smallest(pmn->pmnNext);
if (dw>pmn->mr.dwLen) dw=pmn->mr.dwLen;
}
return dw;
}
void mn_dump_tree(PMNODE pmn, UINT uDepth, UINT uWidth)
{
static char rgchFill[]="----------------------------------------";
LONG lOff = sizeof(rgchFill) - (uDepth+1);
if (lOff<0) lOff=0;
// if(!pmn) return;
PRINTF2("%02lu%s", (unsigned long) uDepth, rgchFill+lOff);
if (!pmn)
{
PRINTF1("NULL(w=%lu)\n", (unsigned long) uWidth);
}
else
{
CHAR *pb = (pmn->mr.pb)?pmn->mr.pb:"\"\"";
CHAR c = pb[pmn->mr.dwLen];
CHAR *pc2 = (CHAR *) pmn->mr.pv;
if (!pc2) pc2="";
pb[pmn->mr.dwLen]=0;
PRINTF3("[%s]:%02lu %s\n", pc2,
(unsigned long) pmn->mr.dwLen, pb);
pb[pmn->mr.dwLen]=c;
mn_dump_tree(pmn->pmnCh, uDepth+1,0); // recurse down
mn_dump_tree(pmn->pmnNext, uDepth, uWidth+1); // recurse left
}
}
// Returns one or more fMATCH_ flags.
// Searches through all its siblings as well...
// Recursive function, so keep locals to a minimum.
// WARNING: Trashes dwLen and cb fields of pmr.
DWORD mn_find_match(PMNODE pmn, PMATCHREC pmr)
{
DWORD dwRet=0;
DWORD dwcbMin;
CHAR *pc;
#ifdef DEBUG
DWORD dwcb;
CHAR rgchTmp[256];
DWORD dwcbTmp;
#endif // DEBUG
if (!pmn || !pmr) goto end;
#ifdef DEBUG
# define DWCB dwcb
# define DBGPSZ rgchTmp
DWCB = pmr->dwLen;
dwcbTmp = sizeof(DBGPSZ)-1;
if (dwcbTmp>DWCB) dwcbTmp=DWCB;
// We do this because pb is not null terminated.
CopyMemory(DBGPSZ, pmr->pb, dwcbTmp);
DBGPSZ[dwcbTmp]=0;
#else // !DEBUG
# define DBGPSZ ""
# define DWCB 0
#endif // !DEBUG
PRINTF1("Entering mn_find_match(-, [%s], -)\n", DBGPSZ);
// Iterate through siblings, looking for matches and partial matches.
// We stop when we find the first match or partial match, because all
// the substrings at the same level are unique and have the same length:
// so if we found a match we can't find a partial match among the siblings,
// and vice versa. Furthermore, if we find a partial match, we don't really
// care which (could be more than one) sibling it is a partial match for.
// If in the future we we *do* return the node for efficiency purposes
// (so that the next call can start where we left off),
// we would return the node for the *first* partial match we found.
pc = pmr->pb;
dwcbMin = pmn->mr.dwLen;
if (pmr->dwLen<dwcbMin)
{
dwcbMin=pmr->dwLen;
dwRet = fMATCH_PARTIAL;
}
else if (pmr->dwLen==dwcbMin)
{
dwRet = fMATCH_COMPLETE;
}
else
{
// pmr->dwLen>pmn->mr.dwU, dwRet==0, so do nothing
}
// WARNING: we trash pmr here, except for pmr->pv
pmr->dwLen-=dwcbMin;
pmr->pb+=dwcbMin;
while(pmn)
{
// Fundamental assumption is that all dwLens of siblings are equal.
ASSERT((pmn->pmnNext)? pmn->mr.dwLen==pmn->pmnNext->mr.dwLen:TRUE);
if (!_strnicmp(pc, pmn->mr.pb, dwcbMin))
{
PRINTF3("Match: dwcb=%lu; pmn->mr.dwLen=%lu; pc=[%s]\n",
(unsigned long) DWCB,
(unsigned long) pmn->mr.dwLen,
DBGPSZ);
// Note: dwRet is computed just once, out of the while loop.
// we were really overloading dwRet then. Now we compute the
// true return value.
switch(dwRet)
{
case 0: // i.e., (DWCB > pmn->mr.dwLen)
ASSERT(DWCB>pmn->mr.dwLen);
// Recurse down. WARNING: pmr is trashed, except for pmr->pv
dwRet = mn_find_match(pmn->pmnCh, pmr);
break;
case fMATCH_PARTIAL: // i.e., (DWCB < pmn->mr.dwLen)
ASSERT(DWCB<pmn->mr.dwLen);
break;
case fMATCH_COMPLETE: // i.e., (DWCB == pmn->mr.dwLen)
ASSERT(DWCB==pmn->mr.dwLen);
// Now let's see if we're truly a perfect macth: non-null
// pv indicates an actual response terminates in this node.
dwRet=0;
if (pmn->mr.pv)
{
pmr->pv = pmn->mr.pv;
dwRet = fMATCH_COMPLETE;
}
// Non-null pmnCh implies there are postfixes, i.e., longer
// responses
if (pmn->pmnCh)
{
dwRet |= fMATCH_PARTIAL;
}
break;
default:
ASSERT(FALSE);
dwRet=0;
goto end;
}
if (dwRet) break; // break out of while loop if we got something
}
pmn=pmn->pmnNext;
}
if (!pmn)
{
dwRet=0;
}
else
{
ASSERT(dwRet && !_strnicmp(pc, pmn->mr.pb, dwcbMin));
}
PRINTF2("Exiting mn_find_match(-, [%s], -) returing 0x%lx\n", DBGPSZ,
(unsigned long) dwRet);
end:
return dwRet;
}