1213 lines
29 KiB
C++
1213 lines
29 KiB
C++
// Copyright (C) Microsoft Corporation 1993-1997
|
|
|
|
#include "header.H"
|
|
|
|
#ifndef _CTABLE_INCLUDED
|
|
#include "ctable.h"
|
|
#endif
|
|
|
|
const int TABLE_ALLOC_SIZE = 4096; // allocate in page increments
|
|
const int MAX_POINTERS = (1024 * 1024); // 1 meg, 260,000+ strings
|
|
const int MAX_STRINGS = (10 * 1024 * 1024) - 4096L; // 10 megs
|
|
|
|
// Align on 32 bits for Intel, 64 bits for MIPS
|
|
|
|
#ifdef _X86_
|
|
const int ALIGNMENT = 4;
|
|
#else
|
|
const int ALIGNMENT = 8;
|
|
#endif
|
|
|
|
#ifdef _DEBUG
|
|
int g_cbTableAllocated;
|
|
int g_cbTableReserved;
|
|
int g_cTables;
|
|
#endif
|
|
|
|
CTable::CTable()
|
|
{
|
|
cbMaxBase = MAX_STRINGS;
|
|
cbMaxTable = MAX_POINTERS;
|
|
InitializeTable();
|
|
#ifdef _DEBUG
|
|
g_cTables++;
|
|
#endif
|
|
}
|
|
|
|
// Use this constructor to reduce reserved memory
|
|
|
|
CTable::CTable(int cbStrings)
|
|
{
|
|
cbMaxBase = cbStrings;
|
|
cbMaxTable = cbStrings / 4;
|
|
InitializeTable();
|
|
#ifdef _DEBUG
|
|
g_cTables++;
|
|
#endif
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: =
|
|
|
|
PURPOSE: Copies a table -- only works with tables containing ONLY
|
|
strings. Won't work with tables that combined data with
|
|
the strings.
|
|
|
|
PARAMETERS:
|
|
tblSrc
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
26-Mar-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
#pragma warning(disable:4172) // returning address of local variable or temporary
|
|
|
|
const CTable& CTable::operator =(const CTable& tblSrc)
|
|
{
|
|
Empty();
|
|
|
|
int srcpos = 1;
|
|
while (srcpos < tblSrc.endpos) {
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if (endpos >= maxpos)
|
|
{
|
|
return NULL;
|
|
}
|
|
|
|
if ((ppszTable[endpos] =
|
|
TableMalloc((int)strlen(tblSrc.ppszTable[srcpos]) + 1)) == NULL) {
|
|
OOM();
|
|
return *this;
|
|
}
|
|
strcpy(ppszTable[endpos++], tblSrc.ppszTable[srcpos++]);
|
|
}
|
|
return *this;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ~CTable
|
|
|
|
PURPOSE: Close the table and free all memory associated with it
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
26-Feb-1990 [ralphw]
|
|
27-Mar-1990 [ralphw]
|
|
Pass the address of the handle, so that we can set it to NULL.
|
|
This eliminates the chance of using a handle after it's memory
|
|
has been freed.
|
|
|
|
***************************************************************************/
|
|
|
|
CTable::~CTable()
|
|
{
|
|
Cleanup();
|
|
#ifdef _DEBUG
|
|
g_cTables--;
|
|
#endif
|
|
}
|
|
|
|
void CTable::Cleanup(void)
|
|
{
|
|
if (pszBase) {
|
|
VirtualFree(pszBase, cbStrings, MEM_DECOMMIT);
|
|
VirtualFree(pszBase, 0, MEM_RELEASE);
|
|
}
|
|
if (ppszTable) {
|
|
VirtualFree(ppszTable, cbPointers, MEM_DECOMMIT);
|
|
VirtualFree(ppszTable, 0, MEM_RELEASE);
|
|
}
|
|
if (m_pFreed)
|
|
lcClearFree(&m_pFreed);
|
|
#ifdef _DEBUG
|
|
g_cbTableAllocated -= (cbPointers + cbStrings);
|
|
g_cbTableReserved -= (cbMaxBase + cbMaxTable);
|
|
#endif
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CTable::Empty
|
|
|
|
PURPOSE: Empties the current table by freeing all memory, then
|
|
recreating the table using the default size
|
|
|
|
PARAMETERS:
|
|
void
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
22-Feb-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::Empty(void)
|
|
{
|
|
Cleanup();
|
|
InitializeTable();
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: GetString
|
|
|
|
PURPOSE: get a line from the table
|
|
|
|
RETURNS: FALSE if there are no more lines
|
|
|
|
COMMENTS:
|
|
If no strings have been placed into the table, the return value
|
|
is FALSE.
|
|
|
|
MODIFICATION DATES:
|
|
01-Jan-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
BOOL CTable::GetString(PSTR pszDst)
|
|
{
|
|
*pszDst = 0; // clear the line no matter what happens
|
|
|
|
if (curpos >= endpos)
|
|
return FALSE;
|
|
strcpy(pszDst, (PCSTR) ppszTable[curpos++]);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CTable::GetString(PSTR pszDst, int pos) const
|
|
{
|
|
*pszDst = 0; // clear the line no matter what happens
|
|
|
|
if (pos >= endpos || pos == 0)
|
|
return FALSE;
|
|
strcpy(pszDst, (PCSTR) ppszTable[pos]);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL CTable::GetIntAndString(int* plVal, PSTR pszDst)
|
|
{
|
|
*pszDst = 0; // clear the line no matter what happens
|
|
|
|
if (curpos >= endpos)
|
|
return FALSE;
|
|
*plVal = *(int *) ppszTable[curpos];
|
|
strcpy(pszDst, (PCSTR) ppszTable[curpos++] + sizeof(int));
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: AddString
|
|
|
|
PURPOSE: Add a string to a table
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
01-Jan-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int CTable::AddString(PCSTR pszString)
|
|
{
|
|
if (!pszString)
|
|
return 0;
|
|
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if (endpos >= maxpos)
|
|
return 0;
|
|
|
|
if ((ppszTable[endpos] =
|
|
TableMalloc((int)strlen(pszString) + 1)) == NULL)
|
|
return 0;
|
|
|
|
strcpy(ppszTable[endpos], pszString);
|
|
|
|
return endpos++;
|
|
}
|
|
|
|
int CTable::AddString(PCWSTR pszString)
|
|
{
|
|
if (!pszString)
|
|
return 0;
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if (endpos >= maxpos)
|
|
return 0;
|
|
|
|
if ((ppszTable[endpos] =
|
|
TableMalloc((int)lstrlenW(pszString) + 2)) == NULL)
|
|
return 0;
|
|
|
|
lstrcpyW((PWSTR) ppszTable[endpos], pszString);
|
|
|
|
return endpos++;
|
|
}
|
|
|
|
int CTable::AddData(int cb, const void* pdata)
|
|
{
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if (endpos >= maxpos)
|
|
return 0;
|
|
|
|
if ((ppszTable[endpos] = TableMalloc(cb)) == NULL)
|
|
return 0;
|
|
|
|
if (pdata)
|
|
CopyMemory(ppszTable[endpos], pdata, cb);
|
|
|
|
return endpos++;
|
|
}
|
|
|
|
int CTable::AddIntAndString(int lVal, PCSTR pszString)
|
|
{
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if (endpos >= maxpos)
|
|
return 0;
|
|
|
|
if ((ppszTable[endpos] =
|
|
TableMalloc((int)strlen(pszString) + 1 + (int)sizeof(int))) == NULL)
|
|
return 0;
|
|
|
|
*(int*) ppszTable[endpos] = lVal;
|
|
strcpy(ppszTable[endpos] + sizeof(int), pszString);
|
|
|
|
return endpos++;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: IncreaseTableBuffer
|
|
|
|
PURPOSE: Called when we need more room for string pointers
|
|
|
|
PARAMETERS:
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
23-Feb-1992 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::IncreaseTableBuffer(void)
|
|
{
|
|
ASSERT(cbPointers < cbMaxTable);
|
|
if (!VirtualAlloc((PBYTE) ppszTable + cbPointers, TABLE_ALLOC_SIZE,
|
|
MEM_COMMIT, PAGE_READWRITE)) {
|
|
OOM();
|
|
return;
|
|
}
|
|
cbPointers += TABLE_ALLOC_SIZE;
|
|
#ifdef _DEBUG
|
|
g_cbTableAllocated += TABLE_ALLOC_SIZE;
|
|
#endif
|
|
maxpos = cbPointers / sizeof(PSTR);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: TableMalloc
|
|
|
|
PURPOSE: Suballocate memory
|
|
|
|
RETURNS:
|
|
pointer to the memory
|
|
|
|
COMMENTS:
|
|
Instead of allocating memory for each string, memory is used from 4K
|
|
blocks. When the table is freed, all memory is freed as a single
|
|
unit. This has the advantage of speed for adding strings, speed for
|
|
freeing all strings, and low memory overhead to save strings.
|
|
|
|
MODIFICATION DATES:
|
|
26-Feb-1990 [ralphw]
|
|
26-Mar-1994 [ralphw]
|
|
Ported to 32-bits
|
|
|
|
***************************************************************************/
|
|
|
|
PSTR CTable::TableMalloc(int cb)
|
|
{
|
|
/*
|
|
* Align allocation request so that all allocations fall on an
|
|
* alignment boundary (32 bits for Intel, 64 bits for MIPS).
|
|
*/
|
|
|
|
cb = (cb & (ALIGNMENT - 1)) ?
|
|
cb / ALIGNMENT * ALIGNMENT + ALIGNMENT : cb;
|
|
|
|
if (m_pFreed) {
|
|
|
|
// First look for an exact match
|
|
|
|
for (int i = 0; i < m_cFreedItems; i++) {
|
|
ASSERT_COMMENT(m_pFreed[i].cb, "This memory has been used again -- it shouldn't be in the array");
|
|
if (cb > m_pFreed[i].cb)
|
|
break;
|
|
if (cb == m_pFreed[i].cb)
|
|
goto GotAMatch;
|
|
}
|
|
|
|
// Couldn't find an exact match, so find the first one that fits
|
|
|
|
for (i--; i >= 0; i--) {
|
|
ASSERT_COMMENT(m_pFreed[i].cb, "This memory has been used again -- it shouldn't be in the array");
|
|
|
|
if (cb < m_pFreed[i].cb) {
|
|
|
|
// If there's more then 32 bytes left, then suballoc
|
|
|
|
if (cb + 32 < m_pFreed[i].cb) {
|
|
PSTR psz = (PSTR) m_pFreed[i].pMem;
|
|
m_pFreed[i].pMem += cb;
|
|
m_pFreed[i].cb -= cb;
|
|
// Keep the sizes sorted
|
|
|
|
QSort(m_pFreed, m_cFreedItems, sizeof(TABLE_FREED_MEMORY),
|
|
CompareIntPointers);
|
|
return psz;
|
|
}
|
|
GotAMatch:
|
|
m_cFreedItems--;
|
|
PSTR psz = (PSTR) m_pFreed[i].pMem;
|
|
if (i < m_cFreedItems) {
|
|
MemMove(&m_pFreed[i], &m_pFreed[i + 1],
|
|
sizeof(TABLE_FREED_MEMORY) * (m_cFreedItems - i));
|
|
#ifdef _DEBUG
|
|
m_pFreed[m_cFreedItems].cb = 0;
|
|
#endif
|
|
}
|
|
#ifdef _DEBUG
|
|
else
|
|
m_pFreed[i].cb = 0;
|
|
#endif
|
|
return psz;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (CurOffset + cb >= cbStrings) {
|
|
int cbNew = cbStrings + TABLE_ALLOC_SIZE;
|
|
while (cbNew < CurOffset + cb)
|
|
cbNew += TABLE_ALLOC_SIZE;
|
|
|
|
// We rely on VirtualAlloc to fail if cbStrings exceeds cbMaxBase
|
|
|
|
if(cbNew > cbMaxBase)
|
|
{
|
|
ASSERT_COMMENT(FALSE, "Table memory overflow");
|
|
return NULL;
|
|
}
|
|
|
|
if (!VirtualAlloc(pszBase + cbStrings, cbNew - cbStrings,
|
|
MEM_COMMIT, PAGE_READWRITE)) {
|
|
ASSERT_COMMENT(FALSE, "Table memory overflow");
|
|
OOM();
|
|
return NULL;
|
|
}
|
|
#ifdef _DEBUG
|
|
g_cbTableAllocated += (cbNew - cbStrings);
|
|
#endif
|
|
cbStrings = cbNew;
|
|
}
|
|
|
|
int offset = CurOffset;
|
|
CurOffset += cb;
|
|
return pszBase + offset;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: SetPosition
|
|
|
|
PURPOSE: Sets the position for reading from the table
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
26-Feb-1990 [ralphw]
|
|
16-Oct-1990 [ralphw]
|
|
If table position is to large, set to the end of the table,
|
|
not the last line.
|
|
|
|
***************************************************************************/
|
|
|
|
BOOL FASTCALL CTable::SetPosition(int pos)
|
|
{
|
|
if (pos >= endpos)
|
|
pos = endpos;
|
|
|
|
curpos = ((pos == 0) ? 1 : pos);
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CTable::IsHashInTable
|
|
|
|
PURPOSE: Find out if the hash number exists in the table
|
|
|
|
PARAMETERS:
|
|
hash
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
Assumes case-insensitive hash number, and no collisions
|
|
|
|
MODIFICATION DATES:
|
|
05-Feb-1997 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int CTable::IsHashInTable(HASH hash)
|
|
{
|
|
for (int i = 1; i < endpos; i++) {
|
|
if (hash == *(HASH *) ppszTable[i])
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: IsStringInTable
|
|
|
|
PURPOSE: Determine if the string is already in the table
|
|
|
|
RETURNS: position if the string is already in the table,
|
|
0 if the string isn't found
|
|
|
|
COMMENTS:
|
|
The comparison is case-insensitive, and is considerably
|
|
slower then IsCSStringInTable
|
|
|
|
if lcid has been set, NLS string comparisons are used
|
|
|
|
MODIFICATION DATES:
|
|
02-Mar-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int CTable::IsStringInTable(PCSTR pszString) const
|
|
{
|
|
int i;
|
|
|
|
if (!lcid) {
|
|
|
|
/*
|
|
* Skip over as many strings as we can by just checking the first
|
|
* letter. This avoids the overhead of the _strcmpi() function call.
|
|
*/
|
|
|
|
char chLower = ToLower(*pszString);
|
|
char chUpper = ToUpper(*pszString);
|
|
|
|
for (i = 1; i < endpos; i++) {
|
|
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper)
|
|
&& lstrcmpi(ppszTable[i], pszString) == 0)
|
|
return i;
|
|
}
|
|
}
|
|
else { // Use NLS string comparison
|
|
for (i = 1; i < endpos; i++) {
|
|
if (CompareStringA(lcid, fsCompareI | NORM_IGNORECASE,
|
|
pszString, -1, ppszTable[i], -1) == 1)
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CTable::IsCSStringInTable
|
|
|
|
PURPOSE: Case-sensitive search for a string in a table
|
|
|
|
PARAMETERS:
|
|
pszString
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
12-Jun-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int CTable::IsCSStringInTable(PCSTR pszString) const
|
|
{
|
|
char szBuf[sizeof(DWORD) + 1];
|
|
DWORD cmp;
|
|
|
|
if (strlen(pszString) < sizeof(DWORD)) {
|
|
ZeroMemory(szBuf, sizeof(DWORD) + 1);
|
|
strcpy(szBuf, pszString);
|
|
cmp = *(DWORD*) szBuf;
|
|
}
|
|
else
|
|
cmp = *(DWORD*) pszString;
|
|
|
|
for (int i = 1; i < endpos; i++) {
|
|
if (cmp == *(DWORD*) ppszTable[i] &&
|
|
strcmp(ppszTable[i], pszString) == 0)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
int CTable::IsStringInTable(HASH hash, PCSTR pszString) const
|
|
{
|
|
for (int i = 1; i < endpos; i++) {
|
|
if (hash == *(HASH *) ppszTable[i] &&
|
|
// this avoids the very rare hash collision
|
|
strcmp(ppszTable[i] + sizeof(HASH), pszString) == 0)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: AddDblToTable
|
|
|
|
PURPOSE: Add two strings to the table
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
This function checks to see if the second string has already been
|
|
added, and if so, it merely sets the pointer to the original string,
|
|
rather then allocating memory for a new copy of the string.
|
|
|
|
MODIFICATION DATES:
|
|
08-Mar-1991 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int CTable::AddString(PCSTR pszStr1, PCSTR pszStr2)
|
|
{
|
|
int ui;
|
|
|
|
AddString(pszStr1);
|
|
if ((ui = IsSecondaryStringInTable(pszStr2)) != 0) {
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
ppszTable[endpos++] = ppszTable[ui];
|
|
return endpos - 1;
|
|
}
|
|
else {
|
|
return AddString(pszStr2);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: IsPrimaryStringInTable
|
|
|
|
PURPOSE:
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
03-Apr-1991 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int CTable::IsPrimaryStringInTable(PCSTR pszString) const
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* Skip over as many strings as we can by just checking the first
|
|
* letter. This avoids the overhead of the _strcmpi() function call.
|
|
* Since the strings aren't necessarily alphabetized, we must trudge
|
|
* through the entire table using the _strcmpi() as soon as the first
|
|
* character matches.
|
|
*/
|
|
|
|
char chLower = ToLower(*pszString);
|
|
char chUpper = ToUpper(*pszString);
|
|
for (i = 1; i < endpos; i += 2) {
|
|
if (*ppszTable[i] == chLower || *ppszTable[i] == chUpper)
|
|
break;
|
|
}
|
|
for (; i < endpos; i += 2) {
|
|
if (lstrcmpi(ppszTable[i], pszString) == 0)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: IsSecondaryStringInTable
|
|
|
|
PURPOSE:
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
03-Apr-1991 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int CTable::IsSecondaryStringInTable(PCSTR pszString) const
|
|
{
|
|
int i;
|
|
|
|
/*
|
|
* Skip over as many strings as we can by just checking the first
|
|
* letter. This avoids the overhead of the _strcmpi() function call.
|
|
* Since the strings aren't necessarily alphabetized, we must trudge
|
|
* through the entire table using the _strcmpi() as soon as the first
|
|
* character matches.
|
|
*/
|
|
|
|
char chLower = ToLower(*pszString);
|
|
char chUpper = ToUpper(*pszString);
|
|
for (i = 2; i < endpos; i += 2) {
|
|
if (*ppszTable[i] == chLower || *ppszTable[i] == chUpper)
|
|
break;
|
|
}
|
|
for (; i < endpos; i += 2) {
|
|
if (lstrcmpi(ppszTable[i], pszString) == 0)
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: SortTable
|
|
|
|
PURPOSE: Sort the current buffer
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
01-Jan-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::SortTable(int sortoffset)
|
|
{
|
|
if (endpos < 3) // don't sort one entry
|
|
return;
|
|
m_sortoffset = sortoffset;
|
|
|
|
if (lcid) {
|
|
fsSortFlags = fsCompare;
|
|
doLcidSort(1, (int) endpos - 1);
|
|
}
|
|
else
|
|
doSort(1, (int) endpos - 1);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: doSort
|
|
|
|
PURPOSE:
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
Use QSORT algorithm
|
|
|
|
MODIFICATION DATES:
|
|
27-Mar-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::doSort(int left, int right)
|
|
{
|
|
int last;
|
|
|
|
if (left >= right) // return if nothing to sort
|
|
return;
|
|
|
|
// REVIEW: should be a flag before trying this -- we may already know
|
|
// that they won't be in order.
|
|
|
|
// Only sort if there are elements out of order.
|
|
|
|
j = right - 1;
|
|
while (j >= left) {
|
|
|
|
// REVIEW: strcmp is NOT case-sensitive!!!
|
|
|
|
if (strcmp(ppszTable[j] + m_sortoffset,
|
|
ppszTable[j + 1] + m_sortoffset) > 0)
|
|
break;
|
|
else
|
|
j--;
|
|
}
|
|
if (j < left)
|
|
return;
|
|
|
|
sTmp = (left + right) / 2;
|
|
pszTmp = ppszTable[left];
|
|
ppszTable[left] = ppszTable[sTmp];
|
|
ppszTable[sTmp] = pszTmp;
|
|
|
|
last = left;
|
|
for (j = left + 1; j <= right; j++) {
|
|
if (strcmp(ppszTable[j] + m_sortoffset,
|
|
ppszTable[left] + m_sortoffset) < 0) {
|
|
sTmp = ++last;
|
|
pszTmp = ppszTable[sTmp];
|
|
ppszTable[sTmp] = ppszTable[j];
|
|
ppszTable[j] = pszTmp;
|
|
}
|
|
}
|
|
pszTmp = ppszTable[left];
|
|
ppszTable[left] = ppszTable[last];
|
|
ppszTable[last] = pszTmp;
|
|
|
|
/*
|
|
* REVIEW: we need to add some sort of stack depth check to prevent
|
|
* overflow of the stack.
|
|
*/
|
|
|
|
if (left < last - 1)
|
|
doSort(left, last - 1);
|
|
if (last + 1 < right)
|
|
doSort(last + 1, right);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CTable::doLcidSort
|
|
|
|
PURPOSE: Sort using CompareStringA
|
|
|
|
PARAMETERS:
|
|
left
|
|
right
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
03-Jun-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::doLcidSort(int left, int right)
|
|
{
|
|
int last;
|
|
#ifdef _DEBUG
|
|
static BOOL fWarned = FALSE;
|
|
if (!fWarned) {
|
|
char szBuf[256];
|
|
wsprintf(szBuf, "*** fsSortFlags == %u", fsSortFlags);
|
|
DBWIN(szBuf);
|
|
fWarned = TRUE;
|
|
}
|
|
#endif
|
|
|
|
if (left >= right) // return if nothing to sort
|
|
return;
|
|
|
|
// REVIEW: should be a flag before trying this -- we may already know
|
|
// that they won't be in order.
|
|
|
|
// Only sort if there are elements out of order.
|
|
|
|
j = right - 1;
|
|
while (j >= left) {
|
|
if (CompareStringA(lcid, fsSortFlags, ppszTable[j] + m_sortoffset, -1,
|
|
ppszTable[j + 1] + m_sortoffset, -1) > 2)
|
|
break;
|
|
else
|
|
j--;
|
|
}
|
|
if (j < left)
|
|
return;
|
|
|
|
sTmp = (left + right) / 2;
|
|
pszTmp = ppszTable[left];
|
|
ppszTable[left] = ppszTable[sTmp];
|
|
ppszTable[sTmp] = pszTmp;
|
|
|
|
last = left;
|
|
for (j = left + 1; j <= right; j++) {
|
|
if (CompareStringA(lcid, fsSortFlags, ppszTable[j] + m_sortoffset, -1,
|
|
ppszTable[left] + m_sortoffset, -1) < 2) {
|
|
sTmp = ++last;
|
|
pszTmp = ppszTable[sTmp];
|
|
ppszTable[sTmp] = ppszTable[j];
|
|
ppszTable[j] = pszTmp;
|
|
}
|
|
}
|
|
pszTmp = ppszTable[left];
|
|
ppszTable[left] = ppszTable[last];
|
|
ppszTable[last] = pszTmp;
|
|
|
|
if (left < last - 1)
|
|
doLcidSort(left, last - 1);
|
|
if (last + 1 < right)
|
|
doLcidSort(last + 1, right);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CTable::InitializeTable
|
|
|
|
PURPOSE: Initializes the table
|
|
|
|
PARAMETERS:
|
|
uInitialSize
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
Called by constructor and Empty()
|
|
|
|
|
|
MODIFICATION DATES:
|
|
23-Feb-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::InitializeTable(void)
|
|
{
|
|
// Allocate memory for the strings
|
|
|
|
pszBase = (PSTR) VirtualAlloc(NULL, cbMaxBase, MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
if (!pszBase) {
|
|
ASSERT_COMMENT(FALSE, "Out of virtual address space");
|
|
OOM();
|
|
return;
|
|
}
|
|
if (!VirtualAlloc(pszBase, cbStrings = TABLE_ALLOC_SIZE, MEM_COMMIT,
|
|
PAGE_READWRITE))
|
|
OOM();
|
|
|
|
// Allocate memory for the string pointers
|
|
|
|
ppszTable = (PSTR *) VirtualAlloc(NULL, cbMaxTable, MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
if (!ppszTable) {
|
|
OOM();
|
|
return;
|
|
}
|
|
if (!VirtualAlloc(ppszTable, cbPointers = TABLE_ALLOC_SIZE, MEM_COMMIT,
|
|
PAGE_READWRITE))
|
|
OOM();
|
|
|
|
#ifdef _DEBUG
|
|
g_cbTableAllocated += (cbStrings + cbPointers);
|
|
g_cbTableReserved += (cbMaxBase + cbMaxTable);
|
|
#endif
|
|
|
|
curpos = 1; // set to one so that sorting works
|
|
endpos = 1;
|
|
maxpos = cbPointers / sizeof(PSTR);
|
|
CurOffset = 0;
|
|
lcid = 0;
|
|
m_pFreed = NULL;
|
|
}
|
|
|
|
void FASTCALL CTable::SetSorting(LCID lcid, DWORD fsCompareI, DWORD fsCompare)
|
|
{
|
|
this->lcid = lcid;
|
|
this->fsCompareI = fsCompareI;
|
|
this->fsCompare = fsCompare;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CTable::AddIndexHitString
|
|
|
|
PURPOSE: Add an index, a hit number, and a string
|
|
|
|
PARAMETERS:
|
|
index
|
|
hit
|
|
pszString
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
27-Oct-1993 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::AddIndexHitString(UINT index, UINT hit, PCSTR pszString)
|
|
{
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if ((ppszTable[endpos] =
|
|
TableMalloc((int)strlen(pszString) + 1 + (int)sizeof(UINT) * 2)) == NULL)
|
|
return;
|
|
|
|
*(UINT*) ppszTable[endpos] = index;
|
|
*(UINT*) (ppszTable[endpos] + sizeof(UINT)) = hit;
|
|
|
|
strcpy(ppszTable[endpos++] + sizeof(UINT) * 2, pszString);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: SortTablei
|
|
|
|
PURPOSE: Case-insensitive sort
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
01-Jan-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::SortTablei(int sortoffset)
|
|
{
|
|
if (endpos < 3) // don't sort one entry
|
|
return;
|
|
m_sortoffset = sortoffset;
|
|
if (!lcid)
|
|
lcid = g_lcidSystem;
|
|
|
|
ASSERT(lcid);
|
|
fsSortFlags = fsCompareI | NORM_IGNORECASE;
|
|
doLcidSort(1, endpos - 1);
|
|
|
|
// REVIEW: what is this for?
|
|
#if 0
|
|
int pos;
|
|
|
|
for (pos = 1; pos < endpos - 2; pos++) {
|
|
if (strlen(ppszTable[pos]) ==
|
|
strlen(ppszTable[pos + 1]) &&
|
|
CompareStringA(lcid, fsCompare, ppszTable[pos] + m_sortoffset, -1,
|
|
ppszTable[pos + 1] + m_sortoffset, -1) == 3) {
|
|
PSTR pszTmp = ppszTable[pos];
|
|
ppszTable[pos] = ppszTable[pos + 1];
|
|
ppszTable[pos + 1] = pszTmp;
|
|
if (pos > 2)
|
|
pos -= 2;
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
UINT CTable::GetPosFromPtr(PCSTR psz)
|
|
{
|
|
int pos = 1;
|
|
do {
|
|
if (psz == ppszTable[pos])
|
|
return pos;
|
|
} while (++pos < endpos);
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ReplaceString
|
|
|
|
PURPOSE: Replaces the current string at the specified position with
|
|
a new string
|
|
|
|
RETURNS: TRUE if the function is successful, FALSE if an error occurred.
|
|
An error occurs if the specified position is beyond the end
|
|
of the table.
|
|
|
|
|
|
COMMENTS:
|
|
If the new string is the same size or smaller then the original
|
|
string, then it is copied over the original string. Otherwise,
|
|
a new string buffer is allocated, and the pointer for the specified
|
|
position is changed to point to the new buffer. Note that the old
|
|
string's memory is not freed -- it simply becomes unavailable.
|
|
|
|
MODIFICATION DATES:
|
|
08-Oct-1991 [ralphw]
|
|
Updated to transfer associated line number
|
|
|
|
***************************************************************************/
|
|
|
|
BOOL CTable::ReplaceString(const char * pszNewString, int pos)
|
|
{
|
|
if (pos > endpos)
|
|
return FALSE;
|
|
|
|
if (pos == 0)
|
|
pos = 1;
|
|
|
|
/*
|
|
* If the new string is larger then the old string, then allocate a
|
|
* new buffer for it.
|
|
*/
|
|
|
|
if (strlen(pszNewString) > (size_t) strlen(ppszTable[pos])) {
|
|
if ((ppszTable[pos] =
|
|
TableMalloc((int)strlen(pszNewString) + 1)) == NULL)
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(ppszTable[pos], pszNewString);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void CTable::FreeMemory(PCSTR psz, int cb)
|
|
{
|
|
if (cb == -1)
|
|
cb = (int)strlen(psz) + 1;
|
|
/*
|
|
* Change the size of cb to match what would have been originally
|
|
* allocated. See TableMalloc().
|
|
*/
|
|
|
|
cb = (cb & (ALIGNMENT - 1)) ?
|
|
cb / ALIGNMENT * ALIGNMENT + ALIGNMENT : cb;
|
|
|
|
if (!m_pFreed) {
|
|
m_cFreedMax = 5;
|
|
m_cFreedItems = 0;
|
|
m_pFreed = (TABLE_FREED_MEMORY*) lcMalloc(m_cFreedMax * sizeof(TABLE_FREED_MEMORY));
|
|
}
|
|
else if (m_cFreedItems >= m_cFreedMax) {
|
|
m_cFreedMax += 5;
|
|
m_pFreed = (TABLE_FREED_MEMORY*) lcReAlloc(m_pFreed, m_cFreedMax * sizeof(TABLE_FREED_MEMORY));
|
|
}
|
|
m_pFreed[m_cFreedItems].cb = cb;
|
|
m_pFreed[m_cFreedItems].pMem = psz;
|
|
m_cFreedItems++;
|
|
|
|
// Keep the sizes sorted
|
|
|
|
QSort(m_pFreed, m_cFreedItems, sizeof(TABLE_FREED_MEMORY), CompareIntPointers);
|
|
}
|
|
|
|
|
|
//////////////////////////////////////////////////////////////////////////
|
|
// CWTable
|
|
//////////////////////////////////////////////////////////////////////////
|
|
|
|
void CWTable::_CWTable( UINT CodePage )
|
|
{
|
|
m_CodePage = CodePage;
|
|
}
|
|
|
|
CWTable::CWTable( UINT CodePage )
|
|
{
|
|
_CWTable( CodePage );
|
|
}
|
|
|
|
CWTable::CWTable(int cbStrings, UINT CodePage ) : CTable( cbStrings )
|
|
{
|
|
_CWTable( CodePage );
|
|
}
|
|
|
|
CWTable::~CWTable()
|
|
{
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: GetStringW
|
|
|
|
PURPOSE: Gets a Unicode version fo the stored string.
|
|
|
|
RETURNS: S_OK if the function is successful, S_FALSE otherwise.
|
|
|
|
COMMENTS: Stored string must be MBCS.
|
|
|
|
MODIFICATION DATES:
|
|
08-Sep-1998 [paulti]
|
|
|
|
***************************************************************************/
|
|
|
|
HRESULT CWTable::GetStringW( int pos, WCHAR* pwsz, int cch )
|
|
{
|
|
CHAR* psz = CTable::GetPointer( pos );
|
|
|
|
int iReturn = MultiByteToWideChar( m_CodePage, 0, psz, (int)strlen(psz), pwsz, cch );
|
|
|
|
if( iReturn == 0 )
|
|
return S_FALSE;
|
|
|
|
pwsz[iReturn] = 0;
|
|
|
|
return S_OK;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: GetHashStringW
|
|
|
|
PURPOSE: Gets a Unicode versions of the string when the both a Hash
|
|
and a string pair are stored.
|
|
|
|
RETURNS: S_OK if the function is successful, S_FALSE otherwise.
|
|
|
|
COMMENTS: Stored string must be MBCS.
|
|
|
|
MODIFICATION DATES:
|
|
08-Sep-1998 [paulti]
|
|
|
|
***************************************************************************/
|
|
|
|
HRESULT CWTable::GetHashStringW( int pos, WCHAR* pwsz, int cch )
|
|
{
|
|
CHAR* psz = CTable::GetHashStringPointer( pos );
|
|
|
|
int iReturn = MultiByteToWideChar( m_CodePage, 0, psz, (int)strlen(psz), pwsz, cch );
|
|
|
|
if( iReturn == 0 )
|
|
return S_FALSE;
|
|
|
|
pwsz[iReturn] = 0;
|
|
|
|
return S_OK;
|
|
}
|