mirror of https://github.com/lianthony/NT4.0
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.
1188 lines
31 KiB
1188 lines
31 KiB
/*++
|
|
|
|
Copyright (c) 1993 Microsoft Corporation
|
|
|
|
Module Name:
|
|
|
|
strngtab.c
|
|
|
|
Abstract:
|
|
|
|
String table functions for Windows NT Setup API dll
|
|
|
|
A string table is a block of memory that contains a bunch of strings.
|
|
Hashing is used, and each hash table entry points to a linked list
|
|
of strings within the string table. Strings within each linked list
|
|
are sorted in ascending order. A node in the linked list consists of
|
|
a pointer to the next node, followed by the string itself. Nodes
|
|
are manually aligned to start on DWORD boundaries so we don't have to
|
|
resort to using unaligned pointers.
|
|
|
|
Author:
|
|
|
|
Ted Miller (tedm) 11-Jan-1995
|
|
|
|
Revision History:
|
|
|
|
--*/
|
|
|
|
#include "setupntp.h"
|
|
#pragma hdrstop
|
|
|
|
|
|
//
|
|
// Values used for the initial and growth size
|
|
// of the string table data area
|
|
//
|
|
// (We start out with 6K, but remember that this includes the hash buckets.
|
|
// After you subtract their part of the buffer, you're left with ~4K bytes.)
|
|
//
|
|
#define STRING_TABLE_INITIAL_SIZE 6144
|
|
#define STRING_TABLE_GROWTH_SIZE 2048
|
|
|
|
#include "pshpack1.h"
|
|
|
|
typedef struct _STRING_NODE {
|
|
//
|
|
// This is stored as an offset instead of a pointer
|
|
// because the table can move as it's built
|
|
// The offset is from the beginning of the table
|
|
//
|
|
LONG NextOffset;
|
|
//
|
|
// This field must be last
|
|
//
|
|
TCHAR String[ANYSIZE_ARRAY];
|
|
} STRING_NODE, *PSTRING_NODE;
|
|
|
|
#include "poppack.h"
|
|
|
|
|
|
typedef struct _STRING_TABLE {
|
|
PUCHAR Data; // First HASH_BUCKET_COUNT DWORDS are StringNodeOffset array.
|
|
DWORD DataSize;
|
|
DWORD BufferSize;
|
|
MYLOCK Lock;
|
|
} STRING_TABLE, *PSTRING_TABLE;
|
|
|
|
#define LockTable(table) BeginSynchronizedAccess(&((table)->Lock))
|
|
#define UnlockTable(table) EndSynchronizedAccess(&((table)->Lock))
|
|
|
|
|
|
VOID
|
|
pStringTableComputeHashValue(
|
|
IN PTSTR String,
|
|
OUT PDWORD StringLength,
|
|
IN DWORD Flags,
|
|
OUT PDWORD HashValue
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Compute a hash value for a given string.
|
|
|
|
The algorithm simply adds up the unicode values for each
|
|
character in the string and then takes the result mod the
|
|
number of hash buckets.
|
|
|
|
Arguments:
|
|
|
|
String - supplies the string for which a hash value is desired.
|
|
|
|
StringLength - receives the number of characters in the string,
|
|
not including the terminating nul.
|
|
|
|
Flags - supplies flags controlling how the hashing is to be done. May be
|
|
a combination of the following values (all other bits ignored):
|
|
|
|
STRTAB_BUFFER_WRITEABLE - The caller-supplied buffer may be written to during
|
|
the string look-up. Specifying this flag improves the
|
|
performance of this API for case-insensitive string
|
|
additions. This flag is ignored for case-sensitive
|
|
string additions.
|
|
|
|
STRTAB_ALREADY_LOWERCASE - The supplied string has already been converted to
|
|
all lower-case (e.g., by calling CharLower), and
|
|
therefore doesn't need to be lower-cased in the
|
|
hashing routine. If this flag is supplied, then
|
|
STRTAB_BUFFER_WRITEABLE is ignored, since modifying
|
|
the caller's buffer is not required.
|
|
|
|
HashValue - receives the hash value.
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD d, Length, Value;
|
|
|
|
if((Flags & (STRTAB_BUFFER_WRITEABLE | STRTAB_ALREADY_LOWERCASE)) == STRTAB_BUFFER_WRITEABLE) {
|
|
//
|
|
// Then the buffer is writeable, but isn't yet lower-case. Take care of that right now.
|
|
//
|
|
CharLower(String);
|
|
Flags |= STRTAB_ALREADY_LOWERCASE;
|
|
}
|
|
|
|
//
|
|
// Define a macro to ensure we don't get sign-extension when adding up character values.
|
|
//
|
|
#ifdef UNICODE
|
|
#define DWORD_FROM_TCHAR(x) ((DWORD)((WCHAR)(x)))
|
|
#else
|
|
#define DWORD_FROM_TCHAR(x) ((DWORD)((UCHAR)(x)))
|
|
#endif
|
|
|
|
if(Flags & STRTAB_ALREADY_LOWERCASE) {
|
|
for(Value=0,Length=lstrlen(String),d=0;
|
|
d < Length;
|
|
Value += DWORD_FROM_TCHAR(String[d++]));
|
|
} else {
|
|
//
|
|
// Make sure we don't get sign-extension on extended chars
|
|
// in String -- otherwise we get values like 0xffffffe4 passed
|
|
// to CharLower(), which thinks it's a pointer and faults.
|
|
//
|
|
for(Value=0,Length=lstrlen(String),d=0;
|
|
d < Length;
|
|
Value += DWORD_FROM_TCHAR(CharLower((PTSTR)(UCHAR)String[d++])));
|
|
}
|
|
|
|
*HashValue = Value % HASH_BUCKET_COUNT;
|
|
*StringLength = Length;
|
|
}
|
|
|
|
|
|
LONG
|
|
pStringTableLookUpString(
|
|
IN PVOID StringTable,
|
|
IN OUT PTSTR String,
|
|
OUT PDWORD StringLength,
|
|
OUT PDWORD HashValue, OPTIONAL
|
|
OUT PVOID *FindContext, OPTIONAL
|
|
IN DWORD Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Locates a string in the string table, if present.
|
|
If the string is not present, this routine may optionally tell its
|
|
caller where the search stopped. This is useful for maintaining a
|
|
sorted order for the strings.
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies handle to string table to be searched
|
|
for the string
|
|
|
|
String - supplies the string to be looked up
|
|
|
|
StringLength - receives number of characters in the string, not
|
|
including the terminating nul.
|
|
|
|
HashValue - Optionally, receives hash value for the string. If this
|
|
parameter is specified, then FindContext must be specified as well.
|
|
|
|
FinalNode - Optionally, receives the context at which the search was
|
|
terminated. If HashValue is not specified, then this parameter
|
|
is ignored.
|
|
|
|
(NOTE: This is actually a PSTRING_NODE pointer, that is used
|
|
during new string addition. Since this routine has wider exposure
|
|
than just internal string table usage, this parameter is made into
|
|
a PVOID, so no one else has to have access to string table-internal
|
|
structures.
|
|
|
|
On return, this variable receives a pointer to the string node of
|
|
the node where the search stopped. If the string was found, then
|
|
this is a pointer to the string's node. If the string was not found,
|
|
then this is a pointer to the last string node whose string is
|
|
'less' (based on lstrcmpi) than the string we're looking for.
|
|
Note that this value may be NULL.)
|
|
|
|
Flags - supplies flags controlling how the string is to be located. May be
|
|
a combination of the following values:
|
|
|
|
STRTAB_CASE_INSENSITIVE - Search for the string case-insensitively.
|
|
|
|
STRTAB_CASE_SENSITIVE - Search for the string case-sensitively. This flag
|
|
overrides the STRTAB_CASE_INSENSITIVE flag.
|
|
|
|
STRTAB_BUFFER_WRITEABLE - The caller-supplied buffer may be written to during
|
|
the string look-up. Specifying this flag improves the
|
|
performance of this API for case-insensitive string
|
|
additions. This flag is ignored for case-sensitive
|
|
string additions.
|
|
|
|
In addition to the above public flags, the following private flag is also
|
|
allowed:
|
|
|
|
STRTAB_ALREADY_LOWERCASE - The supplied string has already been converted to
|
|
all lower-case (e.g., by calling CharLower), and
|
|
therefore doesn't need to be lower-cased in the
|
|
hashing routine. If this flag is supplied, then
|
|
STRTAB_BUFFER_WRITEABLE is ignored, since modifying
|
|
the caller's buffer is not required.
|
|
|
|
Return Value:
|
|
|
|
The return value is a value that uniquely identifies the string
|
|
within the string table, namely the offset of the string node
|
|
within the string table.
|
|
|
|
If the string could not be found the value is -1.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTRING_NODE node,prev;
|
|
int i;
|
|
PSTRING_TABLE stringTable = StringTable;
|
|
DWORD hashValue;
|
|
PSTRING_NODE FinalNode;
|
|
LONG rc = -1;
|
|
|
|
//
|
|
// If this is a case-sensitive lookup, then we want to reset the STRTAB_BUFFER_WRITEABLE
|
|
// flag, if present, since otherwise the string will get replaced with its all-lowercase
|
|
// counterpart.
|
|
//
|
|
if(Flags & STRTAB_CASE_SENSITIVE) {
|
|
Flags &= ~STRTAB_BUFFER_WRITEABLE;
|
|
}
|
|
|
|
//
|
|
// Compute hash value
|
|
//
|
|
pStringTableComputeHashValue(String,StringLength,Flags,&hashValue);
|
|
|
|
if(((PLONG)(stringTable->Data))[hashValue] == -1) {
|
|
//
|
|
// The string table contains no strings at the computed hash value.
|
|
//
|
|
FinalNode = NULL;
|
|
goto clean0;
|
|
}
|
|
|
|
//
|
|
// We know there's at least one string in the table with the computed
|
|
// hash value, so go find it. There's no previous node yet.
|
|
//
|
|
node = (PSTRING_NODE)(stringTable->Data + ((PLONG)(stringTable->Data))[hashValue]);
|
|
prev = NULL;
|
|
|
|
//
|
|
// Go looking through the string nodes for that hash value,
|
|
// looking through the string.
|
|
//
|
|
while(1) {
|
|
|
|
i = (Flags & STRTAB_CASE_SENSITIVE)
|
|
? lstrcmp(String,node->String)
|
|
: lstrcmpi(String,node->String);
|
|
|
|
if(i == 0) {
|
|
FinalNode = node;
|
|
rc = (PUCHAR)node - stringTable->Data;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// If the string we are looking for is 'less' than the current
|
|
// string, we're done looking, because the strings are kept in
|
|
// a sorted order.
|
|
//
|
|
if(i < 0) {
|
|
FinalNode = prev;
|
|
break;
|
|
}
|
|
|
|
//
|
|
// The string we are looking for is 'greater' than the current string.
|
|
// Keep looking, unless we've reached the end of the table.
|
|
//
|
|
if(node->NextOffset == -1) {
|
|
FinalNode = node;
|
|
break;
|
|
} else {
|
|
prev = node;
|
|
node = (PSTRING_NODE)(stringTable->Data + node->NextOffset);
|
|
}
|
|
}
|
|
|
|
clean0:
|
|
|
|
if(HashValue) {
|
|
*HashValue = hashValue;
|
|
*FindContext = FinalNode;
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
StringTableLookUpString(
|
|
IN PVOID StringTable,
|
|
IN OUT PTSTR String,
|
|
IN DWORD Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Locates a string in the string table, if present.
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies handle to string table to be searched
|
|
for the string
|
|
|
|
String - supplies the string to be looked up. If STRTAB_BUFFER_WRITEABLE is
|
|
specified and a case-insensitive lookup is requested, then this buffer
|
|
will be all lower-case upon return.
|
|
|
|
Flags - supplies flags controlling how the string is to be located. May be
|
|
a combination of the following values:
|
|
|
|
STRTAB_CASE_INSENSITIVE - Search for the string case-insensitively.
|
|
|
|
STRTAB_CASE_SENSITIVE - Search for the string case-sensitively. This flag
|
|
overrides the STRTAB_CASE_INSENSITIVE flag.
|
|
|
|
STRTAB_BUFFER_WRITEABLE - The caller-supplied buffer may be written to during
|
|
the string look-up. Specifying this flag improves the
|
|
performance of this API for case-insensitive string
|
|
additions. This flag is ignored for case-sensitive
|
|
string additions.
|
|
|
|
In addition to the above public flags, the following private flag is also
|
|
allowed:
|
|
|
|
STRTAB_ALREADY_LOWERCASE - The supplied string has already been converted to
|
|
all lower-case (e.g., by calling CharLower), and
|
|
therefore doesn't need to be lower-cased in the
|
|
hashing routine. If this flag is supplied, then
|
|
STRTAB_BUFFER_WRITEABLE is ignored, since modifying
|
|
the caller's buffer is not required.
|
|
|
|
Return Value:
|
|
|
|
The return value is a value that uniquely identifies the string
|
|
within the string table.
|
|
|
|
If the string could not be found the value is -1.
|
|
|
|
--*/
|
|
|
|
{
|
|
DWORD StringLength, PrivateFlags, AlreadyLcFlag;
|
|
LONG rc;
|
|
|
|
if(!LockTable((PSTRING_TABLE)StringTable)) {
|
|
return(-1);
|
|
}
|
|
|
|
switch(Flags & ~STRTAB_ALREADY_LOWERCASE) { // ignore the 'already lower-case' flag here.
|
|
|
|
case STRTAB_CASE_INSENSITIVE :
|
|
case STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE :
|
|
PrivateFlags = Flags;
|
|
break;
|
|
|
|
default :
|
|
PrivateFlags = STRTAB_CASE_SENSITIVE | (Flags & STRTAB_ALREADY_LOWERCASE);
|
|
}
|
|
|
|
rc = pStringTableLookUpString(
|
|
StringTable,
|
|
String,
|
|
&StringLength,
|
|
NULL,
|
|
NULL,
|
|
PrivateFlags
|
|
);
|
|
|
|
UnlockTable((PSTRING_TABLE)StringTable);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
LONG
|
|
pStringTableAddString(
|
|
IN PVOID StringTable,
|
|
IN PTSTR String,
|
|
IN DWORD Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a string to the string table if the string is not already
|
|
in the string table. (Does not do locking!)
|
|
|
|
If the string is to be added case-insensitively, then it is
|
|
lower-cased, and added case-sensitively. Since lower-case characters
|
|
are 'less than' lower case ones (according to lstrcmp), this ensures that
|
|
a case-insensitive string will always appear in front of any of its
|
|
case-sensitive counterparts. This ensures that we always find the correct
|
|
string ID for things like section names.
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies handle to string table to be searched
|
|
for the string
|
|
|
|
String - supplies the string to be added
|
|
|
|
Flags - supplies flags controlling how the string is to be added, and
|
|
whether the caller-supplied buffer may be modified. May be a combination
|
|
of the following values:
|
|
|
|
STRTAB_CASE_INSENSITIVE - Add the string case-insensitively. The
|
|
specified string will be added to the string
|
|
table as all lower-case. This flag is overridden
|
|
if STRTAB_CASE_SENSITIVE is specified.
|
|
|
|
STRTAB_CASE_SENSITIVE - Add the string case-sensitively. This flag
|
|
overrides the STRTAB_CASE_INSENSITIVE flag.
|
|
|
|
STRTAB_BUFFER_WRITEABLE - The caller-supplied buffer may be written to during
|
|
the string-addition process. Specifying this flag
|
|
improves the performance of this API for case-
|
|
insensitive string additions. This flag is ignored
|
|
for case-sensitive string additions.
|
|
|
|
In addition to the above public flags, the following private flag is also
|
|
allowed:
|
|
|
|
STRTAB_ALREADY_LOWERCASE - The supplied string has already been converted to
|
|
all lower-case (e.g., by calling CharLower), and
|
|
therefore doesn't need to be lower-cased in the
|
|
hashing routine. If this flag is supplied, then
|
|
STRTAB_BUFFER_WRITEABLE is ignored, since modifying
|
|
the caller's buffer is not required.
|
|
|
|
Return Value:
|
|
|
|
The return value uniquely identifes the string within the string table.
|
|
It is -1 if the string was not in the string table but could not be added
|
|
(out of memory).
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG rc;
|
|
PSTRING_TABLE stringTable = StringTable;
|
|
DWORD StringLength;
|
|
DWORD HashValue;
|
|
PSTRING_NODE PreviousNode,NewNode;
|
|
DWORD SpaceRequired;
|
|
PTSTR TempString = String;
|
|
BOOL FreeTempString = FALSE;
|
|
|
|
if(!(Flags & STRTAB_CASE_SENSITIVE)) {
|
|
|
|
if(!(Flags & STRTAB_ALREADY_LOWERCASE)) {
|
|
|
|
if(Flags == STRTAB_CASE_INSENSITIVE) {
|
|
//
|
|
// Then the string is to be added case-insensitively, but the caller
|
|
// doesn't want us to write to their buffer. Allocate one of our own.
|
|
//
|
|
if(TempString = DuplicateString(String)) {
|
|
FreeTempString = TRUE;
|
|
} else {
|
|
//
|
|
// We couldn't allocate space for our duplicated string. Since we'll
|
|
// only consider exact matches (where the strings are all lower-case),
|
|
// we're stuck, since we can't lower-case the buffer in place.
|
|
//
|
|
return -1;
|
|
}
|
|
}
|
|
//
|
|
// Lower-case the buffer.
|
|
//
|
|
CharLower(TempString);
|
|
}
|
|
|
|
Flags = STRTAB_CASE_SENSITIVE | STRTAB_ALREADY_LOWERCASE;
|
|
}
|
|
|
|
try {
|
|
//
|
|
// The string might already be in there.
|
|
//
|
|
rc = pStringTableLookUpString(
|
|
StringTable,
|
|
TempString,
|
|
&StringLength,
|
|
&HashValue,
|
|
&PreviousNode,
|
|
Flags
|
|
);
|
|
|
|
if(rc != -1) {
|
|
return(rc);
|
|
}
|
|
|
|
//
|
|
// Figure out how much space is required to hold this entry.
|
|
// This is the size of a STRING_NODE plus the length of the string.
|
|
//
|
|
SpaceRequired = sizeof(STRING_NODE) + ((StringLength+1-ANYSIZE_ARRAY)*sizeof(TCHAR));
|
|
|
|
//
|
|
// Make sure things stay aligned within the table
|
|
//
|
|
if(SpaceRequired % sizeof(DWORD)) {
|
|
SpaceRequired += sizeof(DWORD) - (SpaceRequired % sizeof(DWORD));
|
|
}
|
|
|
|
//
|
|
// See if there is currently enough room to add the string to the table.
|
|
//
|
|
if(stringTable->DataSize + SpaceRequired > stringTable->BufferSize) {
|
|
|
|
//
|
|
// Grow the string table.
|
|
//
|
|
PVOID p;
|
|
p = MyRealloc(stringTable->Data,stringTable->BufferSize+STRING_TABLE_GROWTH_SIZE);
|
|
if(!p) {
|
|
return(-1);
|
|
}
|
|
|
|
//
|
|
// Adjust previous node pointer.
|
|
//
|
|
if(PreviousNode) {
|
|
PreviousNode = (PSTRING_NODE)((PUCHAR)p + ((PUCHAR)PreviousNode-(PUCHAR)stringTable->Data));
|
|
}
|
|
stringTable->Data = p;
|
|
stringTable->BufferSize += STRING_TABLE_GROWTH_SIZE;
|
|
}
|
|
|
|
//
|
|
// Stick the string in the string table buffer.
|
|
//
|
|
NewNode = (PSTRING_NODE)(stringTable->Data + stringTable->DataSize);
|
|
|
|
if(PreviousNode) {
|
|
NewNode->NextOffset = PreviousNode->NextOffset;
|
|
PreviousNode->NextOffset = (LONG)NewNode - (LONG)stringTable->Data;
|
|
} else {
|
|
NewNode->NextOffset = ((PLONG)(stringTable->Data))[HashValue];
|
|
((PLONG)(stringTable->Data))[HashValue] = (LONG)NewNode - (LONG)stringTable->Data;
|
|
}
|
|
|
|
lstrcpy(NewNode->String,TempString);
|
|
|
|
stringTable->DataSize += SpaceRequired;
|
|
|
|
rc = (LONG)NewNode - (LONG)stringTable->Data;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
rc = -1;
|
|
}
|
|
|
|
if(FreeTempString) {
|
|
MyFree(TempString);
|
|
}
|
|
|
|
return rc;
|
|
}
|
|
|
|
|
|
LONG
|
|
StringTableAddString(
|
|
IN PVOID StringTable,
|
|
IN PTSTR String,
|
|
IN DWORD Flags
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Adds a string to the string table if the string is not already
|
|
in the string table.
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies handle to string table to be searched
|
|
for the string
|
|
|
|
String - supplies the string to be added
|
|
|
|
Flags - supplies flags controlling how the string is to be added, and
|
|
whether the caller-supplied buffer may be modified. May be a combination
|
|
of the following values:
|
|
|
|
STRTAB_CASE_INSENSITIVE - Add the string case-insensitively. The
|
|
specified string will be added to the string
|
|
table as all lower-case. This flag is overridden
|
|
if STRTAB_CASE_SENSITIVE is specified.
|
|
|
|
STRTAB_CASE_SENSITIVE - Add the string case-sensitively. This flag
|
|
overrides the STRTAB_CASE_INSENSITIVE flag.
|
|
|
|
STRTAB_BUFFER_WRITEABLE - The caller-supplied buffer may be written to during
|
|
the string-addition process. Specifying this flag
|
|
improves the performance of this API for case-
|
|
insensitive string additions. This flag is ignored
|
|
for case-sensitive string additions.
|
|
|
|
In addition to the above public flags, the following private flag is also
|
|
allowed:
|
|
|
|
STRTAB_ALREADY_LOWERCASE - The supplied string has already been converted to
|
|
all lower-case (e.g., by calling CharLower), and
|
|
therefore doesn't need to be lower-cased in the
|
|
hashing routine. If this flag is supplied, then
|
|
STRTAB_BUFFER_WRITEABLE is ignored, since modifying
|
|
the caller's buffer is not required.
|
|
|
|
Return Value:
|
|
|
|
The return value uniquely identifes the string within the string table.
|
|
It is -1 if the string was not in the string table but could not be added
|
|
(out of memory).
|
|
|
|
--*/
|
|
|
|
{
|
|
LONG rc;
|
|
DWORD PrivateFlags;
|
|
|
|
if(!LockTable((PSTRING_TABLE)StringTable)) {
|
|
return(-1);
|
|
}
|
|
|
|
switch(Flags & ~STRTAB_ALREADY_LOWERCASE) {
|
|
|
|
case STRTAB_CASE_INSENSITIVE :
|
|
case STRTAB_CASE_INSENSITIVE | STRTAB_BUFFER_WRITEABLE :
|
|
PrivateFlags = Flags;
|
|
break;
|
|
|
|
default :
|
|
PrivateFlags = STRTAB_CASE_SENSITIVE | (Flags & STRTAB_ALREADY_LOWERCASE);
|
|
}
|
|
|
|
rc = pStringTableAddString(StringTable, String, PrivateFlags);
|
|
|
|
UnlockTable((PSTRING_TABLE)StringTable);
|
|
return(rc);
|
|
}
|
|
|
|
|
|
PTSTR
|
|
pStringTableStringFromId(
|
|
IN PVOID StringTable,
|
|
IN LONG StringId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a string ID returned when a string was added or looked up,
|
|
return a pointer to the actual string. (This is exactly the same
|
|
as StringTableStringFromId, except that it doesn't do locking.)
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies a pointer to the string table containing the
|
|
string to be retrieved.
|
|
|
|
StringId - supplies a string id returned from StringTableAddString
|
|
or StringTableLookUpString.
|
|
|
|
Return Value:
|
|
|
|
Pointer to string data. The caller must not write into or otherwise
|
|
alter the string.
|
|
|
|
--*/
|
|
|
|
{
|
|
return ((PSTRING_NODE)(((PSTRING_TABLE)StringTable)->Data + StringId))->String;
|
|
}
|
|
|
|
|
|
PTSTR
|
|
StringTableStringFromId(
|
|
IN PVOID StringTable,
|
|
IN LONG StringId
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Given a string ID returned when a string was added or looked up,
|
|
return a pointer to the actual string.
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies a pointer to the string table containing the
|
|
string to be retrieved.
|
|
|
|
StringId - supplies a string id returned from StringTableAddString
|
|
or StringTableLookUpString.
|
|
|
|
Return Value:
|
|
|
|
Pointer to string data. The caller must not write into or otherwise
|
|
alter the string.
|
|
|
|
--*/
|
|
|
|
{
|
|
PTSTR p;
|
|
|
|
if(!LockTable((PSTRING_TABLE)StringTable)) {
|
|
return(NULL);
|
|
}
|
|
|
|
p = ((PSTRING_NODE)(((PSTRING_TABLE)StringTable)->Data + StringId))->String;
|
|
|
|
UnlockTable((PSTRING_TABLE)StringTable);
|
|
|
|
return(p);
|
|
}
|
|
|
|
|
|
VOID
|
|
StringTableTrim(
|
|
IN PVOID StringTable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free any memory currently allocated for the string table
|
|
but not currently used.
|
|
|
|
This is useful after all strings have been added to a string table
|
|
because the string table grows by a fixed block size as it's being built.
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies a string table handle returned from
|
|
a call to StringTableInitialize().
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if(!LockTable((PSTRING_TABLE)StringTable)) {
|
|
return;
|
|
}
|
|
|
|
pStringTableTrim(StringTable);
|
|
|
|
UnlockTable((PSTRING_TABLE)StringTable);
|
|
}
|
|
|
|
|
|
VOID
|
|
pStringTableTrim(
|
|
IN PVOID StringTable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Free any memory currently allocated for the string table
|
|
but not currently used.
|
|
|
|
This is useful after all strings have been added to a string table
|
|
because the string table grows by a fixed block size as it's being built.
|
|
|
|
THIS ROUTINE DOES NOT DO LOCKING!
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies a string table handle returned from
|
|
a call to StringTableInitialize().
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTRING_TABLE stringTable = StringTable;
|
|
PVOID p;
|
|
|
|
//
|
|
// If the realloc failed the original block is not freed,
|
|
// so we don't really care.
|
|
//
|
|
|
|
if(p = MyRealloc(stringTable->Data, stringTable->DataSize)) {
|
|
stringTable->Data = p;
|
|
stringTable->BufferSize = stringTable->DataSize;
|
|
}
|
|
}
|
|
|
|
|
|
PVOID
|
|
StringTableInitialize(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create and initialize a string table.
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NULL if the string table could not be created (out of memory).
|
|
Otherwise returns an opaque value that references the string
|
|
table in other StringTable calls.
|
|
|
|
Remarks:
|
|
|
|
This routine returns a string table with synchronization locks
|
|
required by all public StringTable APIs. If the string table
|
|
is to be enclosed in a structure that has its own locking
|
|
(e.g., HINF, HDEVINFO), then the private version of this API
|
|
may be called, which will not create locks for the string table.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTRING_TABLE StringTable;
|
|
|
|
if(StringTable = (PSTRING_TABLE)pStringTableInitialize()) {
|
|
|
|
if(InitializeSynchronizedAccess(&StringTable->Lock)) {
|
|
return StringTable;
|
|
}
|
|
|
|
pStringTableDestroy(StringTable);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PVOID
|
|
pStringTableInitialize(
|
|
VOID
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create and initialize a string table.
|
|
THIS ROUTINE DOES NOT INITIALIZE STRING TABLE SYNCHRONIZATION LOCKS!
|
|
|
|
Arguments:
|
|
|
|
None.
|
|
|
|
Return Value:
|
|
|
|
NULL if the string table could not be created (out of memory).
|
|
Otherwise returns an opaque value that references the string
|
|
table in other StringTable calls.
|
|
|
|
Remarks:
|
|
|
|
The string table returned from this API may not be used as-is with the
|
|
public StringTable APIs--it must have its synchronization locks initialized
|
|
by the public form of this API.
|
|
|
|
--*/
|
|
|
|
{
|
|
UINT u;
|
|
PSTRING_TABLE stringTable;
|
|
|
|
//
|
|
// Allocate a string table
|
|
//
|
|
if(stringTable = MyMalloc(sizeof(STRING_TABLE))) {
|
|
|
|
ZeroMemory(stringTable,sizeof(STRING_TABLE));
|
|
|
|
//
|
|
// Allocate space for the string table data.
|
|
//
|
|
if(stringTable->Data = MyMalloc(STRING_TABLE_INITIAL_SIZE)) {
|
|
|
|
stringTable->BufferSize = STRING_TABLE_INITIAL_SIZE;
|
|
|
|
//
|
|
// Initialize the hash table
|
|
//
|
|
for(u=0; u<HASH_BUCKET_COUNT; u++) {
|
|
((PLONG)(stringTable->Data))[u] = -1;
|
|
}
|
|
|
|
//
|
|
// Set the DataSize to the size of the StringNodeOffset list, so
|
|
// we'll start adding new strings after it.
|
|
//
|
|
stringTable->DataSize = HASH_BUCKET_COUNT * sizeof(LONG);
|
|
|
|
return(stringTable);
|
|
}
|
|
|
|
MyFree(stringTable);
|
|
}
|
|
|
|
return(NULL);
|
|
}
|
|
|
|
|
|
VOID
|
|
StringTableDestroy(
|
|
IN PVOID StringTable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroy a string table, freeing all resources it uses.
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies a string table handle returned from
|
|
a call to StringTableInitialize().
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
if(!LockTable((PSTRING_TABLE)StringTable)) {
|
|
return;
|
|
}
|
|
|
|
DestroySynchronizedAccess(&(((PSTRING_TABLE)StringTable)->Lock));
|
|
|
|
pStringTableDestroy(StringTable);
|
|
}
|
|
|
|
|
|
VOID
|
|
pStringTableDestroy(
|
|
IN PVOID StringTable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Destroy a string table, freeing all resources it uses.
|
|
THIS ROUTINE DOES NOT DO LOCKING!
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies a string table handle returned from
|
|
a call to StringTableInitialize().
|
|
|
|
Return Value:
|
|
|
|
None.
|
|
|
|
--*/
|
|
|
|
{
|
|
MyFree(((PSTRING_TABLE)StringTable)->Data);
|
|
MyFree(StringTable);
|
|
}
|
|
|
|
|
|
PVOID
|
|
StringTableDuplicate(
|
|
IN PVOID StringTable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an independent dupplicate of a string table.
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies a string table handle of string table to duplicate.
|
|
|
|
Return Value:
|
|
|
|
Handle for new string table, NULL if out of memory.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTRING_TABLE New;
|
|
|
|
if(!LockTable((PSTRING_TABLE)StringTable)) {
|
|
return(NULL);
|
|
}
|
|
|
|
if(New = (PSTRING_TABLE)pStringTableDuplicate(StringTable)) {
|
|
|
|
if(!InitializeSynchronizedAccess(&New->Lock)) {
|
|
pStringTableDestroy(New);
|
|
New = NULL;
|
|
}
|
|
}
|
|
|
|
UnlockTable((PSTRING_TABLE)StringTable);
|
|
|
|
return New;
|
|
}
|
|
|
|
|
|
PVOID
|
|
pStringTableDuplicate(
|
|
IN PVOID StringTable
|
|
)
|
|
|
|
/*++
|
|
|
|
Routine Description:
|
|
|
|
Create an independent duplicate of a string table.
|
|
THIS ROUTINE DOES NOT DO LOCKING!
|
|
|
|
Arguments:
|
|
|
|
StringTable - supplies a string table handle of string table to duplicate.
|
|
|
|
Return Value:
|
|
|
|
Handle for new string table, NULL if out of memory or buffer copy failure.
|
|
|
|
Remarks:
|
|
|
|
This routine does not initialize synchronization locks for the duplicate--these
|
|
fields are initialized to NULL.
|
|
|
|
--*/
|
|
|
|
{
|
|
PSTRING_TABLE New;
|
|
PSTRING_TABLE stringTable = StringTable;
|
|
BOOL Success;
|
|
|
|
if(New = MyMalloc(sizeof(STRING_TABLE))) {
|
|
|
|
CopyMemory(New,StringTable,sizeof(STRING_TABLE));
|
|
|
|
//
|
|
// Allocate space for the string table data.
|
|
//
|
|
if(New->Data = MyMalloc(stringTable->DataSize)) {
|
|
//
|
|
// Surround memory copy in try/except, since we may be dealing with
|
|
// a string table contained in a PNF, in which case the buffer is
|
|
// in a memory-mapped file.
|
|
//
|
|
Success = TRUE; // assume success unless we get an inpage error...
|
|
try {
|
|
CopyMemory(New->Data, stringTable->Data, stringTable->DataSize);
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
Success = FALSE;
|
|
}
|
|
|
|
if(Success) {
|
|
New->BufferSize = New->DataSize;
|
|
ZeroMemory(&New->Lock, sizeof(MYLOCK));
|
|
return New;
|
|
}
|
|
|
|
MyFree(New->Data);
|
|
}
|
|
|
|
MyFree(New);
|
|
}
|
|
|
|
return NULL;
|
|
}
|
|
|
|
|
|
PVOID
|
|
InitializeStringTableFromPNF(
|
|
IN PPNF_HEADER PnfHeader
|
|
)
|
|
{
|
|
PSTRING_TABLE StringTable;
|
|
BOOL WasLoaded = TRUE;
|
|
|
|
//
|
|
// Allocate a string table
|
|
//
|
|
if(!(StringTable = MyMalloc(sizeof(STRING_TABLE)))) {
|
|
return NULL;
|
|
}
|
|
|
|
try {
|
|
|
|
StringTable->Data = (PUCHAR)PnfHeader + PnfHeader->StringTableBlockOffset;
|
|
|
|
StringTable->DataSize = StringTable->BufferSize = PnfHeader->StringTableBlockSize;
|
|
|
|
//
|
|
// Clear the Lock structure, because PNF string tables can only be accessed
|
|
// internally, via their associated INF.
|
|
//
|
|
StringTable->Lock.Handles[0] = StringTable->Lock.Handles[1] = NULL;
|
|
|
|
} except(EXCEPTION_EXECUTE_HANDLER) {
|
|
WasLoaded = FALSE;
|
|
}
|
|
|
|
if(WasLoaded) {
|
|
return StringTable;
|
|
} else {
|
|
MyFree(StringTable);
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
|
|
DWORD
|
|
pStringTableGetDataBlock(
|
|
IN PVOID StringTable,
|
|
OUT PVOID *StringTableBlock
|
|
)
|
|
{
|
|
*StringTableBlock = (PVOID)(((PSTRING_TABLE)StringTable)->Data);
|
|
|
|
return ((PSTRING_TABLE)StringTable)->DataSize;
|
|
}
|
|
|