windows-nt/Source/XPSP1/NT/sdktools/restools/rltools/common/custres.c

3038 lines
82 KiB
C
Raw Normal View History

2020-09-26 03:20:57 -05:00
/** CustRes.c
*
* Custom resource handler module for TOKRES.
*
* Written by SteveBl
*
* Exported Functions:
* int ParseResourceDescriptionFile(FILE *ResourceDescriptionFile);
*
* int GetCustomResource(FILE *inResFile, DWORD *lsize,
* CUSTOM_RESOURCE *pCustomResource,
* WORD wTypeId);
*
* void TokCustomResource(FILE *TokFile, RESHEADER ResHeader,
* CUSTOM_RESOURCE *pCustomResource);
*
* void PutCustomResource(FILE *OutResFile, FILE *TokFile,
* RESHEADER ResHeader,
* CUSTOM_RESOURCE *pCustomResource);
*
* void ClearCustomResource(CUSTOM_RESOURCE *pCustomResource);
*
* History:
* Initial version written January 21, 1992. -- SteveBl
*
* 01/21/93 - Changes to allow arb length token texts. Also, fix
* some latent bugs. MHotchin
**/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <tchar.h>
#ifdef RLDOS
#include "dosdefs.h"
#else
#include <windows.h>
#include "windefs.h"
#endif
#include "custres.h"
#include "restok.h"
#include "resread.h"
extern PROJDATA gProj; //... Fields filled in main (UI)
extern BOOL gbMaster;
extern UCHAR szDHW[];
enum LOCALIZABLE_TYPES // determines data storage, reading, and printing method
{
NOTLOCALIZABLE, // not to be stored
NOTLOCALIZABLESZ, // unlocalizable null terminated string
NOTLOCALIZABLEWSZ, // unlocalizable null terminated Unicode string
LT_INTEGER, // store as a long integer
LT_FLOAT, // store as a double preceision floating point number
LT_CHAR, // store as a single character
LT_STRING, // an array of char
LT_SZ, // a null terminated array of characters
LT_WCHAR, // store as a single Unicode character
LT_WSTRING, // an array of Unicode char
LT_WSZ, // a null terminated array of Unicode characters
LT_UNSIGNED=16 // add with the others
};
typedef struct typesizes
{
CHAR *szType;
enum LOCALIZABLE_TYPES iType;
int iShortSize;
int iLongSize;
} TYPESIZES;
TYPESIZES rgTypeSizes[] =
{
#ifdef RLWIN32
"WCHAR", LT_WCHAR, 2, 2,
"TCHAR", LT_WCHAR, 2, 2,
"INT", LT_INTEGER, 4, 4,
"SIGNED", LT_INTEGER, 4, 4,
"UNSIGNED", LT_INTEGER, 4, 4,
"ENUM", LT_INTEGER, 4, 4,
#else //RLWIN32
"TCHAR", LT_CHAR, 1, 1,
"INT", LT_INTEGER, 2, 4,
"SIGNED", LT_INTEGER, 2, 4,
"UNSIGNED", LT_INTEGER, 2, 4,
"ENUM", LT_INTEGER, 2, 2,
#endif //RLWIN32
"CHAR", LT_CHAR, 1, 1,
"BYTE", LT_INTEGER, 1, 1,
"WORD", LT_INTEGER, 2, 2,
"SHORT", LT_INTEGER, 2, 2,
"FLOAT", LT_FLOAT, 4, 4,
"LONG", LT_INTEGER, 4, 4,
"DOUBLE", LT_FLOAT, 8, 8,
"DWORD", LT_INTEGER, 4, 4
};
typedef struct resourcetypes
{
CHAR *szType;
int iType;
} RESOURCETYPES;
RESOURCETYPES rgResourceTypes[] =
{
"CURSOR", 1,
"BITMAP", 2,
"ICON", 3,
"MENU", 4,
"DIALOG", 5,
"STRING", 6,
"FONTDIR", 7,
"FONT", 8,
"ACCELERATORS", 9,
"RCDATA", 10,
"ERRTABLE", 11,
"GROUP_CURSOR", 12,
"GROUP_ICON", 14,
"NAMETABLE", 15,
"VERSION", 16
};
typedef struct CustResTemplate
{
enum LOCALIZABLE_TYPES iType;
unsigned uSize;
struct CustResTemplate far *pNext;
} CUSTRESTEMPLATE;
typedef struct CustResNode
{
BYTE bTypeFlag; /* Indicat's if ID or string */
BYTE bNameFlag; /* Indicat's if ID or string */
WORD wTypeID;
WORD wNameID;
TCHAR *pszType;
TCHAR *pszName;
CUSTRESTEMPLATE far *pTemplate;
struct CustResNode far *pNext;
} CUSTRESNODE;
typedef CUSTRESTEMPLATE far * FPCUSTRESTEMPLATE;
typedef CUSTRESNODE far * FPCUSTRESNODE;
CUSTRESNODE far *pCustResList = NULL;
#define SYMBOLSIZE 255
int fUseSavedSymbol = FALSE;
int *piLineNumber = NULL;
CHAR szSavedSymbol[ SYMBOLSIZE];
/*
* Function Predefinitions:
*/
static int GetResourceType( CHAR sz[]);
static int AddStructureElement( int iType,
int nSize,
FPCUSTRESTEMPLATE *ppCRT,
int fMerge);
#ifdef RLWIN32
static void AddToW( TCHAR *sz, int *c, int lTarget, TCHAR ch);
static TCHAR *CheckBufSizeW(
int *lTarget, //... Length of output buffer
int cOutBufLen, //... Bytes already used in output buffer
int cDelta, //... # characters we want to add to output buffer
TCHAR *szOutBuf); //... ptr to output buffer
#endif
static CHAR *CheckBufSize(
int *lTarget, //... Length of output buffer
int cOutBufLen, //... Bytes already used in output buffer
int cDelta, //... # characters we want to add to output buffer
CHAR *szOutBuf); //... ptr to output buffer
static void AddTo( CHAR *sz, int *c, int lTarget, CHAR ch);
static int UngetSymbol( CHAR sz[]);
static int GetNextSymbol( CHAR sz[], unsigned n, FILE *f);
static int ParseBlock( FILE *f, FPCUSTRESTEMPLATE *ppCRT);
static CUSTRESNODE far * MatchResource( RESHEADER Resheader);
static void far * GetResData( enum LOCALIZABLE_TYPES wType,
unsigned uSize,
FILE *f,
DWORD *lSize);
static int PutResData( void far *pData,
enum LOCALIZABLE_TYPES wType,
unsigned uSize,
FILE *f);
static void far * GetTextData( enum LOCALIZABLE_TYPES wType,
unsigned uSize,
TCHAR sz[]);
static int PutTextData( void far *pData,
enum LOCALIZABLE_TYPES wType,
unsigned uSize,
TCHAR sz[],
int l);
int atoihex( CHAR sz[]);
/** Function: GetResourceType
* Returns the value of the number or resource type in sz.
*
* Arguments:
* sz, string containing either a positive number or a resource type
*
* Returns:
* value in resource
*
* Error Codes:
* -1 if illegal value
*
* History:
* 1/92 - initial implementation -- SteveBl
**/
static int GetResourceType( CHAR sz[])
{
int i;
if (sz[0] >= '0' && sz[0] <= '9')
{
return atoi(sz);
}
for (i = sizeof(rgResourceTypes)/sizeof(RESOURCETYPES);i--;)
{
if ( ! lstrcmpiA( sz, rgResourceTypes[i].szType) )
{
return rgResourceTypes[i].iType;
}
}
return -1;
}
/** Function: AddStructureElement
* Adds an element's type and size to the Template list.
* If this element can be merged with the last element do so.
*
* Arguments:
* iType, how the data is interpreted
* nSize, number of bytes used by the data
* ppCRT, pointer to the next Custom Resource Template pointer
* fMerge, if true then NOTLOCALIZABLE data will be merged.
*
* Returns:
* 0 - if successful
* !0 - if unsuccessful
*
* Error Codes:
* 1 - out of memory
*
* History:
* 1/92 - initial implementation -- SteveBl
**/
static int AddStructureElement(
int iType,
int nSize,
FPCUSTRESTEMPLATE *ppCRT,
int fMerge)
{
if ( fMerge
&& ((iType == NOTLOCALIZABLE && (*ppCRT)->iType == NOTLOCALIZABLE)
|| (iType == NOTLOCALIZABLESZ && (*ppCRT)->iType == NOTLOCALIZABLESZ)
|| (iType == NOTLOCALIZABLEWSZ && (*ppCRT)->iType == NOTLOCALIZABLEWSZ)))
{
// combine this with the last one
(*ppCRT)->uSize+=nSize;
return 0;
}
// can't be combined with previous element
(*ppCRT)->pNext = (CUSTRESTEMPLATE far *)FALLOC( sizeof( CUSTRESTEMPLATE));
(*ppCRT) = (*ppCRT)->pNext;
if (!*ppCRT)
{
return 1;
}
(*ppCRT)->iType = iType;
(*ppCRT)->uSize = nSize;
(*ppCRT)->pNext = NULL;
return 0;
}
/**
* Function: UngetSymbol
* Causes GetNextSymbol to get this symbol next time.
*
* Arguments:
* sz, string buffer for symbol
*
* Returns:
* 0 - if successful
* 1 - if unsuccessful
*
* Error Codes:
* 1 - tried to unget two symbols in a row
*
* History:
* 1/92 - initial implementation -- SteveBl
*
**/
static int UngetSymbol( CHAR sz[])
{
if ( fUseSavedSymbol )
{
return 1; // can only unget one symbol
}
fUseSavedSymbol = 1;
CopyMemory( szSavedSymbol, sz, min( sizeof( szSavedSymbol) - 1, lstrlenA( sz)));
szSavedSymbol[ sizeof( szSavedSymbol) - 1] = '\0';
return( 0);
}
/**
* Function: GetNextSymbol
* Retrieves the next symbol from the file f.
* Whitespace and comments are removed.
* Comments are delimited by either c type comments or
* # (in which case comment extends until end of line)
* If the fUseSavedSymbol flag is set then it gets its symbol
* from szSavedSymbol instead of the file.
*
* Arguments:
* sz - string buffer for next symbol
* n - size of buffer
* f - handle to the input file
*
* Returns:
* 0 if successful with symbol in sz
* 1 if unsuccessful (sz undefined)
*
* Error Codes:
* 1 - eof
*
* History:
* 1/92 - initial implementation -- SteveBl
**/
static int GetNextSymbol( CHAR sz[], unsigned n, FILE *f)
{
unsigned c = 0;
CHAR ch, chLast;
if ( fUseSavedSymbol )
{
CopyMemory( sz, szSavedSymbol, min( (int)n, lstrlenA( szSavedSymbol) + 1));
sz[ n == 0 ? 0 : n - 1] = '\0';
fUseSavedSymbol = FALSE;
return 0;
}
do
{
if (feof(f)) return 1;
ch = (CHAR) getc(f);
if (ch == '\n')
++*piLineNumber;
}
while ((ch == ' ') ||
(ch == '\n') ||
(ch == '\t') ||
(ch == '\f') ||
(ch == '\r') ||
(ch == (CHAR)-1));
if (ch == '#') // commented rest of line
{
do
{
if (feof(f))
{
return 1;
}
ch = (CHAR) getc(f);
} while (ch != '\n');
++*piLineNumber;
return GetNextSymbol( sz, n, f);
}
if (ch == '"') // it is a label, parse to the next quote
{
do
{
if (c<n)
{
sz[c++]=ch; // write all but the last quote
}
if (feof(f))
{
return 1;
}
ch = (CHAR)getc(f);
if (ch == '\n')
{
return 1;
}
} while (ch != '"');
if (c<n)
{
sz[ c++] = '\0';
}
else
{
sz[ n == 0 ? 0 : n - 1] = '\0';
}
return 0;
}
if (ch == '/') // possible comment
{
if (feof(f))
{
return 1;
}
ch = (CHAR) getc(f);
if (ch == '/') // commented rest of line
{
do
{
if (feof(f))
{
return 1;
}
ch = (CHAR) getc(f);
} while (ch != '\n');
++*piLineNumber;
return( GetNextSymbol( sz, n, f));
}
if (ch == '*') // commented until */
{
if (feof(f))
{
return 1;
}
ch = (CHAR) getc(f);
if (ch == '\n')
{
++*piLineNumber;
}
do
{
chLast = ch;
if (feof(f))
{
return 1;
}
ch = (CHAR) getc(f);
if (ch == '\n')
++*piLineNumber;
} while (!(chLast == '*' && ch == '/'));
return( GetNextSymbol( sz, n, f));
}
ungetc(ch, f);
}
// finally found the beginning of a symbol
if (ch < '0' || (ch > '9' && ch < '@')
|| (ch > 'Z' && ch < 'a') || ch > 'z')
{
if (c<n)
{
sz[c++] = ch;
}
if (c<n)
{
sz[c] = '\0';
}
else
{
sz[ n == 0 ? 0 : n - 1] = 0;
}
return 0;
}
do
{
if (c<n)
{
sz[c++]=ch;
}
if (feof(f))
{
return 0;
}
ch = (CHAR) getc(f);
} while((ch >= '0' && ch <= '9') ||
(ch >= '@' && ch <= 'Z') ||
(ch >= 'a' && ch <= 'z'));
ungetc(ch, f);
if (c<n)
{
sz[c] = '\0';
}
else
{
sz[ n == 0 ? 0 : n - 1] = '\0';
}
return 0;
}
/**
* Function: ParseBlock
* Parses a block of a custom resource description from just after the
* first curly braces { to just after the closing curly braces } .
* It returns the size of the block it just parsed (in bytes).
*
* Arguments:
* f, handle to an open description file
* ppCRT, pointer to a pointer to the next Custom Resource Template node.
*
* Returns:
* Updated pointer to the next Custom Resource Template node.
* Number of bytes in this block.
* (<0 if there was an error)
*
* Error Codes:
* -1 - Syntax error
* -2 - Unexpected end of file
* -3 - out of memory
*
* History:
* 1/92 - initial implementation -- SteveBl
*/
static int ParseBlock( FILE *f, FPCUSTRESTEMPLATE * ppCRT)
{
int c = 0; // size of the whole block
int n = 0; // size of the current item
int i; //scratch variable
int fUnsigned;
int fLong;
int iType; // type of the current item
int nElements; // size of the array (if one exists)
CHAR szSymbol[SYMBOLSIZE], sz[SYMBOLSIZE];
CUSTRESTEMPLATE far * pFirst,
// saves the first one so we know where to count
// from in case of an array
far *pTemp, far *pEnd;
int fMerge = 0;
// it's only ok to merge after the first element has been written
while (1)
{
pFirst = *ppCRT;
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
if (szSymbol[0] == '}')
{
return c;
}
if ( ! lstrcmpiA( "near", szSymbol) )
{ // near * type
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
if (szSymbol[0]!='*')
{
return -1;
}
// may want to check for a legal type here
do
{
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
} while ((szSymbol[0] != '[') &&
(szSymbol[0] != '}') &&
(szSymbol[0] != ','));
UngetSymbol(szSymbol);
n = 2;
iType = NOTLOCALIZABLE;
if (AddStructureElement(iType, n, ppCRT, fMerge))
{
return -3;
}
}
else
{
if ( ! lstrcmpiA( "far", szSymbol) )
{ // far * type
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
if (szSymbol[0] != '*')
{
return -1;
}
// may want to check for a legal type here
do
{
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
} while ((szSymbol[0] != '[') &&
(szSymbol[0] != '}') &&
(szSymbol[0] != ','));
UngetSymbol(szSymbol);
n = 4;
iType = NOTLOCALIZABLE;
if(AddStructureElement(iType, n, ppCRT, fMerge))
{
return -3;
}
}
else
{
if (szSymbol[0] == '*')
{ // * type
// may want to check for a legal type here
do
{
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
} while ((szSymbol[0] != '[') &&
(szSymbol[0] != '}') &&
(szSymbol[0] != ','));
UngetSymbol(szSymbol);
n = 2;
iType = NOTLOCALIZABLE;
if(AddStructureElement(iType, n, ppCRT, fMerge))
{
return -3;
}
}
else
{
if (szSymbol[0] == '{')
{
n = ParseBlock(f, ppCRT);
if (n<0)
{
return n;
}
}
else
{ //it must be in our list of types
fUnsigned = 0;
fLong = 0;
if ( ! lstrcmpiA( "UNSIGNED", szSymbol) )
{ // unsigned
if ( GetNextSymbol( sz, sizeof( sz), f) )
{
return -2;
}
if (sz[0] == '[' || sz[0] == ',')
{
UngetSymbol(sz);
}
else
{
lstrcpyA( szSymbol, sz);
if ( lstrcmpiA( sz, "SHORT")
&& lstrcmpiA( sz, "LONG")
&& lstrcmpiA( sz, "CHAR")
&& lstrcmpiA( sz, "TCHAR")
&& lstrcmpiA( sz, "INT") )
{
// must be followed by one of these
return -1;
}
}
fUnsigned = 1;
}
else
{
if ( ! lstrcmpiA( "SIGNED", szSymbol) )
{ // signed
if ( GetNextSymbol( sz, sizeof( sz), f) )
{
return -2;
}
if (sz[0] == '[' || sz[0] == ',')
{
UngetSymbol(sz);
}
else
{
lstrcpyA( szSymbol, sz);
if ( lstrcmpiA( sz, "SHORT")
&& lstrcmpiA( sz, "LONG")
&& lstrcmpiA( sz, "CHAR")
&& lstrcmpiA( sz, "TCHAR")
&& lstrcmpiA( sz, "INT") )
{
// must be followed by one of these
return -1;
}
}
}
}
if ( ! lstrcmpiA( "SHORT", szSymbol) )
{ // short
if ( GetNextSymbol( sz, sizeof( sz), f) )
{
return -2;
}
if (sz[0] == '[' || sz[0] == ',')
{
UngetSymbol(sz);
}
else
{
lstrcpyA( szSymbol, sz);
if ( lstrcmpiA( sz, "INT") )
{
// must be followed by one of these
return -1;
}
}
}
else
{
if ( ! lstrcmpiA( "LONG", szSymbol) )
{ // long
if ( GetNextSymbol( sz, sizeof( sz), f) )
{
return -2;
}
if (sz[0] == '[' || sz[0] == ',')
{
UngetSymbol(sz);
}
else
{
lstrcpyA( szSymbol, sz);
if ( lstrcmpiA( sz, "INT")
&& lstrcmpiA( sz, "DOUBLE"))
{
// must be followed by one of these
return -1;
}
}
// BUG! - this code allows UNSIGNED LONG DOUBLE
// which is an illegal type in c. But it's not
// a serious bug so I'll leave it.
fLong = 1;
}
}
i = sizeof(rgTypeSizes)/sizeof(TYPESIZES);
do
{
--i;
} while ( lstrcmpiA( szSymbol, rgTypeSizes[i].szType) && i);
if ( lstrcmpiA( szSymbol, rgTypeSizes[i].szType) )
{
return -1; // type not found in the list
}
if (fLong)
{
n = rgTypeSizes[i].iLongSize;
}
else
{
n = rgTypeSizes[i].iShortSize;
}
iType = rgTypeSizes[i].iType;
if (fUnsigned)
{
iType+=LT_UNSIGNED;
}
if ( lstrcmpA( szSymbol, rgTypeSizes[i].szType) )
{
iType = NOTLOCALIZABLE; // type was not in all caps
}
if ( lstrcmpiA( szSymbol, "CHAR") == 0
|| lstrcmpiA( szSymbol, "TCHAR") == 0
|| lstrcmpiA( szSymbol, "WCHAR") == 0 )
{ // check for a string
lstrcpyA( szDHW, szSymbol); // So can be used later
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
if (szSymbol[0] == '[') // we have a string
{
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
if (szSymbol[0] == ']') // null terminated string
{
n = 0;
if (iType != NOTLOCALIZABLE)
{
if ( lstrcmpiA( szDHW, "CHAR") == 0 )
{
iType += LT_SZ-LT_CHAR;
}
else if ( lstrcmpiA( szDHW,
"WCHAR") == 0 )
{
iType += LT_WSZ-LT_WCHAR;
}
else
{
#ifdef RLRES32
iType += LT_WSZ-LT_WCHAR;
#else
iType += LT_SZ-LT_CHAR;
#endif
}
}
else
{
if ( lstrcmpiA( szDHW, "CHAR") == 0 )
{
iType = NOTLOCALIZABLESZ;
}
else if ( lstrcmpiA( szDHW,
"WCHAR") == 0 )
{
iType = NOTLOCALIZABLEWSZ;
}
else
{
#ifdef RLWIN32
iType = NOTLOCALIZABLEWSZ;
#else
iType = NOTLOCALIZABLESZ;
#endif
}
}
}
else
{
i = atoi(szSymbol);
if (i<1)
{
return -1;
}
n *= i;
if (iType != NOTLOCALIZABLE)
{
if ( lstrcmpiA( szDHW, "CHAR") == 0 )
{
iType += LT_STRING-LT_CHAR;
}
else if ( lstrcmpiA( szDHW,
"WCHAR") == 0 )
{
iType += LT_WSTRING-LT_WCHAR;
}
else
{
#ifdef RLRES32
iType += LT_WSTRING-LT_WCHAR;
#else
iType += LT_STRING-LT_CHAR;
#endif
}
}
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
if (szSymbol[0] != ']')
{
return -1;
}
}
}
else
{
UngetSymbol(szSymbol);
}
}
if(AddStructureElement(iType, n, ppCRT, fMerge))
{
return -3;
}
}
}
}
}
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
while (szSymbol[0] == '[')
{// we have an array
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
if ((szSymbol[0] < '0' || szSymbol[0] > '9') && szSymbol[0] != ']')
{
return -1;
}
nElements = atoi(szSymbol);
if (nElements < 1)
{
return -1;
}
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
if (szSymbol[0] != ']')
{
return -1;
}
pEnd = *ppCRT;
if (pEnd != pFirst)
{
for (i=nElements-1;i--;)
{
pTemp = pFirst;
do
{
pTemp = pTemp->pNext;
AddStructureElement(pTemp->iType,
pTemp->uSize,
ppCRT,
0);
} while (pTemp != pEnd);
}
}
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), f) )
{
return -2;
}
}
c += n;
if (szSymbol[0] == '}')
{
return c;
}
if (szSymbol[0] != ',')
{
return -1;
}
fMerge = 1;
}
}
//+-------------------------------------------------------------------------
//
// Function: LoadCustResDescriptions, Public
//
// Synopsis: Loads the Cusutom Resource Descriptions defined in the RDF
// files, to all the tokenize to parse them.
//
//
// Arguments: [szFileName] The RDF file containing the resource
// descriptions.
//
//
// Effects: The custom resources are loaded into a global list of
// resource descriptions, and used by ReadWinRes to tokenize
// the particular custom resources
//
// Returns: -1 Error Condition
// 1 Resource descrptions loaded
//
//
//
//
// Modifies: [pCustResList] Global list of Custom resource descriptions.
//
// History:
// 16-Oct-92 Created TerryRu
//
//
// Notes: ParseResourceDescriptionFile is the function called to
// actually load the descriptions resources.
//
//--------------------------------------------------------------------------
int LoadCustResDescriptions( CHAR *szRDFs)
{
FILE *fRdf = NULL;
CHAR szCurRDF[MAXFILENAME] = "";
int i1, i2;
if (szRDFs && *szRDFs) //... resource description file name given?
{
i1 = 0;
while (szRDFs[i1] == ' ' && szRDFs[i1] != 0)
{
++i1;
}
while (szRDFs[i1] != 0)
{
i2 = 0;
while (szRDFs[i1] != ' ' && szRDFs[i1] != 0)
{
szCurRDF[i2++] = szRDFs[i1++];
}
szCurRDF[i2] = 0;
while (szRDFs[i1] == ' ' && szRDFs[i1] != 0)
{
++i1;
}
if (fRdf = FOPEN( szCurRDF, "rt"))
{
ParseResourceDescriptionFile(fRdf, &i2);
FCLOSE(fRdf);
}
else
{
return(-1);
}
}
}
return(1); //... Success
}
/**
* Function: ParseResourceDescriptionFile
* Parses a resource description block creating a structure definining
* all recognized custom resources.
*
* Arguments:
* ResourceDescriptionFile, handle to an open description file
* (or the beginning of a description block)
* piErrorLine, pointer to an integer that will hold the line number
* an error occured at in the event that a parsing error is
* encountered.
*
* Returns:
* 0 if successful
* !0 if some error was encountered
* *piErrorLine will hold the line number for the error
*
* Error Codes:
* -1 - Syntax error
* -2 - Unexpected end of file
* -3 - out of memory
*
* History:
* 1/92 - initial implementation -- SteveBl
*
**/
int ParseResourceDescriptionFile(
FILE *pfResourceDescriptionFile,
int *piErrorLine)
{
CUSTRESNODE far * lpCustResNode = NULL;
CUSTRESTEMPLATE far * pCustResTemplate;
static CHAR szSymbol[SYMBOLSIZE];
/*************************************************************************
TCHAR *szResourceType;
*************************************************************************/
int iResourceType;
int r;
BOOL fBeginList = TRUE;
// position lpCustResNode at end of the custom reosource list.
if ( lpCustResNode == NULL )
{
pCustResList = lpCustResNode =
(CUSTRESNODE far *)FALLOC( sizeof( CUSTRESNODE));
}
else
{
fBeginList = FALSE;
lpCustResNode = pCustResList;
while ( lpCustResNode->pNext )
{
lpCustResNode = lpCustResNode->pNext;
}
}
piLineNumber = piErrorLine;
*piLineNumber = 1;
if ( GetNextSymbol( szSymbol,
sizeof( szSymbol),
pfResourceDescriptionFile) )
{
return 0; // file is empty
}
while ( lstrcmpiA( szSymbol, "END") )
{
if ( szSymbol[0] != '<' )
{
return -1; // must begin with a resource number
}
if ( fBeginList == FALSE )
{
lpCustResNode->pNext =
(CUSTRESNODE far *)FALLOC( sizeof( CUSTRESNODE));
lpCustResNode = lpCustResNode->pNext;
}
fBeginList = FALSE;
// intialize nodes fields to Zero defaults.
memset( lpCustResNode, 0, sizeof( CUSTRESNODE));
//... Next symbol will be the resource type
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), pfResourceDescriptionFile) )
{
return -2; // need a number
}
//... Is type a string or a number?
if ( szSymbol[0] != '"' )
{ //... number
iResourceType = GetResourceType( szSymbol);
if ( iResourceType < 0 )
{
return -1;
}
lpCustResNode->wTypeID = (WORD)iResourceType;
lpCustResNode->bTypeFlag = TRUE;
}
else //... string
{
UINT uChars = lstrlenA( szSymbol+1) + 1;
lpCustResNode->pszType = (TCHAR *)FALLOC( MEMSIZE( uChars));
if ( lpCustResNode->pszType == NULL )
{
return -3;
}
_MBSTOWCS( lpCustResNode->pszType, szSymbol+1, uChars, (UINT)-1);
lpCustResNode->bTypeFlag = FALSE;
}
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), pfResourceDescriptionFile) )
{
return -2;
}
/*************************************************************************
//... Is a name provided?
if (szSymbol[0] != '>' && szSymbol[0] != ',')
{
return -1; // must have closing symbol for resource id #
}
if (szSymbol[0] == ',')
{ //... Yes, name is provided
if (iResourceType >= 0)
{
lpCustResNode->wNameID = (WORD)iResourceType;
lpCustResNode->bNameFlag = TRUE;
}
else
{
lpCustResNode->wTypeID = 0;
lpCustResNode->wNameID = IDFLAG;
lpCustResNode->pszType = szResourceType;
lpCustResNode->bTypeFlag = 0;
}
}
else
{
if (iResourceType >= 0)
{
lpCustResNode->wNameID = iResourceType;
}
else
{
lpCustResNode->wNameID = 0;
lpCustResNode->pszName = szResourceType;
lpCustResNode->bNameFlag = 0xff;
}
if (GetNextSymbol(szSymbol, sizeof( szSymbol), pfResourceDescriptionFile))
{
return -2;
}
if (szSymbol[0] != '"')
{
r = GetResourceType(szSymbol);
lpCustResNode->wTypeID = (WORD)r;
}
else
{
lpCustResNode->wTypeID = 0;
lpCustResNode->bTypeFlag = 0;
szResourceType = (TCHAR *)FALLOC(
MEMSIZE( (strlen( szSymbol + 1) + 1)));
strcpy((PCHAR)szResourceType, szSymbol+1);
lpCustResNode->pszType = szResourceType;
}
if (GetNextSymbol(szSymbol, sizeof( szSymbol), pfResourceDescriptionFile))
{
return -2;
}
if (szSymbol[0] != '>')
{
return -1;
}
}
*************************************************************************/
// Start the template by creating a single empty node
// This is necessary for handling recursive arrays.
// There might be a way around it but this works and it is easy.
lpCustResNode->pTemplate=
(FPCUSTRESTEMPLATE)FALLOC( sizeof( CUSTRESTEMPLATE));
if (!lpCustResNode->pTemplate)
{
return -3;
}
pCustResTemplate = (lpCustResNode->pTemplate);
pCustResTemplate->iType = NOTLOCALIZABLE;
pCustResTemplate->uSize = 0;
pCustResTemplate->pNext = NULL;
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), pfResourceDescriptionFile) )
{
return -2;
}
if (szSymbol[0] != '{')
{
return -1; // must have at least one block
}
r = ParseBlock( pfResourceDescriptionFile,
(FPCUSTRESTEMPLATE *)&pCustResTemplate);
if (r < 0)
{
return r;
}
// Now remove that initial empty node (not necessary but cleaner)
pCustResTemplate = lpCustResNode->pTemplate;
lpCustResNode->pTemplate = pCustResTemplate->pNext;
RLFREE( pCustResTemplate);
// the last thing the ParseBlock routine should have read in was a
// closing brace to close the block. The next thing we read should
// either be "end", the end of file, or a new resource definition.
if ( GetNextSymbol( szSymbol, sizeof( szSymbol), pfResourceDescriptionFile) )
{
return 0; // reached end of file
}
}
return 0;
}
/**
* Function: GetCustomResource
* Reads a custom resource from the resource file and returns a pointer
* to the resource data.
*
* Arguments:
* inResFile, handle to an open resource file
* lSize, size in bytes of the resource
* ppCustomResource, address of a pointer to an empty custom resource
* structure
* ResHeader, resource header for this resource
*
* Returns:
* if resource has a definition:
* returns 0 and
* inResFile containing a linked list of the localizable resource data
* else
* returns 1
*
* Error Codes:
* 0 - no error -- resource was retrieved
* 1 - resource is not an understood custom resource (use another method
* or ignore the resource)
* 2 - some error occured parsing the resource
*
* History:
* 1/92 - initial implementation -- SteveBl
*
**/
int GetCustomResource(
FILE *inResFile,
DWORD *plSize,
FPCUSTOM_RESOURCE *ppCustomResource,
RESHEADER ResHeader)
{
CUSTOM_RESOURCE far *lpCustomResource;
CUSTRESNODE far *pCRN;
CUSTRESTEMPLATE far *pCRT;
void far * pData;
BOOL fBeginList = TRUE;
if ( ! (pCRN = MatchResource( ResHeader)) )
{
return 1; // resource doesn't have a match
}
*ppCustomResource = lpCustomResource =
(CUSTOM_RESOURCE far *)FALLOC( sizeof( CUSTOM_RESOURCE));
pCRT = pCRN->pTemplate;
while ( *plSize )
{
// allocate new custome resrouce structure
if ( fBeginList == FALSE )
{
lpCustomResource->pNext =
(CUSTOM_RESOURCE far *)FALLOC( sizeof( CUSTOM_RESOURCE));
lpCustomResource = lpCustomResource->pNext;
}
if ( ! lpCustomResource )
{
return 2; // no memory
}
pData = GetResData( pCRT->iType, pCRT->uSize, inResFile, plSize);
if ( ! pData )
{
return 2; //GetResData crapped out
}
lpCustomResource->pData = pData;
lpCustomResource->pNext = NULL;
fBeginList = FALSE;
pCRT = pCRT->pNext;
if (!pCRT)
{
pCRT = pCRN->pTemplate; //begin next structure
}
}
return 0;
}
/**
* Function: TokCustomResource
* Writes custom resource information to the token file.
*
* Arguments:
* TokFile, handle to the token file
* ResHeader, resource header for this resource
* ppCustomResource, address of a pointer to a filled out
* custom resource structure
*
* Returns:
* Data written to TokFile
*
* Error Codes:
* none
*
* History:
* 1/92 - initial implementation -- SteveBl
*
* 01/93 - Add support for var length Token texts MHotchin
*
**/
void TokCustomResource(
FILE *TokFile,
RESHEADER ResHeader,
FPCUSTOM_RESOURCE *ppCustomResource)
{
CUSTRESNODE far *pCRN;
CUSTRESTEMPLATE far *pCRT;
CUSTOM_RESOURCE far *lpCustomResource;
TCHAR sz[ MAXTEXTLEN];
TOKEN Token;
WORD wID = 0;
int l;
lpCustomResource = *ppCustomResource;
if (!(pCRN = MatchResource(ResHeader)))
{
QuitT( IDS_ENGERR_09, (LPTSTR)IDS_NOCUSTRES, NULL);
}
pCRT = pCRN->pTemplate;
while ( lpCustomResource )
{
if ( pCRT->iType != NOTLOCALIZABLE
&& pCRT->iType != NOTLOCALIZABLESZ
&& pCRT->iType != NOTLOCALIZABLEWSZ )
{
if ( PutTextData( lpCustomResource->pData,
pCRT->iType,
pCRT->uSize,
sz,
sizeof( sz)) )
{
QuitT( IDS_ENGERR_09, (LPTSTR)IDS_CUSTRES, NULL);
}
/* UNCOMMENT THIS WHEN STRING TYPES ARE SUPPORTED IN TOKENS
**********
Token.szType[0] = '\0';
if (!ResHeader.bTypeFlag)
{
Token.wType = IDFLAG;
_tcscpy( Token.szType, ResHeader.pszType);
}
else
**********
*/
Token.wType = ResHeader.wTypeID;
Token.wName = ResHeader.wNameID;
if ( ResHeader.bNameFlag == IDFLAG )
{
lstrcpy( Token.szName, ResHeader.pszName);
}
else
{
Token.szName[0] = '\0';
}
Token.wID = wID++;
Token.wReserved = (gbMaster ? ST_NEW : ST_TRANSLATED);
Token.wFlag = 0;
if ( (pCRT->iType == LT_UNSIGNED + LT_STRING)
|| (pCRT->iType == LT_STRING)
|| (pCRT->iType == LT_WSTRING) )
{
l = pCRT->uSize;
while( l > 1 && ! sz[l-1])
{
--l; // skip any trailing nulls
}
Token.szText = BinToText( sz, l);
}
else
{
Token.szText = BinToText( sz, lstrlen( sz));
}
PutToken( TokFile, &Token);
RLFREE( Token.szText);
}
pCRT = pCRT->pNext;
if ( ! pCRT )
{
pCRT = pCRN->pTemplate; //begin next structure
}
lpCustomResource = lpCustomResource->pNext;
}
}
/**
* Function: PutCustomResource
* Writes custom resource information to the output resource
* file. If the information is localizable it is retrieved from the
* indicated token file.
*
* Arguments:
* OutResFile, handle to the target resource file
* TokFile, handle to the token file
* ResHeader, resource header for this resource
* ppCustomResource, address of a pointer to a filled out
* custom resource structure
*
* Returns:
* CustomResource written to OutResFile
*
* Error Codes:
* none
*
* History:
* ??/?? Created by ???
*
* 01/93 Added support for var length token texts. MHotchin
*
**/
void PutCustomResource(
FILE *OutResFile,
FILE *TokFile,
RESHEADER ResHeader,
FPCUSTOM_RESOURCE *ppCustomResource)
{
CUSTRESNODE far *pCRN = NULL;
CUSTRESTEMPLATE far *pCRT = NULL;
CUSTOM_RESOURCE far *lpCustomResource = NULL;
TCHAR sz[ MAXTEXTLEN] = TEXT("");
void far *pData = NULL;
TOKEN Token;
DWORD lSize = 0;
fpos_t ResSizePos;
WORD wID=0;
unsigned n;
lpCustomResource = *ppCustomResource;
if ( ! (pCRN = MatchResource( ResHeader)) )
{
QuitT( IDS_ENGERR_09, (LPTSTR)IDS_NOCUSTRES, NULL);
}
if ( PutResHeader( OutResFile, ResHeader, &ResSizePos, &lSize) )
{
QuitT( IDS_ENGERR_06, (LPTSTR)IDS_CUSTRES, NULL);
}
lSize = 0;
pCRT = pCRN->pTemplate;
while ( lpCustomResource )
{
BOOL fAlloced = FALSE;
if ( pCRT->iType != NOTLOCALIZABLE
&& pCRT->iType != NOTLOCALIZABLESZ
&& pCRT->iType != NOTLOCALIZABLEWSZ )
{
/* UNCOMMENT THIS WHEN STRING TYPES ARE SUPPORTED IN TOKENS
*
Token.szwType[0] = '\0';
if (!ResHeader.bTypeFlag)
{
Token.wType = IDFLAG;
_tcscpy(Token.szwType, ResHeader.pszType);
}
else
*
*/
Token.wType = ResHeader.wTypeID;
Token.wName = ResHeader.wNameID;
if ( ResHeader.bNameFlag == IDFLAG )
{
lstrcpy( Token.szName, ResHeader.pszName);
}
else
{
Token.szName[0] = '\0';
}
Token.wID = wID++;
Token.wFlag = 0;
Token.wReserved =(gbMaster ? ST_NEW : ST_TRANSLATED);
Token.szText = NULL;
if ( ! FindToken( TokFile, &Token, ST_TRANSLATED) )
{
QuitT( IDS_ENGERR_06, (LPTSTR)IDS_NOCUSTRES, NULL);
}
n = TextToBin( sz, Token.szText, sizeof( sz));
RLFREE( Token.szText);
while ( n < pCRT->uSize )
{
sz[n++]='\0'; // padd additional space with nulls
}
pData = GetTextData( pCRT->iType, pCRT->uSize, sz);
if ( ! pData)
{
QuitT( IDS_ENGERR_09, (LPTSTR)IDS_CUSTRES, NULL);
}
fAlloced = TRUE;
}
else
{
pData = lpCustomResource->pData;
fAlloced = FALSE;
}
lSize += PutResData( pData, pCRT->iType, pCRT->uSize, OutResFile);
if ( fAlloced )
{
RLFREE( pData);
}
pCRT = pCRT->pNext;
if ( ! pCRT )
{
pCRT = pCRN->pTemplate; //begin next structure
}
lpCustomResource = lpCustomResource->pNext;
}
if( ! UpdateResSize( OutResFile, &ResSizePos, lSize) )
{
QuitT( IDS_ENGERR_07, (LPTSTR)IDS_CUSTRES, NULL);
}
}
/**
* Function: ClearCustomResource
* Frees memory allocated to a custom resource list.
*
* Arguments:
* ppCustomResource, address of a pointer to a filled out
* custom resource structure
*
* Returns:
* Memory allocatd to pCustomResource is freed.
*
* Error Codes:
* none
*
* History:
* 1/92 -- initial implementation -- SteveBl
*
**/
void ClearCustomResource( FPCUSTOM_RESOURCE *ppCustomResource)
{
CUSTOM_RESOURCE far *pCR;
CUSTOM_RESOURCE far *lpCustomResource;
lpCustomResource = *ppCustomResource;
while ( lpCustomResource )
{
pCR = lpCustomResource;
RLFREE( pCR->pData);
lpCustomResource = pCR->pNext;
RLFREE( pCR);
}
}
/**
* Function:
* Tries to find a custom resource that matches the resource specified
* in the resource header.
*
* Arguments:
* Resheader, resource header.
*
* Returns:
* pointer to the resource template (or null)
*
* Error Codes:
* null -- resource not found
*
* History:
* 1/92 -- initial implementation -- SteveBl
*
**/
static CUSTRESNODE far * MatchResource( RESHEADER Resheader)
{
CUSTRESNODE far *pCR = pCustResList;
while ( pCR )
{
if ( (0==pCR->bTypeFlag) == (0==Resheader.bTypeFlag) )
{
if ( ((!pCR->bTypeFlag) && ! _tcscmp( pCR->pszType,
Resheader.pszType))
|| ((pCR->bTypeFlag) && pCR->wTypeID == Resheader.wTypeID))
{ // TYPES MATCH
/*************************************************************************
if (pCR->wNameID == IDFLAG)
{
pCRTypeMatch = pCR;
}
else
{
if ((0==pCR->bNameFlag) == (0==Resheader.bNameFlag))
{
if (((!pCR->bNameFlag)
&& ! _tcscmp(pCR->pszName, Resheader.pszName)) ||
((pCR->bNameFlag) &&
pCR->wNameID == Resheader.wNameID))
{ // NAMES MATCH
*************************************************************************/
return( pCR); // an exact match
/*************************************************************************
}
}
}
*************************************************************************/
}
}
pCR = pCR->pNext;
}
return( NULL); // either only the type matched or nothing matched
}
/**
* Function: GetResData
* Reads data of the specified type and size from a resource file.
*
* Arguments:
* wType, type of this resource (from resource template)
* uSize, size in bytes of resource (ignored for null terminated strings)
* f, resource file
* lSize, pointer to the number of bytes left in the resource
*
* Returns:
* pointer to the data, lSize is updated
*
* Error Codes:
* null pointer on error
*
* History:
* 1/92 -- initial implementation -- SteveBl
*
**/
static void far * GetResData(
enum LOCALIZABLE_TYPES wType,
unsigned uSize,
FILE *f,
DWORD *lSize)
{
BYTE *pData = NULL;
int i = 0;
if ( wType % LT_UNSIGNED == LT_SZ
|| wType == NOTLOCALIZABLESZ
|| wType % LT_UNSIGNED == LT_WSZ
|| wType == NOTLOCALIZABLEWSZ )
{ // read in the null terminated string
TCHAR ch = IDFLAG;
pData = FALLOC( MEMSIZE(*lSize) );
while ( *lSize && ch != TEXT('\0') )
{
#ifdef RLWIN32
if ( wType % LT_UNSIGNED == LT_WSZ
|| wType == NOTLOCALIZABLEWSZ )
{
((TCHAR *)pData)[i] = ch = GetWord( f, lSize);
}
else
{
char chTmp[2];
chTmp[0] = GetByte( f, lSize);
if ( IsDBCSLeadByte( chTmp[0]) )
{
chTmp[1] = GetByte( f, lSize);
_MBSTOWCS( &((TCHAR *)pData)[i], chTmp, 1, 2);
}
else
{
_MBSTOWCS( &((TCHAR *)pData)[i], chTmp, 1, 1);
}
ch = ((TCHAR *)pData)[i];
}
#else //RLWIN32
*(pData+i) = ch = GetByte( f, lSize);
#endif //RLWIN32
i++;
} // END while( *lSize ...
}
else
{
pData = FALLOC( uSize);
if ( ! pData )
{
QuitA( IDS_ENGERR_11, NULL, NULL);
}
while (uSize-- && *lSize)
{
*(pData+i) = GetByte(f, lSize);
i++;
}
}
return( pData);
}
/**
* Function: PutResData
* Writes data of the specified type to a resource file.
*
* Arguments:
* pData, pointer to data
* wType, type of this resource (from resource template)
* uSize, size in bytes of resource (ignored for null terminated strings)
* f, resource file
*
* Returns:
* Number of bytes written.
*
* Error Codes:
* -1 - error
*
* History:
* 1/92 -- initial implementation -- SteveBl
*
**/
static int PutResData(
void far *pData,
enum LOCALIZABLE_TYPES wType,
unsigned uSize,
FILE *f)
{
DWORD dw = 0;
if ( wType % LT_UNSIGNED == LT_SZ
|| wType == NOTLOCALIZABLESZ
|| wType % LT_UNSIGNED == LT_WSZ
|| wType == NOTLOCALIZABLEWSZ )
{
// write the null terminated string
#ifdef RLWIN32
TCHAR *pChar = (TCHAR *)pData;
if ( wType % LT_UNSIGNED == LT_WSZ
|| wType == NOTLOCALIZABLEWSZ )
{
while( *pChar )
{
PutWord( f, *pChar, &dw);
pChar++;
}
PutWord( f, 0, &dw);
}
else
{
_WCSTOMBS( szDHW, pChar, DHWSIZE, lstrlen( pChar) + 1);
while( szDHW[ dw] )
{
PutByte( f, szDHW[ dw], &dw);
}
PutByte( f, 0, &dw);
}
#else //RLWIN32
while( *((BYTE far *)pData+i) )
{
PutByte( f, *((BYTE far *)pData+dw), &dw);
}
PutByte( f, 0, &dw);
#endif //RLWIN32
}
else
{
while( dw < uSize)
{
PutByte( f, *((BYTE far *)pData+dw), &dw);
}
}
return( (int)dw);
}
/**
* Function: GetTextData
* Reads data of the specified type and size from a string.
*
* Arguments:
* wType, type of this resource (from resource template)
* uSize, size in bytes of resource (ignored for null terminated strings)
* sz, source string (always in Unicode if in NT version of tool)
*
* Returns:
* pointer to the data
*
* Error Codes:
* null pointer on error
*
* History:
* 1/92 -- initial implementation -- SteveBl
*
**/
static void far * GetTextData(
enum LOCALIZABLE_TYPES wType,
unsigned uSize,
TCHAR sz[])
{
PBYTE pData = NULL;
int i = 0;
if ( wType % LT_UNSIGNED == LT_WSZ
|| wType % LT_UNSIGNED == LT_SZ )
{
pData = FALLOC( MEMSIZE( MAXTEXTLEN));
}
else if ( wType % LT_UNSIGNED == LT_WSTRING
|| wType % LT_UNSIGNED == LT_STRING )
{
pData = FALLOC( MEMSIZE( uSize));
}
else
{
pData = FALLOC( uSize);
}
switch (wType)
{
case LT_CHAR:
case LT_UNSIGNED+LT_CHAR:
*pData = (BYTE) sz[0];
break;
case LT_WCHAR:
case LT_UNSIGNED+LT_WCHAR:
*((TCHAR *)pData) = sz[0];
break;
case LT_INTEGER:
if ( uSize == 2 )
{
sscanf( (PCHAR)sz, "%Fhi", pData);
}
else
{
sscanf( (PCHAR)sz, "%Fli", pData);
}
break;
case LT_UNSIGNED+LT_INTEGER:
if ( uSize == 2 )
{
sscanf( (PCHAR)sz, "%Fhu", pData);
}
else
{
sscanf( (PCHAR)sz, "%Flu", pData);
}
break;
case LT_FLOAT:
case LT_UNSIGNED+LT_FLOAT:
if ( uSize == 4 )
{
sscanf( (PCHAR)sz, "%Ff", pData);
}
else
{
sscanf( (PCHAR)sz, "%Flf", pData);
}
break;
case LT_STRING:
case LT_UNSIGNED+LT_STRING:
case LT_WSTRING:
case LT_UNSIGNED+LT_WSTRING:
for ( i = uSize; i--; )
{
*((TCHAR far *)pData + i) = sz[i];
}
break;
case LT_SZ:
case LT_UNSIGNED+LT_SZ:
case LT_WSZ:
case LT_UNSIGNED+LT_WSZ:
#ifdef RLWIN32
CopyMemory( pData, sz, MEMSIZE( min( lstrlen( sz) + 1, MAXTEXTLEN)));
#else
FSTRNCPY( (CHAR far *)pData, sz, MAXTEXTLEN);
#endif
break;
default:
RLFREE( pData);
}
return( pData);
}
/**
* Function: PutTextData
* Writes data of the specified type to a string.
*
* Arguments:
* pData, pointer to data
* wType, type of this resource (from resource template)
* uSize, size in bytes of resource (ignored for null terminated strings)
* sz, destination string
* l, length of destination string (in bytes)
*
* Returns:
* 0 - no errors
*
* Error Codes:
* 1 - error
*
* History:
* 1/92 -- initial implementation -- SteveBl
*
**/
static int PutTextData(
void far *pData,
enum LOCALIZABLE_TYPES wType,
unsigned uSize,
TCHAR sz[],
int l)
{
switch (wType)
{
case LT_CHAR:
case LT_UNSIGNED+LT_CHAR:
case LT_WCHAR:
case LT_UNSIGNED+LT_WCHAR:
CopyMemory( sz, pData, min( uSize, (UINT)l));
break;
case LT_INTEGER:
if ( uSize == 2 )
{
wsprintf( sz, TEXT("%Fhi"), pData);
}
else
{
wsprintf( sz, TEXT("%Fli"), pData);
}
break;
case LT_UNSIGNED+LT_INTEGER:
if ( uSize == 2 )
{
wsprintf( sz, TEXT("%Fhu"), pData);
}
else
{
wsprintf( sz, TEXT("%Flu"), pData);
}
break;
case LT_FLOAT:
case LT_UNSIGNED+LT_FLOAT:
if ( uSize == 4 )
{
wsprintf( sz, TEXT("%Ff"), pData);
}
else
{
wsprintf( sz, TEXT("%Flf"), pData);
}
break;
case LT_STRING:
case LT_UNSIGNED+LT_STRING:
case LT_WSTRING:
case LT_UNSIGNED+LT_WSTRING:
CopyMemory( sz, pData, uSize);
break;
case LT_SZ:
case LT_UNSIGNED+LT_SZ:
CopyMemory( sz, pData, MEMSIZE(min( lstrlen( pData) + 1, l)));
((LPSTR)sz)[ l - 1] = '\0';
break;
case LT_WSZ:
case LT_UNSIGNED+LT_WSZ:
CopyMemory( sz, pData, min( MEMSIZE( lstrlen( pData) + 1), WCHARSIN( l)));
sz[ WCHARSIN( l) - 1] = TEXT('\0');
break;
//#ifdef RLWIN32
// CopyMemory( sz, pData, l > 0 ? l * sizeof( TCHAR) : 0);
//#else
// FSTRNCPY( (CHAR far *) sz, (CHAR far *)pData, l);
//#endif
break;
default:
return( 1);
}
return( 0);
}
/**
* Function: AddTo
* Adds a character to a string at position c.
* c is then incremented only if it is still less than the maximum
* length of the target string. This is to prevent runover.
*
* Arguments:
* sz, target string
* c, pointer to current position value
* lTarget, maximum length of the target string
* ch, character to be added to the string
*/
void AddTo( CHAR *sz, int *c, int lTarget, CHAR ch)
{
sz[*c] = ch;
if (*c < lTarget)
{
(*c)++;
}
}
#ifdef RLWIN32
void AddToW( TCHAR *sz, int *c, int lTarget, TCHAR ch)
{
sz[*c] = ch;
if (*c < lTarget)
{
(*c)++;
}
}
/**
* Function: BinToTextW
* Converts a binary string to it's c representation
* (complete with escape sequences). If the target string is NULL,
* space will be allocated for it.
*
* Arguments:
* rgc, source string
* lSource, length of source string
*
* Returns:
* nothing
*
* Error Codes:
* none
*
* History:
* 1/92 -- initial implementation -- SteveBl
*
* 01/21/93 MHotchin - Made changes to allow this function to allocate
* the memory for the destination string. If the target string
* is NULL, then space will be allocated for it. The target
* string is returned to the caller.
**/
UINT _MBSTOWCS( WCHAR wszOut[], CHAR szIn[], UINT cOut, UINT cIn)
{
UINT n;
n = MultiByteToWideChar( gProj.uCodePage,
MB_PRECOMPOSED,
szIn,
cIn,
wszOut,
cOut);
return( n > 0 ? n - 1 : 0);
}
UINT _WCSTOMBS( CHAR szOut[], WCHAR wszIn[], UINT cOut, UINT cIn)
{
UINT n;
n = WideCharToMultiByte( gProj.uCodePage,
0,
wszIn,
cIn,
szOut,
cOut,
NULL,
NULL);
return( (cIn > 0 ) ? cIn - 1 : 0);
}
WCHAR * BinToTextW(
TCHAR *szInBuf, //... Input, binary, string
int lSource) //... Length of szInBuf
{
int i;
int cOutBufLen = 0;
int lTarget = 0; //... Max length of szOutBuf
TCHAR *szOutBuf = NULL; //... Output string with escape sequences
// If the target is NULL, allocate some memory. We set aside
// 5% more than the source length. MHotchin
// chngd to 5% or 5 chars if 10% is less than 50 davewi
lTarget = (lSource == 0) ? 0 : lSource + 1;
szOutBuf = (TCHAR *)FALLOC( MEMSIZE( lTarget));
for ( i = 0; i < lSource; i++ )
{
switch( szInBuf[i] )
{
case TEXT('\a'):
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 2, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('a'));
break;
case TEXT('\b'):
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 2, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('b'));
break;
case TEXT('\f'):
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 2, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('f'));
break;
case TEXT('\n'):
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 2, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('n'));
break;
case TEXT('\r'):
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 2, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('r'));
break;
case TEXT('\t'):
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 2, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('t'));
break;
case TEXT('\v'):
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 2, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('v'));
break;
case TEXT('\\'):
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 2, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
break;
default:
{
TCHAR wTmp = szInBuf[i];
if ( wTmp == 0 )
{
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 2, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('0'));
}
else if ( (wTmp >= 0 && wTmp < 32)
|| wTmp == 0x7f
|| wTmp == 0xa9
|| wTmp == 0xae )
{
CHAR szt[5];
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 4, szOutBuf);
sprintf( szt, "%#04hx", wTmp);
AddToW( szOutBuf, &cOutBufLen, lTarget, TEXT('\\'));
AddToW( szOutBuf, &cOutBufLen, lTarget, (TCHAR)(szt[0]));
AddToW( szOutBuf, &cOutBufLen, lTarget, (TCHAR)(szt[1]));
AddToW( szOutBuf, &cOutBufLen, lTarget, (TCHAR)(szt[2]));
AddToW( szOutBuf, &cOutBufLen, lTarget, (TCHAR)(szt[3]));
}
else
{
szOutBuf = CheckBufSizeW( &lTarget, cOutBufLen, 1, szOutBuf);
AddToW( szOutBuf, &cOutBufLen, lTarget, wTmp);
}
break;
}
}
}
szOutBuf[ cOutBufLen] = TEXT('\0');
return( szOutBuf);
}
#endif //RLWIN32
/** Function: atoihex
* Converts a string containing hex digits to an integer. String is
* assumed to contain nothing but legal hex digits. No error checking
* is performed.
*
* Arguments:
* sz, null terminated string containing hex digits
*
* Returns:
* value of hex digits in sz
*
* Error Codes:
* none
*
* History:
* 1/92 -- initial implementation -- SteveBl
*
*/
int atoihex( CHAR sz[])
{
int r = 0;
int i = 0;
CHAR ch;
while (sz[i])
{
r *= 16;
ch = (CHAR)toupper(sz[i++]);
if (ch<='9' && ch>='0')
{
r += ch - '0';
}
else
{
if (ch <= 'F' && ch >= 'A')
{
r += ch - 'A' + 10;
}
}
}
return r;
}
#ifdef RLRES32
/**
* Function: TextToBinW
* Converts a string with c escape sequences to a true binary string.
*
* Arguments:
* rgc, target string
* sz, source string
* l, maximum length of target string
*
* Returns:
* length of target string
*
* Error Codes:
* none
*
* History:
* 1/92 -- initial implementation -- SteveBl
* 9/92 -- changed to UNICODE-only version -- davewi
* 01/21/93 -- Changed to allow arb length strings MHotchin.
*
**/
int TextToBinW(
WCHAR szOutBuf[], //... Output, binary, string
WCHAR szInBuf[], //... Input string with escape sequences
int lTarget) //... Max length of szOutBuf
{
int i = 0;
int c = 0;
while ( szInBuf[ c] )
{
if ( szInBuf[ c] == TEXT('\\') )
{ // escape sequence!
c++;
switch ( szInBuf[ c++] )
{
case TEXT('a'):
AddToW( szOutBuf, &i, lTarget, TEXT('\a'));
break;
case TEXT('b'):
AddToW( szOutBuf, &i, lTarget, TEXT('\b'));
break;
case TEXT('f'):
AddToW( szOutBuf, &i, lTarget, TEXT('\f'));
break;
case TEXT('n'):
AddToW( szOutBuf, &i, lTarget, TEXT('\n'));
break;
case TEXT('r'):
AddToW( szOutBuf, &i, lTarget, TEXT('\r'));
break;
case TEXT('t'):
AddToW( szOutBuf, &i, lTarget, TEXT('\t'));
break;
case TEXT('v'):
AddToW( szOutBuf, &i, lTarget, TEXT('\v'));
break;
case TEXT('\''):
AddToW( szOutBuf, &i, lTarget, TEXT('\''));
break;
case TEXT('\"'):
AddToW( szOutBuf, &i, lTarget, TEXT('\"'));
break;
case TEXT('\\'):
AddToW( szOutBuf, &i, lTarget, TEXT('\\'));
break;
case TEXT('0'):
case TEXT('1'):
case TEXT('2'):
{
CHAR szt[4];
szt[0] = szt[1] = szt[2] = szt[3] = '\0';
if ( szInBuf[c-1] == TEXT('0')
&& (szInBuf[c] < TEXT('0') || szInBuf[c] > TEXT('9'))
&& szInBuf[c] != TEXT('x') && szInBuf[c] != TEXT('X') )
{
// Must be '\0'
AddToW( szOutBuf, &i, lTarget, (TCHAR)0);
}
else if ( szInBuf[c] >= TEXT('0') && szInBuf[c] <= TEXT('9') )
{
szt[0] = (CHAR)(szInBuf[c-1]);
szt[1] = (CHAR)(szInBuf[c++]);
if ( szInBuf[c] >= TEXT('0') && szInBuf[c] <= TEXT('9'))
{
szt[2] = (CHAR)(szInBuf[c++]);
}
AddToW( szOutBuf, &i, lTarget, (TCHAR)atoi( szt));
}
else if ( szInBuf[c] == TEXT('X')
|| szInBuf[c] == TEXT('x') )
{
c++;
szt[0] = (CHAR)(szInBuf[c++]);
szt[1] = (CHAR)(szInBuf[c++]);
AddToW( szOutBuf, &i, lTarget, (TCHAR)atoihex( szt));
}
else
{
QuitT( IDS_INVESCSEQ, &szInBuf[c-2], NULL);
}
break;
}
case TEXT('x'):
case TEXT('X'):
{
CHAR szt[4];
szt[0] = szt[1] = szt[2] = szt[3] = '\0';
if ( (szInBuf[c] <= TEXT('9') && szInBuf[c] >= TEXT('0'))
|| (szInBuf[c] >= TEXT('A') && szInBuf[c] <= TEXT('F'))
|| (szInBuf[c] >= TEXT('a') && szInBuf[c] <= TEXT('f')) )
{
szt[0] = (CHAR)(szInBuf[c++]);
if ( (szInBuf[c] <= TEXT('9')
&& szInBuf[c] >= TEXT('0'))
|| (szInBuf[c] >= TEXT('A')
&& szInBuf[c] <= TEXT('F'))
|| (szInBuf[c] >= TEXT('a')
&& szInBuf[c] <= TEXT('f')) )
{
szt[1] = (CHAR)(szInBuf[c++]);
if ( (szInBuf[c] <= TEXT('9')
&& szInBuf[c] >= TEXT('0'))
|| (szInBuf[c] >= TEXT('A')
&& szInBuf[c] <= TEXT('F'))
|| (szInBuf[c] >= TEXT('a')
&& szInBuf[c] <= TEXT('f')) )
{
szt[2] = (CHAR)(szInBuf[c++]);
}
}
}
AddToW( szOutBuf, &i, lTarget, (TCHAR)atoihex( szt));
break;
}
default:
AddToW( szOutBuf, &i, lTarget, szInBuf[c-1]);
break;
} //... END switch
}
else
{
AddToW( szOutBuf, &i, lTarget, szInBuf[c++]);
}
} //... END while
szOutBuf[i++] = TEXT('\0');
return(i);
}
#endif
void ClearResourceDescriptions( void)
{
CUSTRESNODE far *pCR = pCustResList;
CUSTRESNODE far *pCRNext = NULL;
CUSTRESTEMPLATE far *pCRT = NULL;
CUSTRESTEMPLATE far *pCRTNext = NULL;
CUSTRESTEMPLATE far *pCRTTmp = NULL;
while ( pCR )
{
pCRNext = pCR->pNext;
if ( pCR->pszType )
{
RLFREE(pCR->pszType);
}
if ( pCR->pszName )
{
RLFREE(pCR->pszName);
}
pCRT = pCR->pTemplate;
while ( pCRT )
{
pCRTTmp = pCRT->pNext;
RLFREE( pCRT);
pCRT=pCRTTmp;
}
RLFREE( pCR);
pCR = pCRNext;
}
pCustResList = NULL;
}
// Check to see if we need more room. If we have less that 5 bytes
// left, grow the target by another 5%. MHotchin
// chngd to 10% or 10 chars if 10% is less than 10 davewi
static CHAR *CheckBufSize(
int *lTarget, //... Length of output buffer
int cOutBufLen, //... Bytes already used in output buffer
int cDelta, //... # characters we want to add to output buffer
CHAR *szOutBuf) //... ptr to output buffer
{
//... add 1 to allow for trailing nul
if ( *lTarget - cOutBufLen < cDelta + 1 )
{
*lTarget += cDelta;
szOutBuf = (CHAR *)FREALLOC( (BYTE *)szOutBuf, *lTarget);
}
return( szOutBuf);
}
#ifdef RLWIN32
static TCHAR *CheckBufSizeW(
int *lTarget, //... Length of output buffer
int cOutBufLen, //... Bytes already used in output buffer
int cDelta, //... # characters we want to add to output buffer
TCHAR *szOutBuf) //... ptr to output buffer
{
//... add 1 to allow for trailing nul
if ( *lTarget - cOutBufLen < (int)(MEMSIZE( cDelta + 1)) )
{
*lTarget += MEMSIZE( cDelta);
szOutBuf = (TCHAR *)FREALLOC( (BYTE *)szOutBuf, MEMSIZE(*lTarget));
}
return( szOutBuf);
}
#endif //RLWIN32
/**
* Function: BinToTextA
* Converts a binary string to it's c representation
* (complete with escape sequences)
*
* Arguments:
* rgc, source string
* lSource, length of source string
*
* Returns:
* nothing
*
* Error Codes:
* none
*
* History:
* 1/92 -- initial implementation -- SteveBl
* 9/92 -- made this ANSII version-- DaveWi
* because err msg tables in NT are not UNICODE
* 01/19/93 -- Removed the string copies. They were not needed, and
* MHotchin broke anything that had embedded nulls in it.
* Also added support for allocating memory as needed.
**/
PCHAR BinToTextA(
PCHAR szInBuf, //... Input, binary, string
int lSource) //... Length of szInBuf
{
int i;
int cOutBufLen = 0;
int lTarget = 0; //... Max length of szOutBuf
PCHAR szOutBuf = NULL; //... Output string with escape sequences
// If the target is NULL, allocate some memory. We set aside
// 5% more than the source length. MHotchin
// chngd to 5% or 5 chars if 10% is less than 50 davewi
lTarget = (lSource == 0) ? 0 : lSource + 1;
szOutBuf = (PCHAR)FALLOC( lTarget);
for ( i = 0; i < lSource; i++ )
{
switch( szInBuf[i] )
{
case '\a':
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 2, szOutBuf);
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
AddTo(szOutBuf, &cOutBufLen, lTarget, 'a');
break;
case '\b':
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 2, szOutBuf);
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
AddTo(szOutBuf, &cOutBufLen, lTarget, 'b');
break;
case '\f':
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 2, szOutBuf);
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
AddTo(szOutBuf, &cOutBufLen, lTarget, 'f');
break;
case '\n':
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 2, szOutBuf);
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
AddTo(szOutBuf, &cOutBufLen, lTarget, 'n');
break;
case '\r':
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 2, szOutBuf);
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
AddTo(szOutBuf, &cOutBufLen, lTarget, 'r');
break;
case '\t':
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 2, szOutBuf);
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
AddTo(szOutBuf, &cOutBufLen, lTarget, 't');
break;
case '\v':
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 2, szOutBuf);
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
AddTo(szOutBuf, &cOutBufLen, lTarget, 'v');
break;
case '\\':
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 2, szOutBuf);
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
break;
default:
{
unsigned char ucTmp = szInBuf[i];
if ( (ucTmp >= 0 && ucTmp < 32)
|| ucTmp == 0x7f
|| ucTmp == 0xa9
|| ucTmp == 0xae )
{
CHAR szt[5];
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 4, szOutBuf);
sprintf( szt, "%#04hx", (unsigned short)ucTmp);
AddTo(szOutBuf, &cOutBufLen, lTarget, '\\');
AddTo(szOutBuf, &cOutBufLen, lTarget, szt[0]);
AddTo(szOutBuf, &cOutBufLen, lTarget, szt[1]);
AddTo(szOutBuf, &cOutBufLen, lTarget, szt[2]);
AddTo(szOutBuf, &cOutBufLen, lTarget, szt[3]);
}
else
{
szOutBuf = CheckBufSize( &lTarget, cOutBufLen, 1, szOutBuf);
AddTo(szOutBuf, &cOutBufLen, lTarget, szInBuf[i]);
}
break;
}
}
}
szOutBuf[ cOutBufLen] = '\0';
return( szOutBuf);
}
/**
* Function: TextToBinA
* Converts a string with c escape sequences to a true binary string.
*
* Arguments:
* rgc, target string
* sz, source string
* l, maximum length of target string
*
* Returns:
* length of target string
*
* Error Codes:
* none
*
* History:
* 1/92 -- initial implementation -- SteveBl
* 9/92 -- made this ANSII version-- DaveWi
* because msg resource table strings are not UNICODE
* 01/21/93 - Removed the string copies - it breaks on embedded NULL's,
* and they aren't needed anyways. MHotchin
*
**/
int TextToBinA(
CHAR szOutBuf[], //... Output, binary, string
CHAR szInBuf[], //... Input string with escape sequences
int lTarget) //... Max length of szOutBuf
{
int i = 0;
int c = 0;
while (szInBuf[c])
{
if (szInBuf[c] == '\\')
{ // escape sequence!
c++;
switch (szInBuf[c++])
{
case 'a':
AddTo(szOutBuf, &i, lTarget, '\a');
break;
case 'b':
AddTo(szOutBuf, &i, lTarget, '\b');
break;
case 'f':
AddTo(szOutBuf, &i, lTarget, '\f');
break;
case 'n':
AddTo(szOutBuf, &i, lTarget, '\n');
break;
case 'r':
AddTo(szOutBuf, &i, lTarget, '\r');
break;
case 't':
AddTo(szOutBuf, &i, lTarget, '\t');
break;
case 'v':
AddTo(szOutBuf, &i, lTarget, '\v');
break;
case '\'':
AddTo(szOutBuf, &i, lTarget, '\'');
break;
case '\"':
AddTo(szOutBuf, &i, lTarget, '\"');
break;
case '\\':
AddTo(szOutBuf, &i, lTarget, '\\');
break;
case '0':
case '1':
case '2':
{
CHAR szt[4];
szt[0] = szt[1] = szt[2] = szt[3] = '\0';
if ( szInBuf[c] >= '0' && szInBuf[c] <= '9' )
{
szt[0] = szInBuf[c-1];
szt[1] = szInBuf[c++];
if ( szInBuf[c] >= '0' && szInBuf[c] <= '9' )
{
szt[2] = (CHAR)szInBuf[c++];
}
AddTo(szOutBuf, &i, lTarget, (CHAR)atoi( szt));
}
else if ( toupper( szInBuf[c]) == 'X' )
{
c++;
szt[0] = szInBuf[c++];
szt[1] = szInBuf[c++];
AddTo(szOutBuf, &i, lTarget, (CHAR)atoihex( szt));
}
else
{
QuitA( IDS_INVESCSEQ, &szInBuf[c-2], NULL);
}
break;
}
case 'x':
{
CHAR szt[4];
// Changed letters we were comparing to - it used
// to be lower case. MHotchin
szt[0] = szt[1] = szt[2] = szt[3] = '\0';
if ((szInBuf[c] <= '9' && szInBuf[c] >= '0')
|| (toupper(szInBuf[c]) >= 'A'
&& toupper(szInBuf[c]) <= 'F'))
{
szt[0] = (CHAR)szInBuf[c++];
if ((szInBuf[c] <= '9' && szInBuf[c] >= '0')
|| (toupper(szInBuf[c]) >= 'A'
&& toupper(szInBuf[c]) <= 'F'))
{
szt[1] = szInBuf[c++];
if ((szInBuf[c] <= '9' && szInBuf[c] >= '0')
|| (toupper(szInBuf[c]) >= 'A'
&& toupper(szInBuf[c]) <= 'F'))
{
szt[2] = szInBuf[c++];
}
}
}
AddTo(szOutBuf, &i, lTarget, (CHAR)atoihex(szt));
break;
}
default:
AddTo(szOutBuf, &i, lTarget, szInBuf[c-1]);
break;
} //... END switch
}
else
{
AddTo(szOutBuf, &i, lTarget, (CHAR)szInBuf[c++]);
}
} //... END while
szOutBuf[i++] = '\0';
return(i);
}