NT4/private/windows/winnls/nlstrans/table.c
2020-09-30 17:12:29 +02:00

1015 lines
26 KiB
C

/*++
Copyright (c) 1991-1996, Microsoft Corporation All rights reserved.
Module Name:
table.c
Abstract:
This file contains functions necessary to manipulate the various
table structures.
External Routines in this file:
ComputeMBSize
Compute844Size
ComputeCTMapSize
Write844Table
Write844TableMap
WriteCTMapTable
WriteWords
FileWrite
RemoveDuplicate844Levels
Revision History:
06-14-91 JulieB Created.
--*/
//
// Include Files.
//
#include "nlstrans.h"
//
// Constant Declarations.
//
#define HASH_SIZE 65521 // size of hash table (prime #)
//
// Typedef Declarations.
//
typedef struct hash_object_s
{
PVOID pTable; // ptr to table
struct hash_object_s *pNext; // ptr to next hash node
} CT_HASH_OBJECT, *PCT_HASH_OBJECT;
//
// Forward Declarations.
//
void
RemoveDuplicate844Level2(
P844_ARRAY pArr,
int *pBuf2);
void
RemoveDuplicate844Level3(
P844_ARRAY pArr,
int *pBuf3,
int Size);
PVOID
FindHashTable(
PVOID pTbl,
PCT_HASH_OBJECT *pHashTbl,
int Size);
DWORD
GetHashVal(
PVOID pTbl,
int Size);
void
FreeHashTable(
PCT_HASH_OBJECT *pHashTbl);
//-------------------------------------------------------------------------//
// EXTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// ComputeMBSize
//
// This routine returns the size (in words) of the MB, Glyph, and DBCS
// tables.
//
// 07-30-91 JulieB Created.
// 12-10-91 JulieB Modified for new table format.
////////////////////////////////////////////////////////////////////////////
int ComputeMBSize(
PCODEPAGE pCP)
{
int TblSize; // size of table
int Ctr; // loop counter
register int NumRanges; // number of DBCS ranges
PDBCS_ARRAY pArray; // ptr to DBCS array
//
// Compute static size of table.
//
if (pCP->WriteFlags & F_GLYPH)
{
TblSize = 1 + MB_TABLE_SIZE + (1 + GLYPH_TABLE_SIZE) + 1;
}
else
{
TblSize = 1 + MB_TABLE_SIZE + (1) + 1;
}
//
// Compute size with DBCS tables (if any).
//
NumRanges = pCP->NumDBCSRanges;
if ((NumRanges > 0) && (pCP->WriteFlags & F_DBCS))
{
TblSize += DBCS_OFFSET_SIZE;
pArray = pCP->pDBCS;
for (Ctr = 0; Ctr < NumRanges; Ctr++)
{
TblSize += ((pArray[Ctr]->HighRange -
pArray[Ctr]->LowRange + 1) * DBCS_TABLE_SIZE);
}
}
if (Verbose)
printf(" Complete MB Table Size = %d\n", TblSize);
//
// Return the table size.
//
return (TblSize);
}
////////////////////////////////////////////////////////////////////////////
//
// Compute844Size
//
// This routine returns the size (in words) of the 8:4:4 WORD or DWORD
// table.
//
// 07-30-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int Compute844Size(
int cbBuf2,
int cbBuf3,
int Size)
{
int TblSize; // size of table
//
// Adjust size of cbBuf2 and cbBuf3 for the two empty levels.
//
cbBuf2++;
cbBuf3++;
//
// Compute size of table.
//
TblSize = TABLE_SIZE_8 +
(TABLE_SIZE_4 * cbBuf2) +
(TABLE_SIZE_4 * cbBuf3 * Size / sizeof(WORD));
if (Verbose)
printf(" 844 Table Size = %d\t\tBuf2 = %d\tBuf3 = %d\n",
TblSize, cbBuf2, cbBuf3);
//
// Return the table size.
//
return (TblSize);
}
////////////////////////////////////////////////////////////////////////////
//
// ComputeCTMapSize
//
// This routine returns the size of the ctype mapping table.
//
////////////////////////////////////////////////////////////////////////////
DWORD ComputeCTMapSize(
PCT_MAP pMap)
{
DWORD TblSize; // size of table
//
// Compute size of table.
//
TblSize = sizeof(WORD) + (pMap->Length * sizeof(CT_VALUES));
if (Verbose)
printf(" Mapping Table Size = %d\n", TblSize);
//
// Return the table size.
//
return (TblSize);
}
////////////////////////////////////////////////////////////////////////////
//
// Write844Table
//
// This routine writes the 8:4:4 WORD table to the output file.
//
// 07-30-91 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int Write844Table(
FILE *pOutputFile,
P844_ARRAY pArr,
int cbBuf2,
int TblSize,
int Size)
{
WORD EmptyLevel2Offset; // empty level 2 offset
WORD EmptyLevel3Offset; // empty level 3 offset
WORD Pos2; // position array 2
WORD Pos3; // position array 3
WORD PosTemp2 = TABLE_SIZE_4; // position in pTemp2
WORD *pTemp; // temporary storage
PVOID pTemp2; // temporary storage
DWORD Ctr, Ctr2, Ctr3; // loop counters
P844_ARRAY ptr2; // ptr to second array
P844_ARRAY ptr3; // ptr to third array
//
// Need to adjust cbBuf2 for the empty level 2 table.
// TblSize was already adjusted for the empty level tables
// in Compute844Size.
//
cbBuf2++;
//
// Set up the position offsets and the empty second and third level
// table offsets. All Unicode characters that have no mappings will
// point to the empty tables. Grab the first table in the second
// level tables (offset TABLE_SIZE_8 in pTemp) and the first table in
// the third level tables (offset TABLE_SIZE_8 + (cbBuf2 * TABLE_SIZE_4))
// for the empty tables.
//
EmptyLevel2Offset = TABLE_SIZE_8;
Pos2 = EmptyLevel2Offset + TABLE_SIZE_4;
EmptyLevel3Offset = TABLE_SIZE_8 + (cbBuf2 * TABLE_SIZE_4);
Pos3 = EmptyLevel3Offset + (TABLE_SIZE_4 * Size / sizeof(WORD));
//
// Allocate temporary storage buffers.
//
if (AllocateTemp844( &pTemp,
EmptyLevel3Offset,
sizeof(WORD) ))
{
return (1);
}
if (AllocateTemp844( &pTemp2,
TblSize - EmptyLevel3Offset,
Size ))
{
return (1);
}
//
// Set up the empty second level table to point to the empty third
// level table.
//
for (Ctr2 = 0; Ctr2 < TABLE_SIZE_4; Ctr2++)
{
pTemp[EmptyLevel2Offset + Ctr2] = EmptyLevel3Offset;
}
//
// For each entry in the array, copy the appropriate offsets
// to the storage buffer.
//
for (Ctr = 0; Ctr < TABLE_SIZE_8; Ctr++)
{
if ((ptr2 = (P844_ARRAY)(pArr[Ctr])) != NULL)
{
pTemp[Ctr] = Pos2;
for (Ctr2 = 0; Ctr2 < TABLE_SIZE_4; Ctr2++)
{
if ((ptr3 = ptr2[Ctr2]) != NULL)
{
pTemp[Pos2 + Ctr2] = Pos3;
for (Ctr3 = 0; Ctr3 < TABLE_SIZE_4; Ctr3++)
{
memcpy( ((BYTE *)pTemp2) + ((PosTemp2 + Ctr3) * Size),
((BYTE *)ptr3) + (Ctr3 * Size),
Size );
}
//
// When advancing the Pos3 counter, must compensate
// for the Size (multiply by 2 for DWORD).
//
Pos3 += (TABLE_SIZE_4 * Size / sizeof(WORD));
PosTemp2 += TABLE_SIZE_4;
}
else
{
pTemp[Pos2 + Ctr2] = EmptyLevel3Offset;
}
}
Pos2 += TABLE_SIZE_4;
}
else
{
pTemp[Ctr] = EmptyLevel2Offset;
}
}
//
// Write temp storage buffers to output file.
//
if (FileWrite( pOutputFile,
pTemp,
sizeof(WORD),
Pos2,
"8:4:4 buffer" ))
{
return (1);
}
if (FileWrite( pOutputFile,
pTemp2,
Size,
PosTemp2,
"8:4:4 buffer" ))
{
return (1);
}
//
// Return success.
//
return (0);
}
////////////////////////////////////////////////////////////////////////////
//
// Write844TableMap
//
// This routine writes the 8:4:4 BYTE "mapped" table to the output file.
//
// 10-29-93 JulieB Created.
////////////////////////////////////////////////////////////////////////////
int Write844TableMap(
FILE *pOutputFile,
P844_ARRAY pArr,
WORD TblSize)
{
WORD EmptyLevel2Offset; // empty level 2 offset
WORD EmptyLevel3Offset; // empty level 3 offset
WORD Pos; // position level 2 & 3
WORD *pTemp2; // temporary storage - level 2
BYTE *pTempTbl; // temporary storage - entire table
DWORD Ctr, Ctr2, Ctr3; // loop counters
P844_ARRAY ptr2; // ptr to second array
PCT_MAP_VALUE ptr3; // ptr to third array
//
// Set up the second and third level empty tables.
//
EmptyLevel3Offset = (TABLE_SIZE_8 * sizeof(WORD));
EmptyLevel2Offset = EmptyLevel3Offset + (TABLE_SIZE_4 * sizeof(BYTE));
//
// Set up position offset for the regular second and third level
// tables.
//
Pos = EmptyLevel2Offset + (TABLE_SIZE_4 * sizeof(WORD));
//
// Allocate temporary storage buffers.
//
if (AllocateTemp844( &pTemp2,
TABLE_SIZE_4,
sizeof(WORD) ))
{
return (1);
}
if (AllocateTemp844( &pTempTbl,
TblSize,
sizeof(BYTE) ))
{
return (1);
}
//
// Set up the empty second level table to point to the empty third
// level table.
//
for (Ctr = 0; Ctr < TABLE_SIZE_4; Ctr++)
{
pTemp2[Ctr] = EmptyLevel3Offset;
}
memcpy( &pTempTbl[EmptyLevel2Offset],
pTemp2,
TABLE_SIZE_4 * sizeof(WORD) );
//
// For each entry in the array, copy the appropriate offsets
// to the storage buffers.
//
for (Ctr = 0; Ctr < TABLE_SIZE_8; Ctr++)
{
if ((ptr2 = (P844_ARRAY)(pArr[Ctr])) != NULL)
{
//
// See if the table is a duplicate.
//
if (ptr2[DUPLICATE_OFFSET] != 0)
{
//
// Table IS a duplicate, so just save the offset.
//
((WORD *)pTempTbl)[Ctr] = (WORD)(ptr2[DUPLICATE_OFFSET]);
//
// Set the duplicate pointer to null in the previous level,
// so that freeing of the 844 table is simpler.
//
pArr[Ctr] = NULL;
}
else
{
//
// Table is NOT a duplicate.
// Copy it and save the position for use later if
// it's a duplicate.
//
for (Ctr2 = 0; Ctr2 < TABLE_SIZE_4; Ctr2++)
{
if ((ptr3 = ptr2[Ctr2]) != NULL)
{
//
// See if the table is a duplicate.
//
if (*(WORD *)(ptr3 + DUPLICATE_OFFSET) != 0)
{
//
// Table IS a duplicate, so just save the
// offset.
//
pTemp2[Ctr2] = *(WORD *)(ptr3 + DUPLICATE_OFFSET);
//
// Set the duplicate pointer to null in the
// previous level, so that freeing of the
// 844 table is simpler.
//
ptr2[Ctr2] = NULL;
}
else
{
//
// Table is NOT yet a duplicate.
// Save the position in case this third
// level table is used again.
//
*(WORD *)(ptr3 + DUPLICATE_OFFSET) = Pos;
pTemp2[Ctr2] = Pos;
//
// Copy the third level table to the buffer
// and update the position counter.
//
for (Ctr3 = 0; Ctr3 < TABLE_SIZE_4; Ctr3++)
{
pTempTbl[Pos + Ctr3] = ptr3[Ctr3];
}
Pos += TABLE_SIZE_4;
}
}
else
{
pTemp2[Ctr2] = EmptyLevel3Offset;
}
}
//
// Save the position in case this second level table is
// used again.
//
(WORD)ptr2[DUPLICATE_OFFSET] = Pos;
//
// Copy the second level table to the buffer,
// update the first level table with the position of
// the second level table, and update the position
// counter.
//
memcpy( &pTempTbl[Pos],
pTemp2,
TABLE_SIZE_4 * sizeof(WORD) );
((WORD *)pTempTbl)[Ctr] = Pos;
Pos += (TABLE_SIZE_4 * sizeof(WORD));
}
}
else
{
((WORD *)pTempTbl)[Ctr] = EmptyLevel2Offset;
}
}
//
// Write temp storage buffers to output file.
//
if (FileWrite( pOutputFile,
pTempTbl,
sizeof(BYTE),
TblSize,
"8:4:4 buffer" ))
{
return (1);
}
//
// Return success.
//
return (0);
}
////////////////////////////////////////////////////////////////////////////
//
// WriteCTMapTable
//
// This routine writes the ctype mapping table to the output file.
//
////////////////////////////////////////////////////////////////////////////
int WriteCTMapTable(
FILE *pOutputFile,
PCT_MAP pMap,
WORD MapSize)
{
//
// Write the size of the mapping table.
//
if (FileWrite( pOutputFile,
&MapSize,
sizeof(WORD),
1,
"Mapping Table size" ))
{
fclose(pOutputFile);
return (1);
}
//
// Write mapping table to output file.
//
if (FileWrite( pOutputFile,
pMap->pCTValues,
MapSize - sizeof(WORD),
1,
"Mapping Table buffer" ))
{
return (1);
}
//
// Return success.
//
return (0);
}
////////////////////////////////////////////////////////////////////////////
//
// WriteWords
//
// This routine writes multiple words of the same value to the output file.
// The number of values written is determined by the Num parameter.
//
// 07-30-91 JulieB Created.
// 12-10-91 JulieB Modified for new table format.
////////////////////////////////////////////////////////////////////////////
int WriteWords(
FILE *pOutputFile,
int Value,
int Num)
{
//
// Write the given 'Value' as a WORD 'Num' times to the output file.
//
if (FileWrite( pOutputFile,
&Value,
sizeof(WORD),
Num,
"WRITE WORDS" ))
{
return (1);
}
//
// Return success.
//
return (0);
}
////////////////////////////////////////////////////////////////////////////
//
// FileWrite
//
// This routine writes the given buffer to the output file. If an error is
// encountered, then it is returned.
//
// 07-30-91 JulieB Created.
// 12-10-91 JulieB Modified for new table format.
////////////////////////////////////////////////////////////////////////////
int FileWrite(
FILE *pOutputFile,
void *Buffer,
int Size,
int Count,
char *ErrStr)
{
//
// Write information to output file.
//
if (fwrite( Buffer,
Size,
Count,
pOutputFile ) != (unsigned int)Count)
{
printf("Write Error: Can't write %s to file.\n", ErrStr);
return (1);
}
//
// Return success.
//
return (0);
}
////////////////////////////////////////////////////////////////////////////
//
// RemoveDuplicate844Levels
//
// This routine removes all duplicate second levels and all duplicate
// third levels from an 8:4:4 table.
//
////////////////////////////////////////////////////////////////////////////
void RemoveDuplicate844Levels(
P844_ARRAY pArr,
int *pBuf2,
int *pBuf3,
int Size)
{
//
// Remove the duplicates from the third level of the 8:4:4 table
// first.
//
RemoveDuplicate844Level3( pArr,
pBuf3,
Size );
//
// Remove the duplicates from the second level of the 8:4:4 table.
//
RemoveDuplicate844Level2( pArr,
pBuf2 );
}
//-------------------------------------------------------------------------//
// INTERNAL ROUTINES //
//-------------------------------------------------------------------------//
////////////////////////////////////////////////////////////////////////////
//
// RemoveDuplicate844Level2
//
// This routine removes all duplicate second levels from the given 8:4:4
// table.
//
////////////////////////////////////////////////////////////////////////////
void RemoveDuplicate844Level2(
P844_ARRAY pArr,
int *pBuf2)
{
P844_ARRAY pTbl2; // ptr to second array
P844_ARRAY pCmp; // ptr to second array to compare
int Ctr, Ctr2, Ctr3; // loop counters
//
// Search through all second level tables. If there is a duplicate,
// fix the affected pointers in the first level table and free the
// duplicate table.
//
for (Ctr = 1; Ctr < TABLE_SIZE_8; Ctr++)
{
if ((pTbl2 = (P844_ARRAY)(pArr[Ctr])) != NULL)
{
//
// See if any of the previous second level tables are the
// same as the current one.
//
for (Ctr2 = Ctr - 1; Ctr2 >= 0; Ctr2--)
{
if ((pCmp = (P844_ARRAY)(pArr[Ctr2])) != NULL)
{
//
// Compare each entry in both tables to see if
// the tables are the same.
//
for (Ctr3 = 0; Ctr3 < TABLE_SIZE_4; Ctr3++)
{
if (pTbl2[Ctr3] != pCmp[Ctr3])
{
break;
}
}
if (Ctr3 == TABLE_SIZE_4)
{
//
// Tables are the same. Fix the pointer
// in the first level table.
//
pArr[Ctr] = pCmp;
//
// Free the duplicate second level table.
//
free(pTbl2);
//
// Decrement the number of second level tables.
//
(*pBuf2)--;
//
// Found the duplicate, so break out of the
// comparison loop.
//
break;
}
}
}
}
}
}
////////////////////////////////////////////////////////////////////////////
//
// RemoveDuplicate844Level3
//
// This routine removes all duplicate third levels from the given 8:4:4
// table.
//
////////////////////////////////////////////////////////////////////////////
void RemoveDuplicate844Level3(
P844_ARRAY pArr,
int *pBuf3,
int Size)
{
P844_ARRAY pTbl2; // ptr to second array
PVOID pTbl3; // ptr to third array
PVOID pCmp; // ptr to third array to compare
PCT_HASH_OBJECT *pHashTbl; // hash table
int Ctr, Ctr2; // loop counters
//
// Allocate the hash table.
//
pHashTbl = (PCT_HASH_OBJECT *)malloc(HASH_SIZE * sizeof(PCT_HASH_OBJECT));
memset( pHashTbl,
0,
(HASH_SIZE * sizeof(PCT_HASH_OBJECT)) );
//
// Search through all third level tables. If there is a duplicate,
// fix the affected pointers in the second level tables and free the
// duplicate table.
//
for (Ctr = 0; Ctr < TABLE_SIZE_8; Ctr++)
{
if ((pTbl2 = (P844_ARRAY)(pArr[Ctr])) != NULL)
{
//
// See if any of the previous third level tables are the
// same as the current one.
//
for (Ctr2 = 0; Ctr2 < TABLE_SIZE_4; Ctr2++)
{
if ((pTbl3 = pTbl2[Ctr2]) != NULL)
{
//
// Compare each entry in the table to see if
// the table is the same as any of the previous
// tables.
//
pCmp = FindHashTable( pTbl3,
pHashTbl,
Size );
if (pCmp != NULL)
{
//
// Tables are the same. Fix the pointer
// in the second level table.
//
pTbl2[Ctr2] = pCmp;
//
// Free the duplicate third level table.
//
free(pTbl3);
//
// Decrement the number of second level tables.
//
(*pBuf3)--;
}
}
}
}
}
//
// Free the hash table.
//
FreeHashTable(pHashTbl);
}
////////////////////////////////////////////////////////////////////////////
//
// FindHashTable
//
// This routine searches the hash table for the given third level table.
// If a matching table is found, the pointer to the table is returned.
// Otherwise, it returns NULL.
//
////////////////////////////////////////////////////////////////////////////
PVOID FindHashTable(
PVOID pTbl,
PCT_HASH_OBJECT *pHashTbl,
int Size)
{
DWORD HashVal; // hash value
PCT_HASH_OBJECT pHashN; // ptr to hash node
PCT_HASH_OBJECT pNewHash; // ptr to new hash node
int Ctr; // loop counter
//
// Get hash value of the given table.
//
HashVal = GetHashVal(pTbl, Size);
//
// Search through all hash tables.
//
for (pHashN = pHashTbl[HashVal]; pHashN != NULL; pHashN = pHashN->pNext)
{
//
// See if the two tables are the same. If they are, return the
// pointer to the table.
//
for (Ctr = 0; Ctr < TABLE_SIZE_4; Ctr++)
{
if (memcmp( ((BYTE *)(pHashN->pTable)) + (Ctr * Size),
((BYTE *)pTbl) + (Ctr * Size),
Size ))
{
break;
}
}
if (Ctr == TABLE_SIZE_4)
{
//
// Tables are the same. Return the pointer to the table.
//
return (pHashN->pTable);
}
}
//
// Could not find a table that matched the given table.
// Create a new hash node and insert it in the hash table.
//
pNewHash = (PCT_HASH_OBJECT)malloc(sizeof(CT_HASH_OBJECT));
pNewHash->pTable = pTbl;
pNewHash->pNext = pHashTbl[HashVal];
pHashTbl[HashVal] = pNewHash;
//
// Return NULL to indicate that an identical table could not be found.
//
return (NULL);
}
////////////////////////////////////////////////////////////////////////////
//
// GetHashVal
//
// This routine calculates the hash value of a table.
//
////////////////////////////////////////////////////////////////////////////
DWORD GetHashVal(
PVOID pTbl,
int Size)
{
DWORD HashVal = 0; // hash value
DWORD Multiplier = 1; // multiplier for each entry
int Ctr; // loop counter
for (Ctr = 0; Ctr < TABLE_SIZE_4; Ctr++)
{
HashVal += ((*(((BYTE *)pTbl) + (Ctr * Size))) * Multiplier);
Multiplier *= 2;
}
return ((DWORD)(HashVal / HASH_SIZE));
}
////////////////////////////////////////////////////////////////////////////
//
// FreeHashTable
//
// This routine frees the hash table.
//
////////////////////////////////////////////////////////////////////////////
void FreeHashTable(
PCT_HASH_OBJECT *pHashTbl)
{
PCT_HASH_OBJECT pHashN; // ptr to hash node
PCT_HASH_OBJECT pNext; // ptr to next hash node
int Ctr = 0; // loop counter
//
// Search through each entry in the hash table and free each node.
//
for (Ctr = 0; Ctr < HASH_SIZE; Ctr++)
{
pHashN = pHashTbl[Ctr];
while (pHashN != NULL)
{
pNext = pHashN->pNext;
free(pHashN);
pHashN = pNext;
}
}
//
// Free the hash table array.
//
free(pHashTbl);
}