windows-nt/Source/XPSP1/NT/sdktools/restools/rltools/common/ntmsgtbl.c
2020-09-26 16:20:57 +08:00

721 lines
26 KiB
C

//.....................................................................
//...
//... NTMSGTBL.C
//...
//... Contains functions for handling strings found in NT's Message
//... Resource Tables. This recource type is not present in Win 3.1.
//...
//... Author - David Wilcox (davewi@microsoft)
//...
//... NOTES: Created with tabstop set to 8
//...
//.....................................................................
//...
//... History:
//... Original - 10/92
//... 11/92 - Fixed to handle ULONG msg ID#'s - davewi
//...
//.....................................................................
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <windef.h>
#include <tchar.h>
#include <winver.h>
#include "windefs.h"
#include "restok.h"
#include "custres.h"
#include "ntmsgtbl.h"
#include "resread.h"
typedef PMESSAGE_RESOURCE_ENTRY PMRE;
extern BOOL gbMaster;
extern UCHAR szDHW[];
static PBYTE *pBlockEntries = NULL;
VOID *pResMsgData = NULL; // NT-specific Message Table resource
//.........................................................................
//...
//... Get Message Table from .res file
//...
//... This form of a message table, not found in Win 16, allows very long
//... strings and the text is stored as an ASCIIZ string in the .res file.
VOID *GetResMessage(
FILE *pInResFile, //... The file containing the resources
DWORD *plSize) //... The size of this resource from GetResHeader
{
ULONG ulNumBlocks = 0L; //... # of Message Table resource blocks
ULONG ulStartMsgDataPos = 0L; //... Start of message data in file
ULONG ulBlock; //... Current message block number
USHORT usCurrBlockSize = 0; //... Current size of temp block buffer
USHORT usDeltaBlockSize = 4096; //... Amount to increase usCurrBlockSize
DWORD dwNumMsgs = 0; //... Count of msgs in the resource
PBYTE pMsgBlock = NULL; //... Temp message block buffer
PMESSAGE_RESOURCE_DATA pMsgResData;//... Returned as ptr to the resource
PMESSAGE_RESOURCE_BLOCK pMRB; //... ptr to a block of messages
//... The resource header was read prior to
//... entring this function, so the current
//... file position should now be the start
//... of the resource data.
ulStartMsgDataPos = ftell( pInResFile);
//... Get the number of message blocks and
//... allocate enough memory for the array.
ulNumBlocks = GetdWord( pInResFile, plSize);
//... Allocate space for the array of
//... pointers to entries. This array is used
//... to store pointers to the first entry
//... in each block of message entries.
pBlockEntries = (PBYTE *)FALLOC( ulNumBlocks * sizeof( PBYTE));
if ( ! pBlockEntries )
{
QuitT( IDS_ENGERR_11, NULL, NULL);
}
pMsgResData = (PMESSAGE_RESOURCE_DATA)FALLOC( sizeof( ULONG) + ulNumBlocks
* sizeof( MESSAGE_RESOURCE_BLOCK));
if ( ! pMsgResData )
{
QuitT( IDS_ENGERR_11, NULL, NULL);
}
pResMsgData = pMsgResData;
pMsgResData->NumberOfBlocks = ulNumBlocks;
//... Read the array of message block structs,
//... and initialize block entry pointer array.
for ( ulBlock = 0L, pMRB = pMsgResData->Blocks;
ulBlock < ulNumBlocks;
++ulBlock, ++pMRB )
{
pMRB->LowId = GetdWord( pInResFile, plSize);
pMRB->HighId = GetdWord( pInResFile, plSize);
pMRB->OffsetToEntries = GetdWord( pInResFile, plSize);
if ( pMRB->HighId < pMRB->LowId )
{
ClearResMsg( &pResMsgData);
QuitT( IDS_ENGERR_16, (LPTSTR)IDS_INVMSGRNG, NULL);
}
dwNumMsgs += (pMRB->HighId - pMRB->LowId + 1);
pBlockEntries[ ulBlock] = NULL;
}
//... Read in the MESSAGE_RESOURCE_ENTRY
usCurrBlockSize = usDeltaBlockSize;
for ( ulBlock = 0L, pMRB = pMsgResData->Blocks;
ulBlock < ulNumBlocks;
++ulBlock, ++pMRB )
{
ULONG ulCurrID; //... Current message ID # in this block
ULONG ulEndID; //... Last message ID # in this block + 1
USHORT usLen; //... For length of a message - MUST BE USHORT
USHORT usMsgBlkLen; //... Length of a block of messages
usMsgBlkLen = 0;
//... Move to start of block of message entries
//... then read all the messages in this block.
fseek( pInResFile,
ulStartMsgDataPos + pMRB->OffsetToEntries,
SEEK_SET);
for ( ulCurrID = pMRB->LowId, ulEndID = pMRB->HighId + 1;
ulCurrID < ulEndID;
++ulCurrID, --dwNumMsgs )
{
//... Get Msg Resource entry length
//... (Length is in bytes and includes
//... .Length and .Flags fields and any
//... padding that may exist after the text.)
usLen = GetWord( pInResFile, plSize);
if ( usLen >= 2 * sizeof( USHORT) )
{
PMRE pMRE;
PUCHAR puchText;
//... Create, or expand size of, pMsgBlkData
//... so we can append this entry.
//... Always resave ptr to the message block
//... (it may have moved).
if ( pMsgBlock )
{
if ( (USHORT)(usMsgBlkLen + usLen) > usCurrBlockSize )
{
usCurrBlockSize += __max(usDeltaBlockSize, (USHORT)(usMsgBlkLen + usLen));
pMsgBlock = (PBYTE)FREALLOC( pMsgBlock,
usCurrBlockSize);
}
}
else
{
pMsgBlock = FALLOC( usCurrBlockSize);
}
//... If the malloc worked, read this msg entry.
//... The section assumes there is one WORD
//... per USHORT and one WORD per WCHAR.
pMRE = (PMRE)(pMsgBlock + usMsgBlkLen);
//... Store the .Length field value (USHORT)
pMRE->Length = usLen;
usMsgBlkLen += usLen;
//... Get the .Flags field value (USHORT)
pMRE->Flags = GetWord( pInResFile, plSize);
//... Check to make sure this message is stored
//... either in ASCII in the current code page
//... or in Unicode, else fail.
if ( pMRE->Flags != 0 //... ASCII
&& pMRE->Flags != MESSAGE_RESOURCE_UNICODE ) //... Unicode
{
if ( pMsgBlock != NULL )
{
RLFREE( pMsgBlock);
}
ClearResMsg( &pResMsgData);
QuitA( IDS_NON0FLAG, NULL, NULL);
}
//... Get the .Text field string
usLen -= (2 * sizeof( WORD));
for ( puchText = (PUCHAR)pMRE->Text; usLen; ++puchText, --usLen )
{
*puchText = (UCHAR)GetByte( pInResFile, plSize);
}
DWordUpFilePointer( pInResFile,
MYREAD,
ftell( pInResFile),
plSize);
}
else
{
if ( pMsgBlock != NULL )
{
RLFREE( pMsgBlock);
}
ClearResMsg( &pResMsgData);
QuitT( IDS_ENGERR_05, (LPTSTR)IDS_INVMSGTBL, NULL);
}
} //... END FOR(each message entry in this block)
if ( pMsgBlock != NULL && usMsgBlkLen > 0 )
{
pBlockEntries[ ulBlock] = FALLOC( usMsgBlkLen);
memcpy( pBlockEntries[ ulBlock], pMsgBlock, usMsgBlkLen);
}
} //... END FOR(each message block)
if ( pMsgBlock != NULL )
{
RLFREE( pMsgBlock);
}
DWordUpFilePointer( pInResFile, MYREAD, ftell( pInResFile), plSize);
return( (VOID *)pMsgResData);
}
//.........................................................................
//...
//... Put localized Message Table into .res
//...
//... 01/93 - changes for var length Token text. MHotchin
//... 02/93 - stripped out code that split msgs into multiple tokens. davewi
void PutResMessage(
FILE *fpOutResFile, //... File to which localized resources are written
FILE *fpInTokFile, //... Output token file
RESHEADER ResHeader, //... Resource header data
VOID *pMsgResData) //... message table data built in GetResMessage
{
WORD wcCount = 0;
fpos_t ulResSizePos = 0L; //... File position for fixed up resource size
fpos_t ulBlocksStartPos=0L; //... File position of start of message blocks
ULONG ulNumBlocks = 0L; //... Number of Message Blocks
ULONG ulCurrOffset = 0L; //... Offset to current msg block
ULONG ulResSize = 0L; //... Size of this resource
ULONG ulBlock; //... Temporary counter
USHORT usEntryLen = 0; //... Length of current message entry
PMESSAGE_RESOURCE_DATA pData; //. Message table data from InResFile
static TOKEN Tok; //... Token from localized token file
if ( pMsgResData == NULL)
{
QuitT( IDS_ENGERR_05, (LPTSTR)IDS_NULMSGDATA, NULL);
}
memset( (void *)&Tok, 0, sizeof( Tok));
pData = (PMESSAGE_RESOURCE_DATA)pMsgResData;
if ( PutResHeader( fpOutResFile, ResHeader, &ulResSizePos, &ulResSize))
{
ClearResMsg( &pResMsgData);
QuitT( IDS_ENGERR_06, (LPTSTR)IDS_MSGTBLHDR, NULL);
}
ulResSize = 0L; //... Reset to zero (hdr len not to be included)
ulNumBlocks = pData->NumberOfBlocks;
//... Write number of msg blocks
PutdWord( fpOutResFile, ulNumBlocks, &ulResSize);
//... Remember this file position so we can
//... come back here and update the
//... OffsetToEntries field in each struct.
ulBlocksStartPos = ftell( fpOutResFile);
//... Write the array of message block structs
for ( ulBlock = 0L; ulBlock < ulNumBlocks; ++ulBlock )
{
PutdWord( fpOutResFile, pData->Blocks[ ulBlock].LowId, &ulResSize);
PutdWord( fpOutResFile, pData->Blocks[ ulBlock].HighId, &ulResSize);
PutdWord( fpOutResFile, 0L, &ulResSize); //... Will get fixed up later
}
// Prep for find token call
Tok.wType = ResHeader.wTypeID;
Tok.wName = ResHeader.wNameID;
Tok.wID = 0;
Tok.wFlag = 0;
if ( ResHeader.bNameFlag == IDFLAG )
{
lstrcpy( Tok.szName, ResHeader.pszName);
}
//... Write the MESSAGE_RESOURCE_ENTRY's. First
//... note offset from start of this resource's
//... data to first msg res entry struct which
//... starts right after the array of
//... RESOURCE_MESSAGE_BLOCK structs.
ulCurrOffset = sizeof( ULONG) + ulNumBlocks*sizeof( MESSAGE_RESOURCE_BLOCK);
for ( ulBlock = 0L; ulBlock < ulNumBlocks; ++ulBlock )
{
ULONG ulCurrID; //... Current message ID # in this block
ULONG ulEndID; //... Last message ID # in this block + 1
fpos_t ulEntryPos; //... Start of the current msg entry struct
PBYTE pMRE; //... Ptr to a MESSAGE_RESOURCE_ENTRY
PMESSAGE_RESOURCE_BLOCK pMRB;
//... Retrieve ptr to block of messages. The
//... ptr was stored in the pBlockEntries array
//... in GetResMessage function above.
pMRB = (PMESSAGE_RESOURCE_BLOCK)( &pData->Blocks[ ulBlock]);
pMRE = pBlockEntries[ ulBlock];
//... Note offset to start of block's entries
pData->Blocks[ ulBlock].OffsetToEntries = ulCurrOffset;
for ( ulCurrID = pMRB->LowId, ulEndID = pMRB->HighId + 1;
ulCurrID < ulEndID;
++ulCurrID )
{
static UCHAR szString[ 64] = "";
static TCHAR szwTmp[ 4096] = TEXT("");
USHORT usCnt = 0;
BOOL fFound = FALSE;
ULONG ulEntrySize = 0;
ulEntryPos = ftell( fpOutResFile);
ulEntrySize = 0L;
//... Write dummy entry length.
//... Value gets corrected later.
//... Write the .Flags field's value (USHORT).
PutWord( fpOutResFile, ((PMRE)pMRE)->Length, &ulEntrySize);
PutWord( fpOutResFile, ((PMRE)pMRE)->Flags, &ulEntrySize);
//... Get localized token then the length of
//... that token's new text. Add to that length
//... the length of the two USHORTs and use this
//... combined length as the value to store in
//... the msg res entry's .Length field.
//... Put low word of ID# in .wID and
//... the high word in .szName
Tok.wID = LOWORD( ulCurrID);
_itoa( HIWORD( ulCurrID), szString, 10);
_MBSTOWCS( Tok.szName,
szString,
TOKENSTRINGBUFFER,
lstrlenA( szString) + 1);
//... Always reset .wReserved because the code
//... in FindTokenText will change its value.
Tok.wReserved = ST_TRANSLATED;
Tok.szText = NULL;
*szwTmp = TEXT('\0');
for ( fFound = FALSE, Tok.wFlag = 0;
fFound = FindToken( fpInTokFile, &Tok, ST_TRANSLATED);
Tok.wFlag++ )
{
TextToBin( szwTmp, Tok.szText, lstrlen( Tok.szText) + 1);
//... Write out localized message text. It may
//... be stored as ASCII or Unicode string.
if ( ((PMRE)pMRE)->Flags == 0 ) //... ASCII message
{
_WCSTOMBS( szDHW,
szwTmp,
DHWSIZE,
lstrlen( szwTmp) + 1);
for ( usCnt = 0; szDHW[ usCnt]; ++usCnt )
{
PutByte( fpOutResFile, szDHW[ usCnt], &ulEntrySize);
}
}
else //... Unicode message
{
for ( usCnt = 0; szwTmp[ usCnt]; ++usCnt )
{
PutWord( fpOutResFile, szwTmp[ usCnt], &ulEntrySize);
}
}
*szwTmp = TEXT('\0');
RLFREE( Tok.szText);
//... Always reset .wReserved because the code
//... in FindTokenText will change its value.
Tok.wReserved = ST_TRANSLATED;
}
//... Did we find the token?
if ( Tok.wFlag == 0 && ! fFound )
{
static TCHAR szToken[ 4160];
ParseTokToBuf( szToken, &Tok);
ClearResMsg( &pResMsgData);
QuitT( IDS_ENGERR_05, szToken, NULL);
}
//... nul-terminate the text
if ( ((PMRE)pMRE)->Flags == 0 ) //... ASCII message
{
PutByte( fpOutResFile , '\0', (DWORD *)&ulEntrySize);
}
else //... Unicode message
{
PutWord( fpOutResFile , TEXT('\0'), (DWORD *)&ulEntrySize);
}
DWordUpFilePointer( fpOutResFile,
MYWRITE,
ftell( fpOutResFile),
&ulEntrySize);
//... Also, use this length in later updating
//... next msg block's OffsetToEntries value.
ulResSize += ulEntrySize;
ulCurrOffset += ulEntrySize;
//... Write Msg Resource entry length
//... (Length is in bytes and includes
//... .Length and .Flags fields and any
//... padding needed after the text.)
//...
//... NOTE: Msg text is currently stored as
//... an ASCIIZ string.
fseek( fpOutResFile, (long)ulEntryPos, SEEK_SET);
PutWord( fpOutResFile, (WORD)ulEntrySize, NULL);
fseek( fpOutResFile, 0L, SEEK_END);
//... Move pMRE to point to start of next
//... Message Resource Entry in memory.
pMRE += ((PMRE)pMRE)->Length;
} //... END FOR(each message entry in this block)
ulCurrOffset = DWORDUP( ulCurrOffset);
DWordUpFilePointer( fpOutResFile,
MYWRITE,
ftell( fpOutResFile),
&ulResSize);
} //... END FOR(each message block)
//... Update resource size field in res header
if ( UpdateResSize( fpOutResFile, &ulResSizePos, ulResSize) == 0L )
{
ClearResMsg( &pResMsgData);
QuitT( IDS_ENGERR_07, (LPTSTR)IDS_MSGRESTBL, NULL);
}
//... Now, update the OffsetToEntries fields.
fseek( fpOutResFile, (long)ulBlocksStartPos, SEEK_SET);
for ( ulBlock = 0L; ulBlock < ulNumBlocks; ++ulBlock )
{
PutdWord( fpOutResFile, pData->Blocks[ulBlock].LowId, NULL);
PutdWord( fpOutResFile, pData->Blocks[ulBlock].HighId, NULL);
PutdWord( fpOutResFile, pData->Blocks[ulBlock].OffsetToEntries, NULL);
}
fseek( fpOutResFile, 0L, SEEK_END);
} //... END PutResMessage()
//.........................................................................
//...
//... Write Message Table to the token file
//...
//... This function assumes that, in each message block, the message ID's are
//... contiguouse within the range given in the fields LowId and HighId in a
//... MESSAGE_RESOURCE_BLOCK.
//
// 01/93 - Changes for var length token text strings. Mhotchin
//
void TokResMessage(
FILE *pfTokFile, //... Output token file
RESHEADER ResHeader, //... Resource header data
VOID *pMsgResData) //... Data to tokenize (from GetResMessage call)
{
static TOKEN Tok;
ULONG ulBlock; //... Message resource block number
PMESSAGE_RESOURCE_DATA pData; //... Data to tokenize
PMESSAGE_RESOURCE_BLOCK pMRB; //... ptr to a message block struct
pData = (PMESSAGE_RESOURCE_DATA)pMsgResData;
memset( (void *)&Tok, 0, sizeof( Tok));
Tok.wType = ResHeader.wTypeID;
Tok.wName = ResHeader.wNameID;
Tok.wReserved = (gbMaster ? ST_NEW : ST_NEW | ST_TRANSLATED);
if ( ResHeader.bNameFlag == IDFLAG )
{
lstrcpy( Tok.szName, ResHeader.pszName);
}
for ( ulBlock = 0L; ulBlock < pData->NumberOfBlocks; ++ulBlock )
{
ULONG ulCurrID = 0L; //... ID # of current msg being processed
ULONG ulEndID; //... Last message ID # in this block + 1
USHORT usLineNum = 0; //... Count of lines in a message text
PCHAR pMRE; //... ptr to a message entry struct
//... Get ptr to this message block struct
pMRB = &pData->Blocks[ ulBlock];
//... Get ptr to first entry in
//... this block of messages
pMRE = (PCHAR)pBlockEntries[ ulBlock];
//... Tokenize entries in this block of messages
for ( ulCurrID = pMRB->LowId, ulEndID = pMRB->HighId + 1;
ulCurrID < ulEndID;
++ulCurrID )
{
usLineNum = 0;
//... inclusive of .Length and .Flags fields so
//... we need get the real length of the text.
if ( ((PMRE)pMRE)->Length >= 2 * sizeof( WORD) )
{
USHORT usLen = 0;
USHORT usTokTextLen = 0;
PWCHAR pszwStart = NULL;
// This is really ugly. This code was
// originally to get around the problem
// that tokens could hold only 260 chars.
// Now, it's whatever you want.
// Temp hack - assume each line will be
// less than 4k in size. (mhotchin)
static TCHAR szwString[ 32768 ];
//... Put low word of ID# in .wID and
//... the high word in .szName
Tok.wID = LOWORD( ulCurrID);
_itoa( HIWORD( ulCurrID), szDHW, 10);
_MBSTOWCS( Tok.szName,
szDHW,
TOKENSTRINGBUFFER,
lstrlenA( szDHW) +1);
//... The err msg table strings may be stored
//... in the resources as ANSI or Unicode.
//... If the pMRE->Flags field in the
//... table entry struct is 0, the text is a
//... ANSI striing so we need to convert it to
//... UNICODE (WCHAR).
if ( ((PMRE)pMRE)->Flags == 0 ) //... ASCII message
{
PUCHAR puchStart = (PUCHAR)((PMRE)pMRE)->Text;
usLen = (USHORT)_MBSTOWCS( szwString,
puchStart,
WCHARSIN( sizeof( szwString)),
ACHARSIN( lstrlenA( puchStart) + 1));
if (usLen == 0)
QuitT( IDS_ENGERR_10, szwString, NULL);
pszwStart = szwString;
}
else //... Unicode message
{
pszwStart = (WCHAR *)(((PMRE)pMRE)->Text);
usLen = (USHORT)lstrlen( pszwStart) /*+ 1*/;
}
//... We need to split the token text at \r\n
for ( Tok.wFlag = 0;
usLen > 0;
usLen -= usTokTextLen, Tok.wFlag++ )
{
WCHAR wcTmp;
for ( usTokTextLen = 0, wcTmp = TEXT('\0');
usTokTextLen < usLen;
++usTokTextLen )
{
if ( pszwStart[ usTokTextLen] == TEXT('\r')
&& pszwStart[ usTokTextLen+1] == TEXT('\n') )
{
usTokTextLen += 2;
wcTmp = pszwStart[ usTokTextLen];
pszwStart[ usTokTextLen] = TEXT('\0');
break;
}
}
Tok.szText = BinToTextW( pszwStart, usTokTextLen);
PutToken( pfTokFile, &Tok);
RLFREE( Tok.szText);
pszwStart += usTokTextLen;
*pszwStart = wcTmp;
}
//... Set up to move to start of next msg entry
pMRE += ((PMRE)pMRE)->Length;
}
else
{
ClearResMsg( &pResMsgData);
QuitT( IDS_ENGERR_05, (LPTSTR)IDS_MSGTOOSHORT, NULL);
}
} //... END FOR processing a msg block
} //... END FOR processing all msg blocks
}
//.........................................................................
//...
//... Clear memory created in GetResMessage()
void ClearResMsg(
VOID **pData) //... ptr to ptr to start of memory to free
{
if ( pData != NULL && *pData != NULL )
{
ULONG ulBlock;
PMESSAGE_RESOURCE_DATA pMRD; //... ptr to a message data struct
PMESSAGE_RESOURCE_BLOCK pMRB; //... ptr to a message block struct
pMRD = (PMESSAGE_RESOURCE_DATA)*pData;
pMRB = pMRD->Blocks;
if ( pBlockEntries != NULL )
{
for ( ulBlock = 0L; ulBlock < pMRD->NumberOfBlocks; ++ulBlock )
{
if ( pBlockEntries[ ulBlock] )
{
RLFREE( pBlockEntries[ ulBlock]);
}
}
RLFREE( (PBYTE)pBlockEntries);
}
RLFREE( *pData);
}
}