1234 lines
27 KiB
C++
1234 lines
27 KiB
C++
/************************************************************************
|
|
* *
|
|
* CTABLE.CPP *
|
|
* *
|
|
* Copyright (C) Microsoft Corporation 1993-1994 *
|
|
* All Rights reserved. *
|
|
* *
|
|
************************************************************************/
|
|
|
|
#include "stdafx.h"
|
|
|
|
#ifndef _CTABLE_INCLUDED
|
|
#include "ctable.h"
|
|
#endif
|
|
|
|
const int TABLE_ALLOC_SIZE = 4096; // allocate in page increments
|
|
const int MAX_POINTERS = (2048 * 1024); // 2 meg, 524,288 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
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CreateTable
|
|
|
|
PURPOSE: Creates a table with the specified initial size
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
11-Dec-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
CTable::CTable()
|
|
{
|
|
InitializeTable();
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
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]
|
|
|
|
***************************************************************************/
|
|
|
|
const CTable& CTable::operator =(const CTable& tblSrc)
|
|
{
|
|
Empty();
|
|
return (*this += tblSrc);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: +=
|
|
|
|
PURPOSE: Appends the contents of a table to this 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]
|
|
|
|
***************************************************************************/
|
|
|
|
const CTable& CTable::operator +=(const CTable& tblSrc)
|
|
{
|
|
int srcpos = 1;
|
|
while (srcpos < tblSrc.endpos) {
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if ((ppszTable[endpos] =
|
|
TableMalloc(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(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);
|
|
}
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
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 STDCALL CTable::Empty(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);
|
|
}
|
|
|
|
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 STDCALL 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 STDCALL CTable::GetString(PSTR pszDst, int pos)
|
|
{
|
|
*pszDst = 0; // clear the line no matter what happens
|
|
|
|
if (pos >= endpos || pos == 0)
|
|
return FALSE;
|
|
strcpy(pszDst, (PCSTR) ppszTable[pos]);
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL STDCALL 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;
|
|
}
|
|
|
|
BOOL FASTCALL CTable::GetInt(int* plVal)
|
|
{
|
|
if (curpos >= endpos)
|
|
return FALSE;
|
|
*plVal = *(int *) ppszTable[curpos++];
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CTable::RemoveString
|
|
|
|
PURPOSE: Removes the string from the table
|
|
|
|
PARAMETERS:
|
|
pos
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
Note that this does NOT free the memory used by the string, it
|
|
simply removes the pointer to the allocated memory. The memory
|
|
will be freed when the table is freed.
|
|
|
|
REVIEW: we could keep a free list of freed memory that would include
|
|
strings that were removed, and strings that were replaced where
|
|
the replaced string ended up being larger then the original.
|
|
|
|
MODIFICATION DATES:
|
|
21-Feb-1994 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void STDCALL CTable::RemoveString(int pos)
|
|
{
|
|
if (pos > endpos)
|
|
return;
|
|
if (pos < endpos)
|
|
memcpy(&ppszTable[pos], &ppszTable[pos + 1],
|
|
sizeof(PSTR) * (endpos - pos));
|
|
endpos--;
|
|
}
|
|
|
|
BOOL STDCALL CTable::InsertString(const char* pszString, int pos)
|
|
{
|
|
if (pos > endpos)
|
|
return FALSE;
|
|
if (pos < 1)
|
|
pos = 1;
|
|
|
|
if (endpos + 1 >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
// nake a hole for the new entry
|
|
|
|
memmove(&ppszTable[pos + 1], &ppszTable[pos],
|
|
sizeof(PSTR) * (endpos - pos));
|
|
endpos++;
|
|
|
|
if ((ppszTable[pos] =
|
|
TableMalloc(strlen(pszString) + 1)) == NULL)
|
|
return FALSE; // this will be really, really bad...
|
|
|
|
strcpy(ppszTable[pos], pszString);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: AddString
|
|
|
|
PURPOSE: Add a string to a table
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
01-Jan-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int STDCALL CTable::AddString(const char * pszString)
|
|
{
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if ((ppszTable[endpos] =
|
|
TableMalloc(strlen(pszString) + 1)) == NULL)
|
|
return 0;
|
|
|
|
strcpy(ppszTable[endpos], pszString);
|
|
|
|
return endpos++;
|
|
}
|
|
|
|
int STDCALL CTable::AddData(int cb, const void* pdata)
|
|
{
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if ((ppszTable[endpos] = TableMalloc(cb)) == NULL)
|
|
return 0;
|
|
|
|
memcpy(ppszTable[endpos], pdata, cb);
|
|
|
|
return endpos++;
|
|
}
|
|
|
|
int STDCALL CTable::AddIntAndString(int lVal, PCSTR pszString)
|
|
{
|
|
if (endpos >= maxpos)
|
|
IncreaseTableBuffer();
|
|
|
|
if ((ppszTable[endpos] =
|
|
TableMalloc(strlen(pszString) + 1 + 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 STDCALL CTable::IncreaseTableBuffer(void)
|
|
{
|
|
if (!VirtualAlloc((PBYTE) ppszTable + cbPointers, TABLE_ALLOC_SIZE,
|
|
MEM_COMMIT, PAGE_READWRITE)) {
|
|
OOM();
|
|
return;
|
|
}
|
|
cbPointers += TABLE_ALLOC_SIZE;
|
|
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 STDCALL 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 (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 MAX_STRINGS
|
|
|
|
if (!VirtualAlloc(pszBase + cbStrings, cbNew - cbStrings,
|
|
MEM_COMMIT, PAGE_READWRITE)) {
|
|
OOM();
|
|
return NULL;
|
|
}
|
|
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: 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
|
|
|
|
MODIFICATION DATES:
|
|
02-Mar-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int STDCALL CTable::IsStringInTable(PCSTR pszString)
|
|
{
|
|
int i;
|
|
size_t cbString = strlen(pszString);
|
|
char chLower;
|
|
char chUpper;
|
|
|
|
if (!lcid) {
|
|
|
|
/*
|
|
* Skip over as many strings as we can by just checking the first
|
|
* letter. This avoids the overhead of the _stricmp() function call.
|
|
*/
|
|
|
|
chLower = tolower(*pszString);
|
|
chUpper = toupper(*pszString);
|
|
|
|
for (i = 1; i < endpos; i++) {
|
|
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
|
|
strlen(ppszTable[i]) == cbString &&
|
|
_stricmp(ppszTable[i], pszString) == 0)
|
|
return i;
|
|
}
|
|
}
|
|
else { // Use NLS string comparison
|
|
char szBuf[2];
|
|
|
|
LCMapString(lcid, LCMAP_LOWERCASE, pszString, 1, szBuf, 1);
|
|
chLower = szBuf[0];
|
|
LCMapString(lcid, LCMAP_UPPERCASE, pszString, 1, szBuf, 1);
|
|
chUpper = szBuf[0];
|
|
|
|
for (i = 1; i < endpos; i++) {
|
|
|
|
/*
|
|
* We assume that most of the time we will not find the
|
|
* string. We try to discover that the string doesn't
|
|
* match as quickly as possible. First we check the first
|
|
* letter, and if that doesn't match, try the next string.
|
|
* If the first letter matches, then confirm that the
|
|
* strings are the same length. Only if the first character
|
|
* matches and the strings have the same length do we
|
|
* call the time-comsuming CompareStringA function.
|
|
*/
|
|
|
|
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
|
|
strlen(ppszTable[i]) == cbString &&
|
|
CompareStringA(lcid, fsCompareI | NORM_IGNORECASE,
|
|
pszString, cbString, ppszTable[i], cbString) == 2)
|
|
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 STDCALL CTable::IsCSStringInTable(PCSTR pszString)
|
|
{
|
|
char szBuf[sizeof(DWORD) + 1];
|
|
DWORD cmp;
|
|
|
|
if (strlen(pszString) < sizeof(DWORD)) {
|
|
memset(szBuf, 0, 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;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: CTable::IsStringInTable
|
|
|
|
PURPOSE: Find case-sensitive string in the table
|
|
|
|
PARAMETERS:
|
|
hash
|
|
pszString
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
05-Feb-1995 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int STDCALL CTable::IsStringInTable(HASH hash, PCSTR pszString)
|
|
{
|
|
for (int i = 1; i < endpos; i++) {
|
|
if (hash == *(HASH *) ppszTable[i]) {
|
|
if (strcmp(ppszTable[i] + sizeof(HASH), pszString) == 0)
|
|
return i;
|
|
}
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
|
|
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-1995 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int STDCALL CTable::IsHashInTable(HASH hash)
|
|
{
|
|
for (int i = 1; i < endpos; i++) {
|
|
if (hash == *(HASH *) ppszTable[i])
|
|
return i;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: ReplaceString
|
|
|
|
PURPOSE: Replaces the current string at the specified position with
|
|
a new string
|
|
|
|
RETURNS: TRUE if the function is succesful, 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 STDCALL 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(strlen(pszNewString) + 1)) == NULL)
|
|
return FALSE;
|
|
}
|
|
|
|
strcpy(ppszTable[pos], pszNewString);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
BOOL STDCALL CTable::ReplaceString(const char * pszNewString, const char * pszOldString)
|
|
{
|
|
int pos = IsCSStringInTable(pszOldString);
|
|
if (pos)
|
|
return ReplaceString(pszNewString, pos);
|
|
else
|
|
return FALSE;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
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 STDCALL CTable::AddString(const char *pszStr1, const char *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 STDCALL CTable::IsPrimaryStringInTable(const char *pszString)
|
|
{
|
|
int i;
|
|
size_t cbString = strlen(pszString);
|
|
char chLower;
|
|
char chUpper;
|
|
|
|
if (!lcid) {
|
|
|
|
/*
|
|
* Skip over as many strings as we can by just checking the first
|
|
* letter. This avoids the overhead of the _stricmp() function call.
|
|
*/
|
|
|
|
chLower = tolower(*pszString);
|
|
chUpper = toupper(*pszString);
|
|
|
|
for (i = 1; i < endpos; i += 2) {
|
|
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
|
|
strlen(ppszTable[i]) == cbString &&
|
|
_stricmp(ppszTable[i], pszString) == 0)
|
|
return i;
|
|
}
|
|
}
|
|
else { // Use NLS string comparison
|
|
char szBuf[2];
|
|
|
|
LCMapString(lcid, LCMAP_LOWERCASE, pszString, 1, szBuf, 1);
|
|
chLower = szBuf[0];
|
|
LCMapString(lcid, LCMAP_UPPERCASE, pszString, 1, szBuf, 1);
|
|
chUpper = szBuf[0];
|
|
|
|
for (i = 1; i < endpos; i += 2) {
|
|
|
|
/*
|
|
* We assume that most of the time we will not find the
|
|
* string. We try to discover that the string doesn't
|
|
* match as quickly as possible. First we check the first
|
|
* letter, and if that doesn't match, try the next string.
|
|
* If the first letter matches, then confirm that the
|
|
* strings are the same length. Only if the first character
|
|
* matches and the strings have the same length do we
|
|
* call the time-comsuming CompareStringA function.
|
|
*/
|
|
|
|
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
|
|
strlen(ppszTable[i]) == cbString &&
|
|
CompareStringA(lcid, fsCompareI | NORM_IGNORECASE,
|
|
pszString, cbString, ppszTable[i], cbString) == 2)
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: IsSecondaryStringInTable
|
|
|
|
PURPOSE:
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
03-Apr-1991 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
int STDCALL CTable::IsSecondaryStringInTable(const char *pszString)
|
|
{
|
|
int i;
|
|
size_t cbString = strlen(pszString);
|
|
char chLower;
|
|
char chUpper;
|
|
|
|
if (!lcid) {
|
|
|
|
/*
|
|
* Skip over as many strings as we can by just checking the first
|
|
* letter. This avoids the overhead of the _stricmp() function call.
|
|
*/
|
|
|
|
chLower = tolower(*pszString);
|
|
chUpper = toupper(*pszString);
|
|
|
|
for (i = 2; i < endpos; i++) {
|
|
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
|
|
strlen(ppszTable[i]) == cbString &&
|
|
_stricmp(ppszTable[i], pszString) == 0)
|
|
return i;
|
|
}
|
|
}
|
|
else { // Use NLS string comparison
|
|
char szBuf[2];
|
|
|
|
LCMapString(lcid, LCMAP_LOWERCASE, pszString, 1, szBuf, 1);
|
|
chLower = szBuf[0];
|
|
LCMapString(lcid, LCMAP_UPPERCASE, pszString, 1, szBuf, 1);
|
|
chUpper = szBuf[0];
|
|
|
|
for (i = 2; i < endpos; i++) {
|
|
|
|
/*
|
|
* We assume that most of the time we will not find the
|
|
* string. We try to discover that the string doesn't
|
|
* match as quickly as possible. First we check the first
|
|
* letter, and if that doesn't match, try the next string.
|
|
* If the first letter matches, then confirm that the
|
|
* strings are the same length. Only if the first character
|
|
* matches and the strings have the same length do we
|
|
* call the time-comsuming CompareStringA function.
|
|
*/
|
|
|
|
if ((*ppszTable[i] == chLower || *ppszTable[i] == chUpper) &&
|
|
strlen(ppszTable[i]) == cbString &&
|
|
CompareStringA(lcid, fsCompareI | NORM_IGNORECASE,
|
|
pszString, cbString, ppszTable[i], cbString) == 2)
|
|
return i;
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: SortTable
|
|
|
|
PURPOSE: Sort the current buffer
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
01-Jan-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::SortTable(void)
|
|
{
|
|
if (endpos < 3) // don't sort one entry
|
|
return;
|
|
|
|
// We do this for speed and because JChicago build 122 gives incorrect
|
|
// results for CompareStringA
|
|
|
|
if (lcid && LANGIDFROMLCID(lcid) != 0x0409) {
|
|
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 STDCALL 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: lstrcmp is NOT case-sensitive!!!
|
|
|
|
if (strcmp(ppszTable[j] + SortColumn,
|
|
ppszTable[j + 1] + SortColumn) > 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] + SortColumn,
|
|
ppszTable[left] + SortColumn) < 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 STDCALL CTable::doLcidSort(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) {
|
|
if (CompareStringA(lcid, fsSortFlags, ppszTable[j] + SortColumn, -1,
|
|
ppszTable[j + 1] + SortColumn, -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] + SortColumn, -1,
|
|
ppszTable[left] + SortColumn, -1) < 2) {
|
|
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)
|
|
doLcidSort(left, last - 1);
|
|
if (last + 1 < right)
|
|
doLcidSort(last + 1, right);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: SortTablei
|
|
|
|
PURPOSE: Case-insensitive sort
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
|
|
MODIFICATION DATES:
|
|
01-Jan-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void CTable::SortTablei(void)
|
|
{
|
|
int pos;
|
|
|
|
if (endpos < 3) // don't sort one entry
|
|
return;
|
|
if (lcid) {
|
|
fsSortFlags = fsCompareI | NORM_IGNORECASE;
|
|
doLcidSort(1, endpos - 1);
|
|
for (pos = 1; pos < endpos - 2; pos++) {
|
|
if (strlen(ppszTable[pos] + SortColumn) ==
|
|
strlen(ppszTable[pos + 1] + SortColumn) &&
|
|
CompareStringA(lcid, fsCompare, ppszTable[pos] + SortColumn, -1,
|
|
ppszTable[pos + 1] + SortColumn, -1) == 3) {
|
|
PSTR pszTmp = ppszTable[pos];
|
|
ppszTable[pos] = ppszTable[pos + 1];
|
|
ppszTable[pos + 1] = pszTmp;
|
|
if (pos > 2)
|
|
pos -= 2;
|
|
}
|
|
}
|
|
}
|
|
else
|
|
doSorti(1, (int) endpos - 1);
|
|
}
|
|
|
|
/***************************************************************************
|
|
|
|
FUNCTION: doSort
|
|
|
|
PURPOSE:
|
|
|
|
RETURNS:
|
|
|
|
COMMENTS:
|
|
Use QSORT algorithm
|
|
|
|
MODIFICATION DATES:
|
|
27-Mar-1990 [ralphw]
|
|
|
|
***************************************************************************/
|
|
|
|
void STDCALL CTable::doSorti(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: lstrcmp is NOT case-sensitive!!!
|
|
|
|
if (_stricmp(ppszTable[j] + SortColumn,
|
|
ppszTable[j + 1] + SortColumn) > 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 (_stricmp(ppszTable[j] + SortColumn,
|
|
ppszTable[left] + SortColumn) < 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)
|
|
doSorti(left, last - 1);
|
|
if (last + 1 < right)
|
|
doSorti(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 STDCALL CTable::InitializeTable(void)
|
|
{
|
|
// Allocate memory for the strings
|
|
|
|
pszBase = (PSTR) VirtualAlloc(NULL, MAX_STRINGS, MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
if (!pszBase) {
|
|
OOM();
|
|
return;
|
|
}
|
|
if (!VirtualAlloc(pszBase, cbStrings = TABLE_ALLOC_SIZE, MEM_COMMIT,
|
|
PAGE_READWRITE))
|
|
OOM();
|
|
|
|
// Allocate memory for the string pointers
|
|
|
|
ppszTable = (PSTR *) VirtualAlloc(NULL, MAX_POINTERS, MEM_RESERVE,
|
|
PAGE_READWRITE);
|
|
if (!ppszTable) {
|
|
OOM();
|
|
return;
|
|
}
|
|
if (!VirtualAlloc(ppszTable, cbPointers = TABLE_ALLOC_SIZE, MEM_COMMIT,
|
|
PAGE_READWRITE))
|
|
OOM();
|
|
|
|
curpos = 1; // set to one so that sorting works
|
|
endpos = 1;
|
|
maxpos = cbPointers / sizeof(PSTR);
|
|
SortColumn = 0;
|
|
CurOffset = 0;
|
|
lcid = 0;
|
|
}
|
|
|
|
void FASTCALL CTable::SetSorting(LCID lcid, DWORD fsCompareI, DWORD fsCompare)
|
|
{
|
|
this->lcid = lcid;
|
|
this->fsCompareI = fsCompareI;
|
|
this->fsCompare = fsCompare;
|
|
}
|
|
|
|
void STDCALL CTable::RemoveDuplicateHashStrings(void)
|
|
{
|
|
for (int i = 1; i < endpos - 2; i++) {
|
|
if (*(HASH *) ppszTable[i] == *(HASH *) ppszTable[i + 1] &&
|
|
(strcmp(ppszTable[i] + sizeof(HASH),
|
|
ppszTable[i + 1] + sizeof(HASH)) == 0)) {
|
|
HASH hash = *(HASH *) ppszTable[i];
|
|
PSTR psz = ppszTable[i] + sizeof(HASH);
|
|
int j = i + 2;
|
|
while (j < endpos && hash == *(HASH *) ppszTable[j] &&
|
|
(strcmp(psz, ppszTable[j] + sizeof(HASH)) == 0))
|
|
j++;
|
|
j--;
|
|
memcpy(&ppszTable[i], &ppszTable[j],
|
|
sizeof(PSTR) * (endpos - (j - 1)));
|
|
endpos -= (j - i);
|
|
}
|
|
}
|
|
}
|