/*++ Copyright (c) Microsoft Corporation Module Name: genthnk.c Abstract: This program generates thunks. Author: 08-Jul-1995 JonLe Revision History: July 2001 JayKrell integrated from base\wow64\tools to base\tools merged in checked changes from base\mvdm\MeoWThunks\tools\genthnk -G to ignore functions with no prototype skip leading @ on exports let @Else work with @IfApiCode add -LessTrailingWhitespace option to aid formating let @Else work with a few @IfFoo forms August 2001 JayKrell fixed IfApiRet broken above January 2002 JayKrell integrated /private/winfuse_longhorn/base/tools to /lab01_n/base/win32/fusion/tools some -W4 cleanup --*/ #pragma warning(disable:4057) /* char vs. unsigned char mixup */ #pragma warning(disable:4100) /* unreferenced formal parameter */ #pragma warning(disable:4115) /* named type definition in parentheses */ #pragma warning(disable:4127) /* conditional expression is constant */ #pragma warning(disable:4201) /* nameless struct/union */ #pragma warning(disable:4214) /* bit field types other than int */ #pragma warning(disable:4267) /* conversion from 'size_t' to 'int', possible loss of data */ #pragma warning(disable:4706) /* assignment within conditional expression */ #include "nt.h" #include "ntrtl.h" #include "nturtl.h" #include "windows.h" #include "imagehlp.h" #include #include #include #include #include "gen.h" // bitfield values to indicate which platform an API should be switched in on. #define API_NONE 0 #define API_WIN95 1 #define API_WIN98 2 #define API_NT4 4 #define API_NT5 8 #define API_WIN9x (API_WIN95 | API_WIN98) #define API_NTx (API_NT4 | API_NT5) #define API_ALL (API_WIN9x | API_NTx) #define API_SHIFT_WIN9x 0 // shift API bits right 0 to make Win9x leftmost #define API_SHIFT_NTx 2 // shift API bits right 2 to make NTx leftmost // This is the new VC6 import structure. VC6 import lib spec is checked // in as wx86\doc\vc6.doc. Contact Dan Spalding or Kathleen Herold for // more info. Or look at sdktools\vctools\coff\deflib.h ImportHdr. typedef struct ImgImportHdr { WORD Sig1; // always 0 (IMAGE_FILE_MACHINE_UNKNOWN) WORD Sig2; // always ffff (IMPORT_HDR_SIG2) WORD Version; WORD Machine; DWORD TimeStamp; DWORD SizeOfData; // count of bytes in strings that follow union { WORD Ordinal; WORD Hint; }; WORD Type : 2; // IMPORT_TYPE WORD NameType : 3; // IMPORT_NAME_TYPE WORD Reserved : 11;// Reserved. Must be 0. } VC6_IMAGE_IMPORT_HEADER, *PVC6_IMAGE_IMPORT_HEADER; enum IMPORT_TYPE { IMPORT_CODE = 0, IMPORT_DATA = 1, IMPORT_CONST = 2, }; enum IMPORT_NAME_TYPE { IMPORT_ORDINAL, IMPORT_NAME, IMPORT_NAME_NO_PREFIX, IMPORT_NAME_UNDECORATE }; // end of VC6 import structure // string to put in front of all error messages so that BUILD can find them. const char *ErrMsgPrefix = "NMAKE : U8600: 'GENTHNK' "; // template sections types char szIFUNC[]= "IFunc"; char szEFUNC[]= "EFunc"; char szEFAST[]= "EFast"; char szTYPES[]= "Types"; char szCODE[] = "Code"; char szFAILTYPES[] = "FailTypes"; char szMACROS[]="Macros"; // template properties char szTEMPLENAME[]= "TemplateName"; char szMACRONAME[] = "MacroName"; char szTYPENAME[] = "TypeName"; char szINDLEVEL[] = "IndLevel"; char szDIRECTION[] = "Direction"; char szNUMARGS[] = "NumArgs"; char szCGENBEG[] = "Begin"; // default codeburst name char szCGENEND[] = "End"; char szUSE[] = "Use"; char szALSO[] = "Also"; char szNOTYPE[] = "NoType"; char szCASE[] = "Case"; // substitution macros const char szTEMPLATE[]="Template"; const char szDLLNAME[]="DllName"; const char szXPTNAME[]="XPTName"; const char szDLLTARGET[]="DllTarget"; const char szAPIFNRET[]="ApiFnRet"; const char szAPIFNMOD[]="ApiFnMod"; const char szAPINAME[]="ApiName"; const char szAPINAMESKIP[]="ApiNameSkip"; const char szAPIFORWARD[]="ApiForward"; const char szAPINUM[]="ApiNum"; const char szAPIUNKNOWN[]="ApiUnknown"; const char szAPINODECL[]="ApiNoDecl"; const char szISAPIDECLARED[]="IsApiDeclared"; /* like previous, but a boolean expression */ const char szFASTCALL[]="FastCall"; const char szSLOWCALL[]="SlowCall"; const char szFASTX2NMETH[]="FastX2NMethod"; const char szSLOWX2NMETH[]="SlowX2NMethod"; const char szFATX2NMETH[]="FatX2NMethod"; const char szMETHODNUMBER[]="MethodNumber"; const char szRETSIZE[]="RetSize"; const char szUNALIGNEDTAG64[]="UnalignedTag64"; const char szARGSIZE[]="ArgSize"; const char szARGTYPE[]="ArgType"; const char szARGHOSTTYPE[] = "ArgHostType"; const char szARGTYPEIND[]="ArgTypeInd"; const char szARGHOSTTYPEIND[]="ArgHostTypeInd"; const char szARGNAME[]="ArgName"; const char szARGNAMEHOSTCASTED[]="ArgHostName"; const char szARGVAL[]="ArgVal"; const char szFUNCARGNUM[]="FuncArgNum"; const char szARGMOD[]="ArgMod"; const char szARGPOSTMOD[]="ArgPostMod"; const char szARGLIST[]="ArgList"; const char szIFAPIRET[]="IfApiRet"; const char szDOESAPIRETURNVOID[] = "DoesApiReturnVoid"; /* like previous, but a boolean expression */ const char szIFARGS[]="IfArgs"; const char szARGMORE[]="ArgMore"; const char szAPILIST[]="ApiList"; const char szAPIMORE[]="ApiMore"; const char szLISTCOL[]="ListCol"; const char szARGLOCAL[]="ArgLocal"; const char szARGOFF[]="ArgOff"; const char szARGADDR[]="ArgAddr"; const char szEXPORTLIST[]="ExportList"; const char szEXPNAME[]= "ExpName"; const char szIFEXPFORWARD[]= "IfExpForward"; const char szADDRARGSLIST[]="AddrArgsList"; const char szNARGTYPE[]="NArgType"; const char szNARGNAME[]="NArgName"; const char szIFRETTYPE[]="IfRetType"; const char szIFORDINALS[]="IfOrdinals"; const char szAPISTRINGS[]="ApiStrings"; const char szDBGSINDEX[]="DbgsIndex"; const char szDBGSLIST[]="DbgsList"; const char szDBGSSTRINGS[]="DbgsStrings"; const char szDBGSMORE[]="DbgsMore"; const char szCPPEXPORT[]="CppExport"; const char szCEXPORT[]="CExport"; const char szCPPOUTPUT[]="CppOutput"; const char szCOUTPUT[]="COutput"; const char szAPIDECLSPEC[]="ApiDeclSpec"; const char szIFAPICODE[]="IfApiCode"; const char szRETTYPE[]="RetType"; const char szMARG[]="MArg"; const char szMEMBERTYPES[]="MemberTypes"; const char szBTOTMEMBERTYPES[]="BtoTMemberTypes"; const char szFORCETYPE[]="ForceType"; const char szLOG[]="Log"; const char szRTOLTYPES[]= "RtoLTypes"; const char szIFNOTRETTYPE[]="IfNotRetType"; const char szIFISMEMBER[]="IfIsMember"; const char szIFNISMEMBER[]="IfNotIsMember"; const char szIFISBITFIELD[]="IfIsBitfield"; const char szIFNISBITFIELD[]="IfNotIsBitfield"; const char szIFISARRAY[]="IfIsArray"; const char szIFNISARRAY[]="IfNotIsArray"; const char szARGARRAYELEMENTS[]="ArrayElements"; const char szIFPOINTERTOPTRDEP[]="IfPointerToPtrDep"; const char szIFNPOINTERTOPTRDEP[]="IfNotPointerToPtrDep"; const char szISPOINTERTOPTRDEP[]="IsPointerToPtrDep"; const char szIFPTRDEP[]="IfPtrDep"; const char szIFNPTRDEP[]="IfNotPtrDep"; const char szIFINT64DEPUNION[]="IfInt64DepUnion"; const char szIFNINT64DEPUNION[]="IfNotInt64DepUnion"; const char szNL[]="NL"; const char szINDENT[]="Indent"; const char szNOFORMAT[]="NoFormat"; const char szALIGN[]="Align"; char szCOMMENT[]="Comment"; const char szOFFSET[]="OffSet"; const char szHOSTAPPEND[]="Host"; char szCARG[]="CArg"; char szCARGEXIST[]="CArgExist"; const char szFORCASE[]="ForCase"; const char szCNUMBER[]="CNumber"; const char szISINTFORWARD[]="IsIntForward"; const char szISNOTINTFORWARD[]="IsNotIntForward"; // if support const char szIF[]="If"; const char szELSE[]="Else"; const char szOR[]="Or"; const char szAND[]="And"; const char szNOT[]="Not"; const char szARGUNIONULARGEINTEGER[]="PULARGE_INTEGER"; const char szARGUNIONLARGEINTEGER[]="PLARGE_INTEGER"; BOOL g_fLessTrailingWhitespace; extern char sz__PTR64[]; #define MAX_ALSO 80 #define MAX_CODEBURST 20 #define MAX_NOTYPE 32 typedef struct tagCODEBURST { char *Name; } CODEBURST; CODEBURST CodeBursts[MAX_CODEBURST]; typedef struct _Templates{ LIST_ENTRY TempleEntry; char *Name; int IndLevel; TOKENTYPE tkDirection; PKNOWNTYPES pktType; char *Comment; char *CodeBurst[MAX_CODEBURST]; char *NoTypes[MAX_NOTYPE]; PLIST_ENTRY pCaseList; char Buffer[1]; }TEMPLES, *PTEMPLES; typedef struct _CGenerate { LIST_ENTRY CGenerateEntry; FILE *fp; FILE *fpC; char *FileNameC; char *FileBaseNameC; FILE *fpCpp; char *FileNameCpp; char *FileBaseNameCpp; char TempleName[1]; }CGENERATE, *PCGENERATE; FILE *fpLog; // file pointer to optional log file for @Log() calls // // handy macro to knock out the hi bit in implib style ordinals // #define IMPORDINAL(o) ((o) & ~0x80000000) // // Structure definining the list of arguments for a function // typedef struct _ArgumentsList { LIST_ENTRY ArgumentsEntry; // ptr to prev and next arg PKNOWNTYPES pKnownTypes; // type of this arg PKNOWNTYPES pStructType; // cache used by MemberTypes() DWORD ArgSize; // size of this arg BOOL IsPtr64; // TRUE if this arg is __ptr64 int OffSet; // offset from stack for this arg int IndLevel; // indirection level TOKENTYPE tkDirection; // TK_NONE, TK_IN, TK_OUT, TK_INOUT TOKENTYPE Mod; // modifier (TK_CONST/VOLATILE/NONE) TOKENTYPE SUEOpt; // TK_STRUCT/ENUM/UNION/NONE char *Type; // typename for this arg TOKENTYPE PostMod; // modifier (TK_CONST/VOLATILE/NONE) TOKENTYPE PrePostMod; // modifier (TK_CONST/VOLATILE/NONE) char *Name; // argument name (may be a nonameX) char *ArgLocal; // name of local var containing copy of arg char *HostCastedName; // Contains full name of struct member with // host casts or NULL BOOL fRequiresThunk; // TRUE if arg type contains a nested // function pointer (and hence needs // special thunking) BOOL fNoType; // TRUE if types templates should *not* // be expanded for this param. BOOL fIsMember; // This arg is actually a member of an array BOOL bIsBitfield; // Determines if this is a bitfield int BitsRequired; // Number of bits required for bitfield BOOL bIsArray; // This member is an array int ArrayElements; // Number of elements in the array } ARGSLIST, *PARGSLIST; // // Structure containing the list of macro arguments // typedef struct _MacroArgsList { int NumArgs; LPSTR ArgText[1]; } MACROARGSLIST, *PMACROARGSLIST; typedef struct _MLListEntry { LIST_ENTRY ListEntry; PMACROARGSLIST pMArgs; } MLLISTENTRY, *PMLLISTENTRY; #define MAX_MACRO_STACK 20 PMACROARGSLIST MacroStack[MAX_MACRO_STACK]; int MacroStackTop; // // This defines the first method number that would not be supported as a // fast or slow method call. If this is to be changed then FastN2X and SlowN2X // worker routines need to be addeed in whole32.dll #define MAXFASTN2XMETHODNUMBER 16 // // This defines the maximum number of parameters that are allowed to be in a // FastX2N or SlowX2N method call. To change it new code would have to be // added to FastX2N and SlowX2N in whole32\methods.c to deal with the // additional number of parameters. #define MAXX2NPARAMETERS 10 typedef enum { UNKNOWNMETHOD = 0, FATX2NMETHOD = 1, FASTX2NMETHOD = 2, SLOWX2NMETHOD = 3 } METHODTYPE; typedef struct _ExportDebugInfo { LIST_ENTRY ExportsDbgEntry; LIST_ENTRY ArgsListHead; struct _ExportDebugInfo *IntForward; int ArgsSize; ULONG Function; char *ExtForward; char *ExportName; char *CplusDecoration; ULONG Ordinal; // 0 = known fn, -1 incomplete declaration, 1 no declaration char UnKnownApi; BOOLEAN Data; BOOLEAN PrivateNamed; CHAR FastCall; BYTE ApiPlatform; // the API_ bit collection METHODTYPE X2NMethodType; ULONG MethodNumber; char Buffer[1]; }EXPORTSDEBUG, *PEXPORTSDEBUG; typedef struct _DebugStringsList { LIST_ENTRY DebugStringsEntry; char *Name; char *ArgFormat; char *RetFormat; char Buffer[1]; } DEBUGSTRINGS, *PDEBUGSTRINGS; typedef struct _CGenerateState { PEXPORTSDEBUG ExportsDbg; PDEBUGSTRINGS DebugStrings; PCGENERATE CGen; PTEMPLES Temple; // template for this func (may be IFunc or EFunc) PKNOWNTYPES ApiTypes; int ApiNum; PARGSLIST pArgsList; int ListCol; BOOLEAN MoreApis; BOOLEAN ExTemplate; // true if Temp is an EFunc template with a 'Begin=' PTEMPLES TempleEx; // EFunc for this API (if there is one) int CodeBurstIndex; PTEMPLES CurrentTemple; // This is the template that is currently being expanded. PMACROARGSLIST pMacroArgsList; PCHAR *MemberNoType; // Additional set of notypes to applyPMACROARGSLIST pMacroArgsList; int CaseNumber; // Number of the current Case being expanded. PLIST_ENTRY pCaseList; PMACROARGSLIST pCaseArgsList; } CGENSTATE, *PCGENSTATE; int BeginCBI; // CodeBurstIndex for 'Begin=' PKNOWNTYPES NIL; // for red-black trees PRBTREE FuncsList; PRBTREE TypeDefsList; PRBTREE StructsList; RBTREE FakeFuncsList; LIST_ENTRY TypeTempleList; LIST_ENTRY FailTempleList; LIST_ENTRY IFuncTempleList; LIST_ENTRY EFuncTempleList; LIST_ENTRY EFastTempleList; LIST_ENTRY CodeTempleList; LIST_ENTRY CGenerateList; LIST_ENTRY ExportsList; LIST_ENTRY DebugStringsList; LIST_ENTRY MacroList; ULONG NumDebugStringsEntries; BOOL MapViewDll(char *DllName); char DllName[MAX_PATH+1]= ""; char ExplicitDllBaseName[MAX_PATH+1] = "UNSPECIFIED"; char *DllBaseName = ExplicitDllBaseName; PVOID DllMappedBase = NULL; ULONG_PTR DllRvaOffset; PULONG DllFunctions = NULL; PUSHORT DllNameOrdinals = NULL; PULONG DllNameTable = NULL; ULONG DllExportDirSize; PIMAGE_EXPORT_DIRECTORY DllExportDir; BOOL MapViewImplib(char *ImplibName); char ImplibName[MAX_PATH+1]=""; char *ImplibBaseName = NULL; PVOID ImplibMappedBase= NULL; ULONG ImplibNumSymbols=0; PULONG ImplibSymbolMembers=NULL; PCHAR ImplibSymbolNames=NULL; char szIMPPREFIX[]="__imp_"; char szIDATA5[]=".idata$5"; char szTEXT[]=".text"; char szINTFORWARD[]="_IntForward_"; char XptName[MAX_PATH+1]= ""; char *XptBaseName = NULL; // these are used to report errors while parsing .tpl files char *TemplateFileName; int TemplateLine; char iHandleCpp = 0; // if == 0, Don't use CPP macros, and warn if CPP exports found // if < 0, Don't use CPP macros, no warn if CPP exports found // if > 0, Use CPP macros. BOOL bIgnorePrototypeError; BOOL bNoFuzzyLogic; BOOL bUseExpListAndImplib; BOOL bWarnAboutNestedFuncPtrs; BOOL bUseDirection = TRUE; BOOL bStripNewline = TRUE; int OutputColumn = 0; int IndentLevel = 0; BOOL bFirstCharHit = FALSE; #define INDENTSIZE 4 void SetInternalForwards(void); BOOL ExtractXpt(char *XptName, char *DllName); BOOL ExtractExports(void); BOOL ExtractPpm(char *FileName); BOOL ExtractTemples(char *FileName); BOOL ExtractCGenerate(char *pNames); BOOL ExtractImplib(char *LibName); char *CopyField(char *pDst, char *pSrc, int Len, char Sep); void DumpTemplate(PTEMPLES ptpl, FILE *fp); PTEMPLES GetTemplate(PLIST_ENTRY pHeadList, char *TempleName); char *CGenerate(char *pSrc, PCGENSTATE pCGenState); char *CGenerateEx(char *pSrc, PCGENSTATE pCGenState, char *OutBuffer, SIZE_T MaxLen, SIZE_T *BytesReturned); char *ListApis(char *pSrc, PCGENSTATE pCGenState, BOOL bExports); char *ListArgs(char *pSrc, PCGENSTATE pCGenState, BOOL Always); void ProcessTemple(PCGENSTATE pCGenState); char *IncludeTemplate(char *pSrc, PCGENSTATE pCGenState); char *IncludeTypes(char *pSrc, PCGENSTATE pCGenState, BOOL bRtoL); char *MemberTypes(char *pSrc, PCGENSTATE pCGenState, BOOL bBtoT); char *IfNotRetType(char *pSrc, PCGENSTATE pCGenState); char *IncludeRetType(char *pSrc, PCGENSTATE pCGenState); char *WriteMore(char *pSrc, PCGENSTATE pCGenState, BOOL bMore); BOOL AddToExportsList(PEXPORTSDEBUG pExportsDebug); PEXPORTSDEBUG FindInExportsList(char *Name); char *SkipSubExpression(char *pSrc, char **pSubExpression); PKNOWNTYPES BuildFakeTypesInfo(PEXPORTSDEBUG pExportsDbg, PKNOWNTYPES pKnownTypes); void WriteListColumn(PCGENSTATE pCGenState); char *GetAltExportName(char *Buffer, PCGENSTATE pCGenState, int Len); void BuildArgsList(PTEMPLES pTempleEx, PFUNCINFO funcinfo, PLIST_ENTRY pListHead); char *IfApiRet(char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult); char *DoesApiReturnVoid(char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult); char *IfApiCode(char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult); char *IfRetType(char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult); char *IfArgs(char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult); void ApiStrings(PCGENSTATE pCGenState); int GetFuncArgNum(PCGENSTATE pCGenState); int GetFuncIndex(PCGENSTATE pCGenState, char *FuncTypeName); char *ListDbgs(char *pSrc, PCGENSTATE pCGenState); void WriteDbgsStrings(char *pSrc, PCGENSTATE pCGenState); int GetRetSize(PCGENSTATE pCGenState); int GetArgSize(PEXPORTSDEBUG ExportDebug); char *GetOffSet(char *pSrc, char *Buffer); char *LexMacroArgs(char *pch); PLIST_ENTRY ListFromTempleType(char *TempleType); void UseLogMacros(char *pLogName); char *UpdateLog(char *pSrc, PCGENSTATE pCGenState); BOOL IsPointerToPtrDep(PARGSLIST pArgsList); char* ForceTypeExpand( char *pSrc, PCGENSTATE pCGenState); VOID SetArgListToTypeForArg(PARGSLIST pArgsList, PARGSLIST pArgsListOld, char * pTypeName); void StripTrailingWhitespaceFromString(char * s); char * SkipLeadingWhitespace(char * s); BOOL IsWhitespaceCharacter(char c); BOOLEAN IsFastCall( PCGENSTATE pCGenState ); METHODTYPE GetX2NMethodType( PCGENSTATE pCGenState ); char * GetAddrFirstArg( PCGENSTATE pCGenState, char *Buffer, int BuffLen ); PKNOWNTYPES IsSameType( PKNOWNTYPES pktArgs, int IndLevel, TOKENTYPE tkArgDirection, char *tplTypeName, int tplIndLevel, TOKENTYPE tkTypeDirection, BOOL bScanBaseTypes ); char * WriteArgAddr( char *pSrc, PCGENSTATE pCGenState, char *Buffer, int BuffLen ); BOOL WriteArgLocal( PCGENSTATE pCGenState, char *Buffer, int BuffLen ); BOOL AddTemple( char *TempleType, char *TempleName, char *Comment, char *IndLevel, char *pCCode[MAX_CODEBURST], TOKENTYPE tkDirection, char *Also[MAX_ALSO], int AlsoCount, char *NoType[MAX_NOTYPE], int NoTypeCount, PLIST_ENTRY pCaseList ); int GetCodeBurstIndex( char *BurstName ); int GetExistingCodeBurstIndex( char *BurstName ); BOOLEAN ExpandMacro( char *MacroName, PCGENSTATE pCGenState, char **ppIn, char *OutBuffer, SIZE_T MaxLen, SIZE_T *BytesReturned ); BOOLEAN TempleHasNoCodeBursts( PTEMPLES pTemple ); void PlatformSwitchStart( PCGENSTATE pCGenState, BYTE ApiPlatform ); void PlatformSwitchEnd( PCGENSTATE pCGenState, BYTE ApiPlatform ); void PlatformSwitchEndTable( PCGENSTATE pCGenState, BYTE ApiPlatform ); char * ExtractBoolean1( char *pSrc, PCGENSTATE pCGenState, BOOLEAN *result ); char * ExtractBoolean2( char *pSrc, PCGENSTATE pCGenState, BOOLEAN *result1, BOOLEAN *result2 ); void WriteBoolean ( char *pSrc, BOOL Value ); char *CPlatformSwitches[] = { "", "(%s==0x0400)", "(%s>0x0400)", "(%s>=0x0400)" }; char *AsmPlatformSwitches[] = { "", "(%s_ASM EQ 0400h)", "(%s_ASM GT 0400h)", "(%s_ASM GE 0400h)" }; BOOL ExpandTemple(PTEMPLES ptpl, int CodeBurstIndex, PCGENSTATE pCGenState) { PLIST_ENTRY pOldCaseList; PTEMPLES pOldCurrentTemple; char *pSrc = ptpl->CodeBurst[CodeBurstIndex]; if (NULL == pSrc) { return FALSE; } pSrc = ptpl->CodeBurst[CodeBurstIndex]; while (*pSrc && !isgraph(*pSrc)) { pSrc++; } if ('\0' == *pSrc) { return FALSE; } // // Expand the type here pOldCurrentTemple = pCGenState->CurrentTemple; pOldCaseList = pCGenState->pCaseList; if(ptpl->pCaseList != NULL && !IsListEmpty(ptpl->pCaseList)) { pCGenState->pCaseList = ptpl->pCaseList; } pCGenState->CurrentTemple = ptpl; CGenerate(pSrc, pCGenState); pCGenState->CurrentTemple = pOldCurrentTemple; pCGenState->pCaseList = pOldCaseList; return TRUE; } PVOID CheckHeapAlloc(SIZE_T Size) { PVOID pMem; pMem = GenHeapAlloc(Size); if(NULL == pMem) { DbgPrintf("Error: Out of Memory!\n"); DebugBreak(); ExitErrMsg(FALSE, "Error: Out of Memory!\n"); } return pMem; } typedef struct _StringListEntry { LIST_ENTRY ListEntry; PSTR pStr; } STRINGLISTENTRY, *PSTRINGLISTENTRY; VOID FreeMacroArgsList(PMACROARGSLIST pArgs) { SIZE_T c; for(c=0; c < (SIZE_T)pArgs->NumArgs; c++) { GenHeapFree(pArgs->ArgText[c]); } GenHeapFree(pArgs); } char * CArg( char *pSrc, PCGENSTATE pCGenState, PSTR *pBuffer, BOOL TestExistOnly ) { int i; int ArgNum; CHAR s[MAX_PATH]; PCHAR pResult; PMACROARGSLIST pList = pCGenState->pCaseArgsList; PCHAR pCommandName = TestExistOnly ? szCARGEXIST : szCARG; if (!pList) { ExitErrMsg(FALSE, "%s(%d) %s unexpected: no case is currently being applied\n", TemplateFileName, TemplateLine, pCommandName); return NULL; } if (*pSrc != '(') { ExitErrMsg(FALSE, "%s(%d) %s Incorrect parameter %s\n", TemplateFileName, TemplateLine, pCommandName, pSrc); return NULL; } pSrc++; i = 0; while ((*pSrc != ')') && (i < sizeof(s)-1)) { s[i++] = *pSrc++; } s[i] = 0; ArgNum = atoi(s); pSrc++; // skip ')' if (ArgNum-- == 0) { ExitErrMsg(FALSE, "%s(%d) Invalid %s parameter %s\n", TemplateFileName, TemplateLine, pCommandName, s); return NULL; } if (TestExistOnly) { pResult = (ArgNum >= pList->NumArgs) ? "0" : "1"; } else { if (ArgNum >= pList->NumArgs) { ExitErrMsg(FALSE, "%s(%d) Case only has %d arguments\n", TemplateFileName, TemplateLine, pList->NumArgs); return NULL; } pResult = pList->ArgText[ArgNum]; } if (pBuffer != NULL) { *pBuffer = pResult; } else { CGenerate(pResult, pCGenState); } return pSrc; } char *ForCase(char *pSrc, PCGENSTATE pCGenState) { PMACROARGSLIST pCaseArgsListOld; PLIST_ENTRY pHead, pThis; char *pch; char *pExpression; int OldCaseNumber; // Are any cases available for application if (pCGenState->pCaseList == NULL || (pCGenState->pCaseList != NULL && IsListEmpty(pCGenState->pCaseList))) { //Do nothing return SkipSubExpression(pSrc, NULL); } pch = SkipSubExpression(pSrc, &pExpression); if (pSrc == pch || !pExpression) { return pch; } pSrc = pch; pCaseArgsListOld = pCGenState->pCaseArgsList; pHead = pCGenState->pCaseList; pThis = pHead->Flink; OldCaseNumber = pCGenState->CaseNumber; pCGenState->CaseNumber = 0; do { pCGenState->pCaseArgsList = CONTAINING_RECORD(pThis,MLLISTENTRY,ListEntry)->pMArgs; CGenerate(pExpression, pCGenState); pThis = pThis->Flink; pCGenState->CaseNumber++; } while (pThis != pHead ); pCGenState->CaseNumber = OldCaseNumber; pCGenState->pCaseArgsList = pCaseArgsListOld; return pSrc; } PCHAR ParseMacroArgs(IN PCHAR pch, IN SIZE_T maxlen, OUT PMACROARGSLIST *ppMArgsList ) { PMACROARGSLIST pMArgsList = NULL; LIST_ENTRY ArgsList; PCHAR pl; int ArgCount=0; int ParenDepth=0; SIZE_T len = 0; if (maxlen == 0) { len = MAXUINT_PTR; } InitializeListHead(&ArgsList); if (*pch != '(') { ExitErrMsg(FALSE, "ParseMacroArgs: Expected to find ( for args list\n"); } pch++; ParenDepth++; len++; while(ParenDepth > 0) { pl = pch; while(1) { if('\0' == *pl || len > maxlen) { ExitErrMsg(FALSE, "ParseMacroArgs: Unmatched paren for args list\n"); } if (*pl == '(') { ParenDepth++; } else if (*pl == ')') { ParenDepth--; } if (ParenDepth == 0 || (ParenDepth == 1 && *pl == ',')) { PSTRINGLISTENTRY pSl; pSl = CheckHeapAlloc(sizeof(STRINGLISTENTRY)); pSl->pStr = CheckHeapAlloc(pl - pch + 1); memcpy(pSl->pStr, pch, pl - pch); pSl->pStr[pl - pch] = '\0'; InsertTailList(&ArgsList, &(pSl->ListEntry)); ArgCount++; pch = pl + 1; if (ParenDepth == 0) { // No more arguments goto Exit; } else { // Do next argument break; } } pl++; } } Exit: pMArgsList = CheckHeapAlloc(sizeof(MACROARGSLIST) + sizeof(LPSTR) * ArgCount); pMArgsList->NumArgs = ArgCount; for(ArgCount = 0; ArgCount < pMArgsList->NumArgs; ArgCount++) { PSTRINGLISTENTRY pSl; pSl = CONTAINING_RECORD(ArgsList.Flink,STRINGLISTENTRY,ListEntry); RemoveHeadList(&ArgsList); pMArgsList->ArgText[ArgCount] = pSl->pStr; GenHeapFree(pSl); } *ppMArgsList = pMArgsList; return pch; } void ExtractServicesTab(char *pch); /* main * * standard win32 base windows entry point * returns 0 for clean exit, otherwise nonzero for error * * * ExitCode: * 0 - Clean exit with no Errors * nonzero - error ocurred * */ int __cdecl main(int argc, char **argv) { int i; DWORD dw; char *pch; CGENSTATE CGenState; PLIST_ENTRY Next; BOOL bUseServicesTab = FALSE; // init the lists InitializeListHead(&TypeTempleList); InitializeListHead(&FailTempleList); InitializeListHead(&CodeTempleList); InitializeListHead(&IFuncTempleList); InitializeListHead(&EFuncTempleList); InitializeListHead(&EFastTempleList); InitializeListHead(&CGenerateList); InitializeListHead(&ExportsList); InitializeListHead(&DebugStringsList); InitializeListHead(&MacroList); NumDebugStringsEntries = 0; BeginCBI = GetCodeBurstIndex(szCGENBEG); // Preload 'Begin=' as a valid codeburst SetConsoleCtrlHandler(ConsoleControlHandler, TRUE); /*try*/ { /* * Get cmd line args. */ i = 0; while (++i < argc) { pch = argv[i]; if (*pch == '-' || *pch == '/') { pch++; if (_stricmp(pch, "LessTrailingWhitespace") == 0) { g_fLessTrailingWhitespace = TRUE; } else switch (toupper(*pch)) { case 'D': bDebug = TRUE; setvbuf(stderr, NULL, _IONBF, 0); break; case 'F': bExitClean = FALSE; break; case 'T': // template file name if (!ExtractTemples(pch+1)) { ExitErrMsg(FALSE, "ExtractTemples failed %s\n", pch); } break; case 'C': //cgenerate "-cOutputFileName[,CppOutputFileName]:TemplateName" if (!ExtractCGenerate(pch+1)) { ExitErrMsg(FALSE, "ExtractCGenerate failed %s\n", pch); } break; case 'M': // ppm file name (only 1 expected!) if (FuncsList) { ExitErrMsg(FALSE, "ExtractPpm only one Ppm file allowed %s\n", pch); } if (!ExtractPpm(pch+1)) { ExitErrMsg(FALSE, "ExtractPpm failed %s\n", pch); } break; case 'S': //use a services.tab instead of an exports list bUseServicesTab = TRUE; ExtractServicesTab(pch+1); break; case 'E': // xpt list for exports "-eExportListName" dw = GetFullPathName(pch+1, sizeof(XptName) - 1, XptName, &XptBaseName ); if (!dw || dw >= sizeof(XptName) - 1) { ExitErrMsg(FALSE, "Invalid XptName %s\n", pch); } break; case 'X': // Enable exports from implib, -eXptName assumed bUseExpListAndImplib = TRUE; break; case 'I': // implib file name "-iImplibName" dw = GetFullPathName(pch+1, sizeof(ImplibName) - 1, ImplibName, &ImplibBaseName ); if (!dw || dw >= sizeof(ImplibName) - 1) { ExitErrMsg(FALSE, "Invalid Import Library Name %s\n", pch); } break; case 'L': // Disable fuzzy logic symbol name matching bNoFuzzyLogic = TRUE; break; case 'W': // warn about unthunked structures containing function ptrs bWarnAboutNestedFuncPtrs = TRUE; break; case 'U': // [U]se direction information (__in, __out) bUseDirection = FALSE; // turn it off break; case 'K': // generate chec[K] file from @Log() macros UseLogMacros(pch+1); break; case 'N': // specify explicit DLL base name strncpy(DllBaseName, pch+1, MAX_PATH); break; case 'G': // ignore function prototype errors for debugging purpose only bIgnorePrototypeError = TRUE; break; default: ExitErrMsg(FALSE, "Unrecognized option %s\n", pch); } } else if (*pch) { dw = GetFullPathName(pch, sizeof(DllName) - 1, DllName, &DllBaseName ); if (!dw || dw >= sizeof(DllName) - 1) { ExitErrMsg(FALSE, "Invalid DllName %s\n", pch); } } } if(!bUseServicesTab) { // // MapView of importlib and dll into memory and // set up global variables for easy access // if (ImplibName[0]) { if (!MapViewImplib(ImplibName)) { ExitErrMsg(FALSE, "Couldn't open import lib '%s'\n", ImplibName); } } if (DllName[0]) { if (!MapViewDll(DllName)) { ExitErrMsg(FALSE, "Couldn't open DLL '%s'\n", DllName); } } // // Extract exports using dll and implib. // if (DllName[0] && (!XptName[0] || bUseExpListAndImplib)) { // Insist that we have both an implib and a dll. if ((DllName[0] && !ImplibName[0]) || (ImplibName[0] && !DllName[0])) { ExitErrMsg(FALSE, "DllName or ImplibName missing\n"); } if (!ExtractExports()) { ExitErrMsg(FALSE, "Failed to get exports for <%s>\n", DllName); } } // // Extract exports from the api list // if (XptName[0]) { if (!ExtractXpt(XptName, DllName)) { ExitErrMsg(FALSE, "Failed to get exports for <%s>\n", XptName); } } } // // Set Internal forwards. // SetInternalForwards(); Next = CGenerateList.Flink; while (Next != &CGenerateList) { memset(&CGenState, 0, sizeof(CGenState)); CGenState.CGen = CONTAINING_RECORD(Next,CGENERATE,CGenerateEntry); ProcessTemple(&CGenState); DelOpenFile(CGenState.CGen->fp, NULL); fclose(CGenState.CGen->fp); Next= Next->Flink; } } /*except(EXCEPTION_EXECUTE_HANDLER) { ExitErrMsg(FALSE, "ExceptionCode=%x\n", GetExceptionCode() ); }*/ CloseOpenFileList(FALSE); return 0; } int GetCodeBurstIndex( char *BurstName ) /*++ Routine Description: Given a name of a 'foo=' (ie. "foo"), return its index in the array of codebursts. If there is no 'foo=' on file, add it. Arguments: BurstName - name of codeburst to get/add. Return Value: Index into template->CodeBursts[], or calls ExitErrMsg() on error. --*/ { int i; int FirstFree = -1; if (strcmp(BurstName, "CGenBegin") == 0) { // Compatibility: Accept 'CGenBegin' as 'Begin' return BeginCBI; } for (i=0; iIntForward ? ExportsDbg->IntForward->ExportName : ExportsDbg->ExportName; // // Look in the FakeFuncsLIst, and the FuncsList. // ApiTypes = GetNameFromTypesList(&FakeFuncsList, ExpName); if (!ApiTypes) { ApiTypes = GetNameFromTypesList(FuncsList, ExpName); } // // If export is a decorated name then lets see if we have // a func that matches the undecorated name // if (!ApiTypes) { pch = strchr(ExpName, '@'); if (pch) { *pch = '\0'; ApiTypes = GetNameFromTypesList(&FakeFuncsList, ExpName); if (!ApiTypes) { ApiTypes = GetNameFromTypesList(FuncsList, ExpName); } *pch = '@'; } } if (!ApiTypes && ExportsDbg->Data) { ApiTypes = GetNameFromTypesList(TypeDefsList, "PVOID"); } else { if (!ApiTypes || !ApiTypes->pfuncinfo) { ApiTypes = BuildFakeTypesInfo(ExportsDbg, ApiTypes); } if (!ApiTypes->pktRet) { // Get KnownTypes info for Return Type PKNOWNTYPES pkt; ResetLexer(); LexMacroArgs(ApiTypes->FuncRet); ConsumeConstVolatileOpt(); if (ParseTypes(TypeDefsList, NULL, &pkt) == FALSE) { CurrentTokenIndex = 0; if (ParseTypes(StructsList, NULL, &pkt) == FALSE ) { ExitErrMsg(FALSE, "GetApiTypes: Undefined return type %s\n", ApiTypes->FuncRet); } } ApiTypes->pktRet = pkt; } } return ApiTypes; } /* * ProcessTemple */ void ProcessTemple(PCGENSTATE pCGenState) { PLIST_ENTRY Next; PTEMPLES pTemple; PTEMPLES pTempleEx; pTemple = GetTemplate(&CodeTempleList, pCGenState->CGen->TempleName); if (pTemple) { fprintf(pCGenState->CGen->fp, "%s CodeTemplate:%s\n", pTemple->Comment, pTemple->Name ); pCGenState->Temple = pTemple; ExpandTemple(pCGenState->Temple, pCGenState->CodeBurstIndex, pCGenState); } else if (pTemple = GetTemplate(&IFuncTempleList, pCGenState->CGen->TempleName )) { pCGenState->ApiNum = 0; Next = ExportsList.Flink; while (Next != &ExportsList) { BYTE ApiPlatform; pCGenState->ExportsDbg = CONTAINING_RECORD(Next, EXPORTSDEBUG, ExportsDbgEntry ); // // Switch this API in or out depending on the platform info // ApiPlatform = pCGenState->ExportsDbg->ApiPlatform; pCGenState->Temple = pTemple; PlatformSwitchStart(pCGenState, ApiPlatform); pCGenState->ApiTypes = GetApiTypes(pCGenState->ExportsDbg); // // Use exception template for this api if there is one // pTempleEx = GetTemplate(&EFuncTempleList, pCGenState->ExportsDbg->ExportName ); pCGenState->TempleEx = pTempleEx; if (pTempleEx) { pCGenState->ExTemplate = TRUE; } else { pCGenState->ExTemplate = FALSE; } if (pTempleEx && (pTempleEx->CodeBurst[BeginCBI] || TempleHasNoCodeBursts(pTempleEx))) { pCGenState->Temple = pTempleEx; fprintf(pCGenState->CGen->fp, "%s Func Template:%s\n", pTempleEx->Comment, pTempleEx->Name ); if (TempleHasNoCodeBursts(pTempleEx)) { // skip this API: ex template, but not code at all fprintf(pCGenState->CGen->fp, "%s *** WARNING *** Excluded Api %s\n", pCGenState->Temple->Comment, pCGenState->ExportsDbg->ExportName ); goto SkipGen; } /* else if (bIgnorePrototypeError) { fprintf(pCGenState->CGen->fp, "%s Error:1 Ignoring Api %s\n", pCGenState->Temple->Comment, pCGenState->ExportsDbg->ExportName ); goto SkipGen; } */ } else { // no ex template pCGenState->Temple = pTemple; if (pCGenState->ExportsDbg->Data) { // DATA export - skip the API fprintf(pCGenState->CGen->fp, "%s *** WARNING *** Excluded Data Export %s\n", pCGenState->Temple->Comment, pCGenState->ExportsDbg->ExportName ); goto SkipGen; } else if (!pCGenState->ApiTypes->pfuncinfo) { // members unknown - skip the API if (bIgnorePrototypeError) { fprintf(pCGenState->CGen->fp, "%s Error:2 Ignoring Api %s\n", pCGenState->Temple->Comment, pCGenState->ExportsDbg->ExportName ); goto SkipGen; } else { ExitErrMsg(FALSE, "API %s has no function prototype - unable to generate code.", pCGenState->ExportsDbg->ExportName ); } } else if (!iHandleCpp && pCGenState->ExportsDbg->CplusDecoration) { // CPP export and we aren't set up for CPP exports fprintf(pCGenState->CGen->fp, "%s *** WARNING *** Excluding CPP Api: %s\n", pCGenState->Temple->Comment, pCGenState->ExportsDbg->ExportName ); goto SkipGen; } } // // skip this api if: // - external forward reference // - internal forward which does not define the fn // // if ( (pCGenState->ExportsDbg->ExtForward || (pCGenState->ExportsDbg->IntForward && pCGenState->ExportsDbg->IntForward != pCGenState->ExportsDbg))) { fprintf(pCGenState->CGen->fp, "%s %s forwarded to %s\n", pCGenState->Temple->Comment, pCGenState->ExportsDbg->ExportName, pCGenState->ExportsDbg->ExtForward ? pCGenState->ExportsDbg->ExtForward : pCGenState->ExportsDbg->IntForward->ExportName ); if (pTempleEx) { fprintf(pCGenState->CGen->fp, "%s WARNING: forwarded function has an exception template\n", pCGenState->Temple->Comment, pTempleEx->Name ); } } else { // gen code for this api PLIST_ENTRY NextArg; PARGSLIST pArgsList; BuildArgsList(pTempleEx, pCGenState->ApiTypes->pfuncinfo, &pCGenState->ExportsDbg->ArgsListHead ); if (GetArgSize(pCGenState->ExportsDbg) < 0) { // members unknown - skip the API if (bIgnorePrototypeError) { fprintf(pCGenState->CGen->fp, "%s Error:3 Ignoring Api %s\n", pCGenState->Temple->Comment, pCGenState->ExportsDbg->ExportName ); goto SkipGen; } else { ExitErrMsg(FALSE, "API %s has no function prototype - unable to generate code.", pCGenState->ExportsDbg->ExportName ); } } else { ExpandTemple(pCGenState->Temple, BeginCBI, pCGenState); // // Dump warnings about unthunked parameters which // contain nested function pointers. // if (bWarnAboutNestedFuncPtrs && !pTempleEx) { int ArgNum = 1; NextArg = pCGenState->ExportsDbg->ArgsListHead.Flink; while (NextArg != &pCGenState->ExportsDbg->ArgsListHead) { pArgsList = CONTAINING_RECORD(NextArg, ARGSLIST, ArgumentsEntry ); if (pArgsList->fRequiresThunk) { // // The argument contained a nested function // pointer, and nothing thunked that // function pointer. Warn about a potential // bug. // fprintf(pCGenState->CGen->fp, "// *** WARNING: Arg %d: type '%s' contains an unthunked function pointer ***\n", ArgNum, pArgsList->Type ); } NextArg = NextArg->Flink; ArgNum++; } } // // clean up pArgsList->LocalVar and ArgHostName // NextArg = pCGenState->ExportsDbg->ArgsListHead.Flink; while (NextArg != &pCGenState->ExportsDbg->ArgsListHead) { pArgsList = CONTAINING_RECORD(NextArg, ARGSLIST, ArgumentsEntry ); if (pArgsList->ArgLocal) { GenHeapFree(pArgsList->ArgLocal); pArgsList->ArgLocal = NULL; } if (pArgsList->HostCastedName) { GenHeapFree(pArgsList->HostCastedName); pArgsList->HostCastedName = NULL; } NextArg = NextArg->Flink; } pCGenState->ApiNum++; } } SkipGen: // // End switching this API in or out depending on the platform info // ApiPlatform = pCGenState->ExportsDbg->ApiPlatform; PlatformSwitchEnd(pCGenState, ApiPlatform); Next= Next->Flink; } } else { ExitErrMsg(FALSE, "%s,%s:%s Template undefined\n", pCGenState->CGen->FileNameC, pCGenState->CGen->FileNameCpp ? pCGenState->CGen->FileNameCpp : "", pCGenState->CGen->TempleName ); } } void PlatformSwitchStart( PCGENSTATE pCGenState, BYTE ApiPlatform ) { BOOL fIsAsm; if (ApiPlatform == API_ALL) { return; } // // Switch this API in or out depending on the platform info // 00: don't emit anything // 01: emit "== 0x0400" // 10: emit "> 0x0400" // 11: emit ">= 0x0400" // if (!pCGenState->Temple || !pCGenState->Temple->Comment) { fIsAsm = FALSE; } else { if (strcmp(pCGenState->Temple->Comment, ";") == 0) { fIsAsm = TRUE; } else { fIsAsm = FALSE; } } if (fIsAsm) { fprintf(pCGenState->CGen->fp, "\nif "); } else { fprintf(pCGenState->CGen->fp, "\n#if "); } if (ApiPlatform & API_WIN9x) { BYTE Plat = (ApiPlatform & API_WIN9x) >> API_SHIFT_WIN9x; fprintf(pCGenState->CGen->fp, (fIsAsm) ? AsmPlatformSwitches[Plat] : CPlatformSwitches[Plat], "_WIN32_WINDOWS" ); } if ((ApiPlatform & API_WIN9x) && (ApiPlatform & API_NTx)) { // API is on some flavor of Win9x and some NTx flavor fprintf(pCGenState->CGen->fp, (fIsAsm) ? " OR " : " || "); } if (ApiPlatform & API_NTx) { BYTE Plat = (ApiPlatform & API_NTx) >> API_SHIFT_NTx; fprintf(pCGenState->CGen->fp, (fIsAsm) ? AsmPlatformSwitches[Plat] : CPlatformSwitches[Plat], "_WIN32_WINNT" ); } if (pCGenState->ListCol) { WriteListColumn(pCGenState); } else { fprintf(pCGenState->CGen->fp, "\n"); } } void PlatformSwitchEnd( PCGENSTATE pCGenState, BYTE ApiPlatform ) { if (ApiPlatform != API_ALL) { if (strcmp(pCGenState->Temple->Comment, ";") == 0) { fprintf(pCGenState->CGen->fp, "\nendif ; _WIN32_WIN...\n"); } else { fprintf(pCGenState->CGen->fp, "\n#endif // _WIN32_WIN...\n"); } if (pCGenState->ListCol) { WriteListColumn(pCGenState); } else { fprintf(pCGenState->CGen->fp, "\n"); } } } void PlatformSwitchEndTable( PCGENSTATE pCGenState, BYTE ApiPlatform ) { if (ApiPlatform != API_ALL) { if (strcmp(pCGenState->Temple->Comment, ";") == 0) { fprintf(pCGenState->CGen->fp, "\nendif ; _WIN32_WIN...\n"); } else { fprintf(pCGenState->CGen->fp, "\n#else\n {whInvalidCall, 0, 0},"); fprintf(pCGenState->CGen->fp, "\n#endif // _WIN32_WIN...\n"); } if (pCGenState->ListCol) { WriteListColumn(pCGenState); } else { fprintf(pCGenState->CGen->fp, "\n"); } } } /* * BuildArgsList * * */ void BuildArgsList(PTEMPLES pTempleEx, PFUNCINFO funcinfo, PLIST_ENTRY pListHead) { int i; ULONG Size; int OffSet=0; int ArgOffSet; PKNOWNTYPES pkt; PARGSLIST pArgsList; int NoTypeCount; char *HostCastedName; if (!IsListEmpty(pListHead)) { return; } if (!pTempleEx) { NoTypeCount = 0; } else { // // There is an [EFunc] for this API. Get the count of // NoType= entries for the EFunc. // for (NoTypeCount=0; NoTypeCountNoTypes[NoTypeCount]) { break; } } } while (funcinfo) { pkt = GetNameFromTypesList(TypeDefsList, funcinfo->sType); if (!pkt) { pkt = GetNameFromTypesList(StructsList, funcinfo->sType); if (!pkt) { ExitErrMsg(FALSE, "Unknown type %s\n", funcinfo->sType); } } // // Save the ArgOffSet, and add the args size to the cumulative // offset for the next argument. // // Round up the arg size to the next dword. Assumes intel stack // parameter passing conventions, and that all pointers are // sizeof(int *) except __ptr64 which are sizeof(PVOID64). // ArgOffSet = OffSet; Size = funcinfo->IndLevel + pkt->IndLevel ? funcinfo->fIsPtr64 ? SIZEOFPOINTER64 : SIZEOFPOINTER : pkt->Size; OffSet += ((Size + 3) & ~3) >> 2; // // Create ARGSLIST entry, and add it to the list // pArgsList = GenHeapAlloc(sizeof(ARGSLIST)); if (!pArgsList) { ExitErrMsg(TRUE, "bal.\n"); } memset(pArgsList, 0, sizeof(ARGSLIST)); if(funcinfo->sName == NULL) { HostCastedName = GenHeapAlloc(sizeof(szHOSTAPPEND)); if (NULL == HostCastedName) ExitErrMsg(FALSE, "Out of memory in BuildArgsList\n"); strcpy(HostCastedName, szHOSTAPPEND); } else { HostCastedName = GenHeapAlloc(sizeof(szHOSTAPPEND) + strlen(funcinfo->sName)); if (NULL == HostCastedName) ExitErrMsg(FALSE, "Out of memory in BuildArgsList\n"); strcpy(HostCastedName, funcinfo->sName); strcat(HostCastedName, szHOSTAPPEND); } pArgsList->pKnownTypes = pkt; pArgsList->OffSet = ArgOffSet; pArgsList->IndLevel = funcinfo->IndLevel; pArgsList->ArgSize = Size; pArgsList->IsPtr64 = funcinfo->fIsPtr64; pArgsList->Mod = funcinfo->tkPreMod; pArgsList->tkDirection = funcinfo->tkDirection; pArgsList->SUEOpt = funcinfo->tkSUE; pArgsList->Type = funcinfo->sType; pArgsList->PostMod = funcinfo->tkPostMod; pArgsList->PrePostMod = funcinfo->tkPrePostMod; pArgsList->Name = funcinfo->sName; pArgsList->HostCastedName = HostCastedName; pArgsList->fIsMember = FALSE; pArgsList->bIsBitfield = FALSE; pArgsList->BitsRequired= 0; pArgsList->bIsArray = FALSE; pArgsList->ArrayElements=0; if (pkt->Flags & BTI_CONTAINSFUNCPTR) { // // This parameter type is either a function pointer, or // a type which contains an embedded function pointer. // Something is going to have to thunk it. // pArgsList->fRequiresThunk = TRUE; } if (pTempleEx) { // // There is an [EFunc] for this API. See if this param // should have [Types] templates expanded or not. // for (i=0; iNoTypes[i] && strcmp(pArgsList->Name, pTempleEx->NoTypes[i]) == 0) { // // This param is not supposed to have [Types] expanded // pArgsList->fNoType = TRUE; pTempleEx->NoTypes[i] = NULL; } } } InsertTailList(pListHead, &pArgsList->ArgumentsEntry); // // and on to the next argument ..... // funcinfo = funcinfo->pfuncinfoNext; } if (pTempleEx) { // // For error reporting, indicate any NoTypes= that did not match // a param name // for (i=0; iNoTypes[i]) { ExitErrMsg(FALSE, "[EFunc] %s(%x) has a 'NoType=%s' which does not correspond to an argument name\n", pTempleEx->Name, pTempleEx, pTempleEx->NoTypes[i]); } } } return; } // // return pointer to type of first argument char *NArgType(PCGENSTATE pCGenState, char *s, int iLen, char **ppSrc) { PARGSLIST pArgsList; PLIST_ENTRY Next; char *pch = s; CGENSTATE CGenState; int Len, i; char *pSrc; pSrc = *ppSrc; if (*pSrc != '(') { ErrMsg("Incorrect NArgType parameter %s\n", pSrc); fprintf(pCGenState->CGen->fp, "** ERROR ** Incorrect NArgType parameter %s\n", pSrc); return NULL; } pSrc++; i = 0; while ((*pSrc != ')') && (i < iLen-1)) { s[i++] = *pSrc++; } s[i] = 0; *ppSrc = ++pSrc; Len = atoi(s); if (Len-- == 0) { ErrMsg("Invalid NArgType parameter %s\n", s); fprintf(pCGenState->CGen->fp, "** ERROR ** Invalid NArgType parameter %s\n", s); return NULL; } if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** NArgType Missing argument List: %s\n\n", pCGenState->ApiTypes->TypeName ); return NULL; } Next = pCGenState->ExportsDbg->ArgsListHead.Flink; // check for void arg list pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry); if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) { return NULL; } CGenState = *pCGenState; for (i = 0; (i < Len) && (Next != &CGenState.ExportsDbg->ArgsListHead); i++) { Next= Next->Flink; } if (Next == &CGenState.ExportsDbg->ArgsListHead) { ErrMsg("NArgType parameter out of range %d\n", Len); fprintf(pCGenState->CGen->fp, "** ERROR ** NArgType parameter out of range %d\n", Len); return NULL; } CGenState.pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry); // // Copy in the explicit struct/union/enum keyword, if present // strcat(pch, TokenString[CGenState.pArgsList->SUEOpt]); // // Copy in the actual typename // strcpy(pch, CGenState.pArgsList->Type); if (CGenState.pArgsList->PrePostMod != TK_NONE) { strcat(pch, " "); strcat(pch, TokenString[CGenState.pArgsList->PrePostMod]); } pch = pch + strlen(pch); if (CGenState.pArgsList->IndLevel) { *pch++ = ' '; for (i=0; iIndLevel; ++i) { *pch++ = '*'; } } *pch = '\0'; return(s); } // // return pointer to name of first argument char *NArgName(PCGENSTATE pCGenState, char *s, int iLen, char **ppSrc) { PARGSLIST pArgsList; PLIST_ENTRY Next; char *pch = s; CGENSTATE CGenState; int Len, i; char *pSrc; pSrc = *ppSrc; if (*pSrc != '(') { ErrMsg("Incorrect NArgType parameter %s\n", pSrc); fprintf(pCGenState->CGen->fp, "** ERROR ** Incorrect NArgType parameter %s\n", pSrc); return(NULL); } pSrc++; i = 0; while ((*pSrc != ')') && (i < iLen-1)) { s[i++] = *pSrc++; } s[i] = 0; *ppSrc = ++pSrc; Len = atoi(s); if (Len-- == 0) { ErrMsg("Invalid NArgType parameter %s\n", s); fprintf(pCGenState->CGen->fp, "** ERROR ** Invalid NArgType parameter %s\n", s); return(NULL); } if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** NArgType Missing argument List: %s\n\n", pCGenState->ApiTypes->TypeName ); return(NULL); } Next = pCGenState->ExportsDbg->ArgsListHead.Flink; // check for void arg list pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry); if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) { return(NULL); } CGenState = *pCGenState; for (i = 0; (i < Len) && (Next != &CGenState.ExportsDbg->ArgsListHead); i++) { Next= Next->Flink; } if (Next == &CGenState.ExportsDbg->ArgsListHead) { ErrMsg("NArgName parameter out of range %d\n", Len); fprintf(pCGenState->CGen->fp, "** ERROR ** NArgName parameter out of range %d\n", Len); return(NULL); } CGenState.pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry); strcpy(pch, CGenState.pArgsList->Name); return(s); } char * MArg( char *pSrc, PCGENSTATE pCGenState, PSTR *pBuffer ) /*++ Routine Description: Expand the n'th argument for the current macro Arguments: pSrc - pointer to character following 'MArg' pCGenState - current code-gen state Return Value: pointer to character following the end of the macro argument --*/ { int i; int ArgNum; PMACROARGSLIST pList = pCGenState->pMacroArgsList; char s[MAX_PATH]; PMACROARGSLIST OldList; if (!pList) { ExitErrMsg(FALSE, "%s(%d) MArg unexpected: no macro is currently being expanded\n", TemplateFileName, TemplateLine); return NULL; } if (*pSrc != '(') { ExitErrMsg(FALSE, "%s(%d) Incorrect MArg parameter %s\n", TemplateFileName, TemplateLine, pSrc); return NULL; } pSrc++; i = 0; while ((*pSrc != ')') && (i < sizeof(s)-1)) { s[i++] = *pSrc++; } s[i] = 0; ArgNum = atoi(s); pSrc++; // skip ')' if (ArgNum-- == 0) { ExitErrMsg(FALSE, "%s(%d) Invalid MArg parameter %s\n", TemplateFileName, TemplateLine, s); return NULL; } if (ArgNum >= pList->NumArgs) { ExitErrMsg(FALSE, "%s(%d) Macro only takes %d arguments\n", TemplateFileName, TemplateLine, pList->NumArgs); return NULL; } if (pBuffer == NULL) { OldList = pCGenState->pMacroArgsList; pCGenState->pMacroArgsList = MacroStack[--MacroStackTop]; CGenerate(pList->ArgText[ArgNum], pCGenState); MacroStack[MacroStackTop++] = pCGenState->pMacroArgsList; pCGenState->pMacroArgsList = OldList; } else { *pBuffer = pList->ArgText[ArgNum]; } return pSrc; } char *ArgType(char *Buffer, PCGENSTATE pCGenState) { char *pch; if (pCGenState->pArgsList) { int i; pch = Buffer; if (pCGenState->pArgsList->SUEOpt != TK_NONE) { strcpy(pch, TokenString[pCGenState->pArgsList->SUEOpt]); strcat(pch, " "); pch += strlen(pch); } strcpy(pch, pCGenState->pArgsList->Type); if (pCGenState->pArgsList->PrePostMod != TK_NONE) { strcat(pch, " "); strcat(pch, TokenString[pCGenState->pArgsList->PrePostMod]); } pch = pch+strlen(pch); if (pCGenState->pArgsList->IndLevel) { *pch++ = ' '; for (i=0; ipArgsList->IndLevel; ++i) { *pch++ = '*'; } } *pch = '\0'; pch = Buffer; return pch; } else return NULL; } char *UnalignedTag64(char *Buffer, PCGENSTATE pCGenState) { // // PUT UNALIGNED TAg for interested type like KLPWST KHBITMAP all kernel mode shareable struct // char CurrArgType[256]; if ( NULL == ArgType ( CurrArgType, pCGenState)) return NULL; // // Now chek the name // if ( pCGenState->pArgsList->ArgSize == 8 ) { // // BUGBUG: check if you need special case for KLPWSTR and KHBITMAP // if so put more generic form //(strncmp ( CurrAgrType, "KLPWSTR ",7) == 0) || //(strncmp ( CurrAgrType, "KHBITMAP ",8) == 0) // strcpy (Buffer, "*(UNALIGNED "); strcat (Buffer, CurrArgType); if (strchr(CurrArgType, '*') == NULL ) strcat ( Buffer, " "); strcat (Buffer, "*)&"); return Buffer; } return NULL; } char *ArgHostType(char *Buffer, PCGENSTATE pCGenState) { char *pch; if (pCGenState->pArgsList) { pch = Buffer; /*if (pCGenState->pArgsList->SUEOpt != TK_NONE) { strcpy(pch, TokenString[pCGenState->pArgsList->SUEOpt]); strcat(pch, " "); pch += strlen(pch); }*/ if (pCGenState->pArgsList->IndLevel > 0) { strcpy(pch, GetHostPointerName(pCGenState->pArgsList->IsPtr64)); pch += strlen(pch); } else { char Buffer[MAX_PATH]; strcpy(pch, GetHostTypeName(pCGenState->pArgsList->pKnownTypes, Buffer)); pch += strlen(pch); } *pch = '\0'; pch = Buffer; return pch; } else return NULL; } BOOL IsPointer(PCGENSTATE pCGenState) { return (pCGenState->pArgsList->IndLevel > 0) || (pCGenState->pArgsList->pKnownTypes->IndLevel > 0); } char *ArgTypeInd(char *Buffer, PCGENSTATE pCGenState, BOOL bHostName) { CGENSTATE GenStateOld; ARGSLIST ArgsListOld; KNOWNTYPES KnownTypes; PKNOWNTYPES pCurrent; int IndLevel; char *pch; //copy over the old structures before mangaling them GenStateOld = *pCGenState; ArgsListOld = *(pCGenState->pArgsList); KnownTypes = *(pCGenState->pArgsList->pKnownTypes); pCGenState->pArgsList->pKnownTypes = &KnownTypes; if (pCGenState->pArgsList->IndLevel > 0) { IndLevel = pCGenState->pArgsList->IndLevel - 1; goto success; } pCurrent = &KnownTypes; IndLevel = pCurrent->IndLevel; if (IndLevel == 0) { ErrMsg("ArgTypeInd: Tried to get name of type pointed to by %s\n",pCGenState->pArgsList->Name); ExitErrMsg(FALSE, "ArgTypeInd: %s is not a pointer!\n", pCGenState->pArgsList->Name); } while(1) {//chase all the way down to a struct/union/enum or a func_ptr PCHAR IndName; ASSERT(pCurrent != NULL); if (pCurrent->IndLevel == 1 && !bHostName && ((IndName = IsDefinedPtrToPtrDependent(pCurrent->TypeName)) != NULL)) { PKNOWNTYPES pkt; IndLevel--; pkt = GetNameFromTypesList(TypeDefsList, IndName); ASSERT(pkt != NULL); KnownTypes = *pkt; goto success; } else if (pCurrent->pTypedefBase != NULL) { pCurrent = pCurrent->pTypedefBase; } else { //hit a struct/union/enum or func_ptr KnownTypes = *pCurrent; pCGenState->pArgsList->pStructType = NULL; pCGenState->pArgsList->SUEOpt = TK_NONE; IndLevel--; if (pCurrent->Flags & BTI_NOTDERIVED) { pCGenState->pArgsList->SUEOpt = TK_NONE; goto success; } else if(strcmp("struct", KnownTypes.BaseName) == 0) { pCGenState->pArgsList->SUEOpt = TK_STRUCT; goto success; } else if(strcmp("union", KnownTypes.BaseName) == 0) { pCGenState->pArgsList->SUEOpt = TK_UNION; goto success; } else if(strcmp("enum", KnownTypes.BaseName) == 0) { pCGenState->pArgsList->SUEOpt = TK_ENUM; goto success; } else { ExitErrMsg(FALSE, "ArgTypeInd: Can't determine what %s is.\n", pCGenState->pArgsList->Name); } } } success: //fake out the typename and the indirection KnownTypes.IndLevel = 0; pCGenState->pArgsList->IndLevel = IndLevel; pCGenState->pArgsList->Type = KnownTypes.TypeName; //Print the mangled type, then restore the old type if (bHostName) pch = ArgHostType(Buffer, pCGenState); else pch = ArgType(Buffer, pCGenState); *pCGenState = GenStateOld; *(pCGenState->pArgsList) = ArgsListOld; return pch; } char *ApiName(char *pSrc, char**pch, char *Buffer, PCGENSTATE pCGenState) { char *pTemp; strcpy(Buffer, pCGenState->ExportsDbg->ExportName); // if ApiName has decoration then truncate it pTemp = strchr(Buffer, '@'); if (pTemp) { *pTemp = '\0'; } *pch = Buffer; return pSrc; } char *ApiNameSkip(char *pSrc, char**pch, char *Buffer, PCGENSTATE pCGenState) { char *pNewSrc, *pTemp, *pEnd; int CharsToSkip; pNewSrc = ApiName(pSrc, pch, Buffer, pCGenState); pEnd = SkipSubExpression(pNewSrc, NULL); if (pNewSrc == pEnd) return pNewSrc; pTemp = pNewSrc+1; CharsToSkip = atoi(pTemp); while(**pch != '\0' && CharsToSkip > 0) { (*pch)++; CharsToSkip--; } return pEnd; } BOOL IsPointerToPtrDep(PARGSLIST pArgsList) { PKNOWNTYPES pCurrent; pCurrent = pArgsList->pKnownTypes; if (pArgsList->IndLevel + pCurrent->IndLevel < 1) ExitErrMsg(FALSE, "IsPointerToPtrDep: %s is not a pointer\n", pArgsList->Name); if (pArgsList->IndLevel + pCurrent->IndLevel > 1) { // Since pCurrent->IndLevel is acumulative, this can happen if and // only if this type or one of its base types is a pointer to // another pointer. This case is defined to be pointer dependent. return TRUE; } // At this point, either pArgsList->IndLevel == 1 and pCurrent->IndLevel == 0 // or pArgsList->IndLevel == 0 and pCurrent->IndLevel = 1. // First check if this type is defined to be a pointer to a pointer dependent type. // If not, defererence the pointer by walking through typedefs until pCurrent->IndLevel = 0 // Note that multiple levels of pointers are no longer possible. if(IsDefinedPtrToPtrDependent(pCurrent->TypeName)) { return TRUE; } while(pCurrent->IndLevel != 0) { // Check if this type is one of the special types used // between sortpp and genthnk. if (pCurrent->Flags & BTI_NOTDERIVED) return FALSE; // Assert that this type is not a struct, union, or enum. // This shouldn't happen because sortpp should store // these with an indlevel of 0. ASSERT(strcmp(pCurrent->BaseName, "struct") != 0); ASSERT(strcmp(pCurrent->BaseName, "union") != 0); ASSERT(strcmp(pCurrent->BaseName, "enum") != 0); // Check if this type is a function pointer. If it is, // return FALSE since they are arbitrarly defined to not // be pointer dependent. This may be changed check if any // of the arguments to the function pointer are pointer dependent. if (strcmp(pCurrent->BaseName, "()") == 0) return FALSE; // Get the base typedef. pCurrent = pCurrent->pTypedefBase; } // Now that the pointer has been dereferenced, test if // this type is pointer dependent. return (pCurrent->Flags & BTI_POINTERDEP) != 0; } char *TestIfPointerToPtrDep(char *pSrc, PCGENSTATE pCGenState, PCHAR pch) { PCHAR pEnd; PMACROARGSLIST pMArgsList; ARGSLIST ArgsList; CHAR TypeName[MAX_PATH]; SIZE_T BytesReturned; pEnd = SkipSubExpression(pSrc, NULL); if (pSrc == pEnd) { ExitErrMsg(FALSE, "TestIfPointerToPtrDep: exactly 1 argument is required.\n"); } ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList); if (pMArgsList->NumArgs != 1) { ExitErrMsg(FALSE, "IncludeRetTypes: exactly 1 argument is required.\n"); } CGenerateEx(pMArgsList->ArgText[0], pCGenState, TypeName, MAX_PATH, &BytesReturned); SetArgListToTypeForArg(&ArgsList, &ArgsList, TypeName); if(IsPointerToPtrDep(&ArgsList)) { strcpy(pch, "1"); } else { strcpy(pch, "0"); } FreeMacroArgsList(pMArgsList); return pEnd; } BOOL IsPtrDep(PARGSLIST pArgsList) { //This is a pointer to something(ptr dep.) if (pArgsList->IndLevel > 0) return TRUE; return pArgsList->pKnownTypes->Flags & ( BTI_POINTERDEP | BTI_INT64DEP ); } BOOL IsInt64DepUnion(PCGENSTATE pCGenState) { char Buff[256]; Buff[0]=0; ArgTypeInd( Buff, pCGenState, FALSE); // make exception for union _ULARGE_INTEGER if (strncmp(Buff, "union _ULARGE_INTEGER", sizeof ("union _ULARGE_INTEGER")) == 0 ) return TRUE; //IsPointerToPtrDep ( pArgsList ); if (strncmp(Buff, "union _LARGE_INTEGER", sizeof ("union _LARGE_INTEGER")) == 0 ) return TRUE; //IsPointerToPtrDep ( pArgsList ); return FALSE; //pArgsList->pKnownTypes->Flags & BTI_INT64DEP; } void DoIndent(PCGENSTATE pCGenState) { int i; for(i=IndentLevel, OutputColumn = 1; i > 0; i--,OutputColumn++) { if (fputc(' ', pCGenState->CGen->fp) != ' ') ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC); OutputColumn++; } } char * CGeneratePrintChar(char *pch, PCGENSTATE pCGenState) { if (!bStripNewline) { if('\n' == *pch) { //bFirstCharHit = FALSE; OutputColumn = 0; //will be incremented to 1 } goto PrintIt; } else { if (*pch == '\n') goto SkipIt; if (!bFirstCharHit) { if(!isspace(*pch)) { DoIndent(pCGenState); bFirstCharHit = TRUE; goto PrintIt; } else goto SkipIt; } else goto PrintIt; } PrintIt: if (fputc(*pch, pCGenState->CGen->fp) != *pch) goto PrintError; OutputColumn++; SkipIt: return pch + 1; PrintError: ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC); return NULL; } char *CGenerate(char *pSrc, PCGENSTATE pCGenState) { return CGenerateEx(pSrc, pCGenState, NULL, 0, NULL); } /* * CGenerate * */ char *CGenerateEx(char *pSrc, PCGENSTATE pCGenState, char *OutBuffer, SIZE_T MaxLen, SIZE_T *BytesReturned) { FILE **pfp = &pCGenState->CGen->fp; char *pch; size_t Len; char Buffer[MAX_PATH*4]; char *BufferPos = NULL; if (OutBuffer != NULL) { BufferPos = OutBuffer; *BytesReturned = 0; } while (*pSrc) { if (OutBuffer != NULL && MaxLen == 0) { ExitErrMsg(FALSE, "Out of buffer space!\n"); } if (*pSrc != '@') { if (OutBuffer != NULL) { *BufferPos++ = *pSrc++; *BytesReturned += 1; MaxLen--; } else { pSrc = CGeneratePrintChar(pSrc, pCGenState); } } else if (*(pSrc + 1) == '@') { pSrc++; if (OutBuffer != NULL) { *BufferPos++ = *pSrc++; *BytesReturned += 1; MaxLen--; } else { pSrc = CGeneratePrintChar(pSrc, pCGenState); } } else { #define ELSE(f) \ if ( *pSrc == '@' && \ !strncmp(pSrc+1, szELSE, sizeof(szELSE) - 1)) { \ pSrc += sizeof(szELSE) - 1+1; \ pSrc = WriteMore(pSrc, pCGenState, !(f)); \ } pch = NULL; memset(Buffer, 0, sizeof(Buffer)); pSrc++; //skip the @ is the command name if(bStripNewline && !bFirstCharHit) { OutputColumn = 1 + IndentLevel; } if (!strncmp(pSrc, szNL, sizeof(szNL) - 1)) { pSrc += sizeof(szNL) - 1; if (fputc('\n', *pfp) != '\n') ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC); OutputColumn = 1; bFirstCharHit = FALSE; } else if (!strncmp(pSrc, szINDENT, sizeof(szINDENT) - 1)) { int OldIndent; pSrc += sizeof(szINDENT) - 1; OldIndent = IndentLevel; IndentLevel += INDENTSIZE; pSrc = WriteMore(pSrc, pCGenState, TRUE); IndentLevel = OldIndent; } else if (!strncmp(pSrc, szNOFORMAT, sizeof(szNOFORMAT) - 1)) { BOOL bOldStripNewline; pSrc += sizeof(szNOFORMAT) - 1; bOldStripNewline = bStripNewline; bStripNewline = FALSE; pSrc = WriteMore(pSrc, pCGenState, TRUE); bStripNewline = bOldStripNewline; } else if (!strncmp(pSrc, szTEMPLATE, sizeof(szTEMPLATE) - 1)) { pSrc += sizeof(szTEMPLATE) - 1; pSrc = IncludeTemplate(pSrc, pCGenState); } else if (!strncmp(pSrc, szAPILIST, sizeof(szAPILIST) - 1)) { pSrc += sizeof(szAPILIST) - 1; pSrc = ListApis(pSrc, pCGenState, FALSE); } else if (!strncmp(pSrc, szAPINAMESKIP, sizeof(szAPINAMESKIP) -1 )) { pSrc += sizeof(szAPINAMESKIP) - 1; pSrc = ApiNameSkip(pSrc, &pch, Buffer, pCGenState); } else if (!strncmp(pSrc, szAPINAME, sizeof(szAPINAME) - 1)) { pSrc += sizeof(szAPINAME) - 1; pSrc = ApiName(pSrc, &pch, Buffer, pCGenState); } else if (!strncmp(pSrc, szAPIFORWARD, sizeof(szAPIFORWARD) - 1)) { pSrc += sizeof(szAPIFORWARD) - 1; if (pCGenState->ExportsDbg->IntForward) { strcpy(Buffer, szINTFORWARD); strcpy(Buffer + sizeof(szINTFORWARD) - 1, pCGenState->ExportsDbg->IntForward->ExportName ); } else { strcpy(Buffer, pCGenState->ExportsDbg->ExportName); } // if ApiName has decoration then truncate it pch = strchr(Buffer, '@'); if (pch) { *pch = '\0'; } pch = Buffer; } else if (!strncmp(pSrc, szAPINUM, sizeof(szAPINUM) - 1)) { _itoa(pCGenState->ApiNum, Buffer, 10); pch = Buffer; pSrc += sizeof(szAPINUM) - 1; } else if (!strncmp(pSrc, szAPIFNRET, sizeof(szAPIFNRET) - 1)) { if (pCGenState->ApiTypes) { pch = pCGenState->ApiTypes->FuncRet; } pSrc += sizeof(szAPIFNRET) - 1; } else if (!strncmp(pSrc, szAPIDECLSPEC, sizeof(szAPIDECLSPEC) - 1)) { BOOL b = pCGenState->ApiTypes && (pCGenState->ApiTypes->Flags & BTI_DLLEXPORT); pSrc += sizeof(szAPIDECLSPEC) - 1; pSrc = WriteMore(pSrc, pCGenState, b); } else if (!strncmp(pSrc, szAPIFNMOD, sizeof(szAPIFNMOD) - 1)) { if (pCGenState->ApiTypes) { pch = pCGenState->ApiTypes->FuncMod; } pSrc += sizeof(szAPIFNMOD) - 1; } else if (!strncmp(pSrc, szAPIMORE, sizeof(szAPIMORE) - 1)) { pSrc += sizeof(szAPIMORE) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->MoreApis); } else if (!strncmp(pSrc, szIFAPIRET, sizeof(szIFAPIRET) - 1)) { BOOL fResult = FALSE; pSrc += sizeof(szIFAPIRET) - 1; pSrc = IfApiRet(pSrc, pCGenState, &fResult); ELSE(fResult); } else if (!strncmp(pSrc, szDOESAPIRETURNVOID, sizeof(szDOESAPIRETURNVOID) - 1)) { BOOL fResult = FALSE; pSrc += sizeof(szDOESAPIRETURNVOID) - 1; pSrc = DoesApiReturnVoid(pSrc, pCGenState, &fResult); WriteBoolean(Buffer, fResult); pch = Buffer; } else if (!strncmp(pSrc, szIFISMEMBER, sizeof(szIFISMEMBER) - 1)) { pSrc += sizeof(szIFISMEMBER) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->pArgsList->fIsMember); } else if (!strncmp(pSrc, szIFNISMEMBER, sizeof(szIFNISMEMBER) - 1)) { pSrc += sizeof(szIFNISMEMBER) - 1; pSrc = WriteMore(pSrc, pCGenState, !(pCGenState->pArgsList->fIsMember)); } else if (!strncmp(pSrc, szIFISBITFIELD, sizeof(szIFISBITFIELD) - 1)) { pSrc += sizeof(szIFISBITFIELD) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->pArgsList->bIsBitfield); } else if (!strncmp(pSrc, szIFNISBITFIELD, sizeof(szIFNISBITFIELD) - 1)) { pSrc += sizeof(szIFNISBITFIELD) - 1; pSrc = WriteMore(pSrc, pCGenState, !(pCGenState->pArgsList->bIsBitfield)); } else if (!strncmp(pSrc, szIFISARRAY, sizeof(szIFISARRAY) - 1)) { pSrc += sizeof(szIFISARRAY) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->pArgsList->bIsArray); } else if (!strncmp(pSrc, szIFNISARRAY, sizeof(szIFNISARRAY) - 1)) { pSrc += sizeof(szIFNISARRAY) - 1; pSrc = WriteMore(pSrc, pCGenState, !(pCGenState->pArgsList->bIsArray)); } else if (!strncmp(pSrc, szARGARRAYELEMENTS, sizeof(szARGARRAYELEMENTS) - 1)) { pSrc += sizeof(szARGARRAYELEMENTS) - 1; _itoa((int)(pCGenState->pArgsList->ArrayElements), Buffer, 10); pch = Buffer; } else if (!strncmp(pSrc, szIFPOINTERTOPTRDEP, sizeof(szIFPOINTERTOPTRDEP) -1 )) { pSrc += sizeof(szIFPOINTERTOPTRDEP) - 1; pSrc = WriteMore(pSrc, pCGenState, IsPointerToPtrDep(pCGenState->pArgsList)); } else if (!strncmp(pSrc, szIFNPOINTERTOPTRDEP, sizeof(szIFNPOINTERTOPTRDEP) -1 )) { pSrc += sizeof(szIFNPOINTERTOPTRDEP) - 1; pSrc = WriteMore(pSrc, pCGenState, !IsPointerToPtrDep(pCGenState->pArgsList)); } else if (!strncmp(pSrc, szISPOINTERTOPTRDEP, sizeof(szISPOINTERTOPTRDEP) -1 )) { pSrc += sizeof(szISPOINTERTOPTRDEP) - 1; pch = Buffer; pSrc = TestIfPointerToPtrDep(pSrc, pCGenState, pch); } else if (!strncmp(pSrc, szIFPTRDEP, sizeof(szIFPTRDEP) -1 )) { pSrc += sizeof(szIFPTRDEP) - 1; pSrc = WriteMore(pSrc, pCGenState, IsPtrDep(pCGenState->pArgsList)); } else if (!strncmp(pSrc, szIFNPTRDEP, sizeof(szIFNPTRDEP) -1 )) { pSrc += sizeof(szIFNPTRDEP) - 1; pSrc = WriteMore(pSrc, pCGenState, !IsPtrDep(pCGenState->pArgsList)); } else if (!strncmp(pSrc, szIFINT64DEPUNION, sizeof(szIFINT64DEPUNION) -1 )) { pSrc += sizeof(szIFINT64DEPUNION) - 1; pSrc = WriteMore(pSrc, pCGenState, IsInt64DepUnion(pCGenState)); } else if (!strncmp(pSrc, szIFNINT64DEPUNION, sizeof(szIFNINT64DEPUNION) -1 )) { pSrc += sizeof(szIFNINT64DEPUNION) - 1; pSrc = WriteMore(pSrc, pCGenState, !IsInt64DepUnion(pCGenState)); } else if (!strncmp(pSrc, szIFAPICODE, sizeof(szIFAPICODE) - 1)) { BOOL fResult = FALSE; pSrc += sizeof(szIFAPICODE) - 1; pSrc = IfApiCode(pSrc, pCGenState, &fResult); ELSE(fResult); } else if (!strncmp(pSrc, szFASTCALL, sizeof(szFASTCALL) - 1)) { pSrc += sizeof(szFASTCALL) - 1; pSrc = WriteMore(pSrc, pCGenState, IsFastCall(pCGenState)); } else if (!strncmp(pSrc, szSLOWCALL, sizeof(szSLOWCALL) - 1)) { pSrc += sizeof(szSLOWCALL) - 1; pSrc = WriteMore(pSrc, pCGenState, !IsFastCall(pCGenState)); } else if (!strncmp(pSrc, szFASTX2NMETH, sizeof(szFASTX2NMETH) - 1)) { pSrc += sizeof(szFASTX2NMETH) - 1; pSrc = WriteMore(pSrc, pCGenState, GetX2NMethodType(pCGenState) == FASTX2NMETHOD); } else if (!strncmp(pSrc, szSLOWX2NMETH, sizeof(szSLOWX2NMETH) - 1)) { pSrc += sizeof(szSLOWX2NMETH) - 1; pSrc = WriteMore(pSrc, pCGenState, GetX2NMethodType(pCGenState) == SLOWX2NMETHOD); } else if (!strncmp(pSrc, szFATX2NMETH, sizeof(szFATX2NMETH) - 1)) { pSrc += sizeof(szFATX2NMETH) - 1; pSrc = WriteMore(pSrc, pCGenState, GetX2NMethodType(pCGenState) == FATX2NMETHOD); } else if (!strncmp(pSrc, szMETHODNUMBER, sizeof(szMETHODNUMBER) - 1)) { pSrc += sizeof(szMETHODNUMBER) - 1; _itoa(pCGenState->ExportsDbg->MethodNumber, Buffer, 10); pch = Buffer; } else if (!strncmp(pSrc, szIFARGS, sizeof(szIFARGS) - 1)) { BOOL fResult = FALSE; pSrc += sizeof(szIFARGS) - 1; pSrc = IfArgs(pSrc, pCGenState, &fResult); ELSE(fResult); } else if (!strncmp(pSrc, szFUNCARGNUM, sizeof(szFUNCARGNUM) - 1)) { pSrc += sizeof(szFUNCARGNUM) - 1; _itoa(GetFuncArgNum(pCGenState), Buffer, 10); pch = Buffer; } else if (!strncmp(pSrc, szRETSIZE, sizeof(szRETSIZE) - 1)) { pSrc += sizeof(szRETSIZE) - 1; _itoa(GetRetSize(pCGenState), Buffer, 10); pch = Buffer; } else if (!strncmp(pSrc, szARGSIZE, sizeof(szARGSIZE) - 1)) { pSrc += sizeof(szARGSIZE) - 1; _itoa(GetArgSize(pCGenState->ExportsDbg), Buffer, 10); pch = Buffer; } else if (!strncmp(pSrc, szFORCASE, sizeof(szFORCASE) - 1)) { pSrc += sizeof(szFORCASE) - 1; pSrc = ForCase(pSrc, pCGenState); } else if (!strncmp(pSrc, szCARGEXIST, sizeof(szCARGEXIST) - 1)) { pSrc += sizeof(szCARGEXIST) - 1; if (OutBuffer != NULL) { pSrc = CArg(pSrc, pCGenState, &pch, TRUE); } else { pSrc = CArg(pSrc, pCGenState, NULL, TRUE); } } else if (!strncmp(pSrc, szCARG, sizeof(szCARG) - 1)) { pSrc += sizeof(szCARG) - 1; if (OutBuffer != NULL) { pSrc = CArg(pSrc, pCGenState, &pch, FALSE); } else { pSrc = CArg(pSrc, pCGenState, NULL, FALSE); } } else if (!strncmp(pSrc, szCNUMBER, sizeof(szCNUMBER) - 1)) { pSrc += sizeof(szCNUMBER) - 1; _itoa(pCGenState->CaseNumber, Buffer, 10); pch = Buffer; } else if (!strncmp(pSrc, szARGLIST, sizeof(szARGLIST) - 1)) { pSrc += sizeof(szARGLIST) - 1; if (pCGenState->ApiTypes) { pSrc = ListArgs(pSrc, pCGenState, TRUE); } } else if (!strncmp(pSrc, szNARGTYPE, sizeof(szNARGTYPE) - 1)) { pSrc += sizeof(szNARGTYPE) - 1; pch = NArgType(pCGenState, Buffer, sizeof(Buffer), &pSrc); } else if (!strncmp(pSrc, szNARGNAME, sizeof(szNARGNAME) - 1)) { pSrc += sizeof(szNARGNAME) - 1; pch = NArgName(pCGenState, Buffer, sizeof(Buffer), &pSrc); } else if (!strncmp(pSrc, szMARG, sizeof(szMARG) - 1)) { pSrc += sizeof(szMARG) - 1; if (OutBuffer != NULL) { pSrc = MArg(pSrc, pCGenState, &pch); } else { pSrc = MArg(pSrc, pCGenState, NULL); } } else if (!strncmp(pSrc, szFORCETYPE, sizeof(szFORCETYPE) - 1)) { pSrc += sizeof(szFORCETYPE) - 1; pSrc = ForceTypeExpand( pSrc, pCGenState); } else if (!strncmp(pSrc, szMEMBERTYPES, sizeof(szMEMBERTYPES) - 1)) { pSrc += sizeof(szMEMBERTYPES) - 1; pSrc = MemberTypes( pSrc, pCGenState, FALSE); } else if (!strncmp(pSrc, szBTOTMEMBERTYPES, sizeof(szBTOTMEMBERTYPES) - 1)) { pSrc += sizeof(szBTOTMEMBERTYPES) - 1; pSrc = MemberTypes( pSrc, pCGenState, TRUE); } else if (!strncmp(pSrc, szLOG, sizeof(szLOG) - 1)) { pSrc += sizeof(szLOG) - 1; pSrc = UpdateLog(pSrc, pCGenState); } else if (!strncmp(pSrc, szIFRETTYPE, sizeof(szIFRETTYPE) - 1)) { BOOL fResult = FALSE; pSrc += sizeof(szIFRETTYPE) - 1; pSrc = IfRetType(pSrc, pCGenState, &fResult); ELSE(fResult); } else if (!strncmp(pSrc, szIFNOTRETTYPE, sizeof(szIFNOTRETTYPE) - 1)) { pSrc += sizeof(szIFNOTRETTYPE) - 1; pSrc = IfNotRetType(pSrc, pCGenState); } else if (!strncmp(pSrc, szARGMOD, sizeof(szARGMOD) - 1)) { pSrc += sizeof(szARGMOD) - 1; if (pCGenState->pArgsList) { pch = TokenString[pCGenState->pArgsList->Mod]; } } else if (!strncmp(pSrc, szARGPOSTMOD, sizeof(szARGPOSTMOD) - 1)) { pSrc += sizeof(szARGPOSTMOD) - 1; if (pCGenState->pArgsList) { pch = TokenString[pCGenState->pArgsList->PostMod]; } } else if (!strncmp(pSrc, szARGTYPEIND, sizeof(szARGTYPEIND) - 1)) { pSrc += sizeof(szARGTYPEIND) - 1; pch = ArgTypeInd(Buffer, pCGenState, FALSE); } else if (!strncmp(pSrc, szARGHOSTTYPEIND, sizeof(szARGHOSTTYPEIND) - 1)) { pSrc += sizeof(szARGHOSTTYPEIND) - 1; pch = ArgTypeInd(Buffer, pCGenState, TRUE); } else if (!strncmp(pSrc, szARGHOSTTYPE, sizeof(szARGHOSTTYPE) -1 )) { pSrc += sizeof(szARGHOSTTYPE) - 1; pch = ArgHostType(Buffer, pCGenState); } else if (!strncmp(pSrc, szARGTYPE, sizeof(szARGTYPE) - 1)) { pSrc += sizeof(szARGTYPE) - 1; pch = ArgType(Buffer, pCGenState); } else if (!strncmp(pSrc, szUNALIGNEDTAG64, sizeof(szUNALIGNEDTAG64) - 1)) { pSrc += sizeof(szUNALIGNEDTAG64) - 1; pch = UnalignedTag64(Buffer, pCGenState); } else if (!strncmp(pSrc, szARGNAME, sizeof(szARGNAME) - 1)) { if (pCGenState->pArgsList) { pch = pCGenState->pArgsList->Name; if (!pch) { pch = ""; } } pSrc += sizeof(szARGNAME) - 1; } else if (!strncmp(pSrc, szARGNAMEHOSTCASTED, sizeof(szARGNAMEHOSTCASTED) - 1)) { if (pCGenState->pArgsList) { pch = pCGenState->pArgsList->HostCastedName; if (!pch) { if (pCGenState->pArgsList->Name == NULL) pch = ""; else pch = pCGenState->pArgsList->Name; } } pSrc += sizeof(szARGNAMEHOSTCASTED) - 1; } else if (!strncmp(pSrc, szARGVAL, sizeof(szARGVAL) - 1)) { if (pCGenState->pArgsList) { strcpy(Buffer, pCGenState->pArgsList->Name); // replace all occurrences of '->' by '__' // and '.', '*', ')', and '(' by '_' pch = Buffer; while (*pch) { if (*pch == '.' || *pch == ')' || *pch == '(' || *pch == '*') *pch = '_'; else if (*pch == '-' && *(pch+1) == '>') { *pch = '_'; *(pch+1) = '_'; pch++; } pch++; } pch = Buffer; } else { pch = ""; } pSrc += sizeof(szARGVAL) - 1; } else if (!strncmp(pSrc, szARGOFF, sizeof(szARGOFF) - 1)) { pSrc += sizeof(szARGOFF) - 1; if (pCGenState->pArgsList) { _itoa(pCGenState->pArgsList->OffSet, Buffer, 10); pch = Buffer; } } else if (!strncmp(pSrc, szARGADDR, sizeof(szARGADDR) - 1)) { pSrc += sizeof(szARGADDR) - 1; if (pCGenState->pArgsList) { if (pCGenState->pArgsList->ArgLocal) { pch = Buffer; *pch = '&'; strcpy(pch+1, pCGenState->pArgsList->ArgLocal); pSrc = SkipSubExpression(pSrc, NULL); } else { pch = Buffer; pSrc = WriteArgAddr(pSrc, pCGenState, pch, sizeof(Buffer)-1 ); } } } else if (!strncmp(pSrc, szADDRARGSLIST, sizeof(szADDRARGSLIST) - 1)) { pSrc += sizeof(szADDRARGSLIST) - 1; pch = GetAddrFirstArg(pCGenState, Buffer, sizeof(Buffer) - 1); } else if (!strncmp(pSrc, szARGLOCAL, sizeof(szARGLOCAL) - 1)) { pSrc += sizeof(szARGLOCAL) - 1; if (pCGenState->pArgsList) { pch = Buffer; if (!WriteArgLocal(pCGenState, pch, sizeof(Buffer)-1)) { ExitErrMsg(FALSE, "CGenerate failed\n"); } } } else if (!strncmp(pSrc, szARGMORE, sizeof(szARGMORE) - 1)) { pSrc += sizeof(szARGMORE) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->pArgsList && pCGenState->pArgsList->ArgumentsEntry.Flink != &pCGenState->ExportsDbg->ArgsListHead ); } else if (!strncmp(pSrc, szTYPES, sizeof(szTYPES) - 1)) { pSrc += sizeof(szTYPES) - 1; pSrc = IncludeTypes(pSrc, pCGenState, FALSE); } else if (!strncmp(pSrc, szRTOLTYPES, sizeof(szRTOLTYPES) - 1)) { pSrc += sizeof(szRTOLTYPES) - 1; pSrc = IncludeTypes(pSrc, pCGenState, TRUE); } else if (!strncmp(pSrc, szRETTYPE, sizeof(szRETTYPE) - 1)) { pSrc += sizeof(szRETTYPE) - 1; pSrc = IncludeRetType(pSrc, pCGenState); } else if (!strncmp(pSrc, szEXPORTLIST, sizeof(szEXPORTLIST) - 1)) { pSrc += sizeof(szEXPORTLIST) - 1; pSrc = ListApis(pSrc, pCGenState, TRUE); } else if (!strncmp(pSrc, szEXPNAME, sizeof(szEXPNAME) - 1)) { pSrc += sizeof(szEXPNAME) - 1; pch = pCGenState->ExportsDbg->ExportName; } else if (!strncmp(pSrc, szIFEXPFORWARD, sizeof(szIFEXPFORWARD) - 1)) { pSrc += sizeof(szIFEXPFORWARD) - 1; pch = GetAltExportName(Buffer, pCGenState, sizeof(Buffer) - 1); } else if (!strncmp(pSrc, szIFORDINALS, sizeof(szIFORDINALS) - 1)) { pSrc += sizeof(szIFORDINALS) - 1; if (pCGenState->ExportsDbg && (pCGenState->ExportsDbg->Ordinal & 0x80000000)) { pch = Buffer; *pch = '@'; _itoa(IMPORDINAL(pCGenState->ExportsDbg->Ordinal), pch + 1, 10 ); } } else if (!strncmp(pSrc, szLISTCOL, sizeof(szLISTCOL) - 1)) { pSrc += sizeof(szLISTCOL) - 1; pCGenState->ListCol = OutputColumn; } else if (!strncmp(pSrc, szDLLNAME, sizeof(szDLLNAME) - 1)) { Len = CopyToken(Buffer, DllBaseName, sizeof(Buffer) - 1); if (Len >= sizeof(Buffer) - 1) { ExitErrMsg(FALSE, "OverFlow %s\n", pSrc); } pch = Buffer; pSrc += sizeof(szDLLNAME) - 1; } else if (!strncmp(pSrc, szXPTNAME, sizeof(szXPTNAME) - 1)) { Len = CopyToken(Buffer, XptBaseName, sizeof(Buffer) - 1); if (Len >= sizeof(Buffer) - 1) { ExitErrMsg(FALSE, "OverFlow %s\n", pSrc); } pch = Buffer; pSrc += sizeof(szXPTNAME) - 1; } else if (!strncmp(pSrc, szDLLTARGET, sizeof(szDLLTARGET) - 1)) { Len = CopyToken(Buffer, pCGenState->CGen->FileBaseNameC, sizeof(Buffer) - 1); if (Len >= sizeof(Buffer) - 1) { ExitErrMsg(FALSE, "Overflow %s\n", pSrc); } pch = Buffer; pSrc += sizeof(szDLLTARGET) - 1; } else if (!strncmp(pSrc, szAPIUNKNOWN, sizeof(szAPIUNKNOWN) - 1)) { pSrc += sizeof(szAPIUNKNOWN) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->ExportsDbg->UnKnownApi ); } else if (!strncmp(pSrc, szAPINODECL, sizeof(szAPINODECL) - 1)) { pSrc += sizeof(szAPINODECL) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->ExportsDbg->UnKnownApi == 1 ); } else if (!strncmp(pSrc, szISAPIDECLARED, sizeof(szISAPIDECLARED) - 1)) { pSrc += sizeof(szISAPIDECLARED) - 1; WriteBoolean(Buffer, pCGenState->ExportsDbg->UnKnownApi == 0); pch = Buffer; } else if (!strncmp(pSrc, szAPISTRINGS, sizeof(szAPISTRINGS) - 1)) { pSrc += sizeof(szAPISTRINGS) - 1; if (pCGenState->ApiTypes) { ApiStrings(pCGenState); } } else if (!strncmp(pSrc, szDBGSINDEX, sizeof(szDBGSINDEX) - 1)) { char *pExpression, *pFree; int Index; pSrc += sizeof(szDBGSINDEX) - 1; pch = pSrc; pSrc = SkipSubExpression(pch, &pFree); if (pSrc != pch) { if (!pFree && pCGenState->pArgsList ) { pExpression = pCGenState->pArgsList->Type; } else { pExpression = pFree; } Index = GetFuncIndex(pCGenState, pExpression); if (Index == -1) { ExitErrMsg(FALSE, "DebugsIndex unknown! %s\n", pch); } _itoa(Index, Buffer, 10); pch = Buffer; if (pFree) { GenHeapFree(pFree); } } else { pch = NULL; } } else if (!strncmp(pSrc, szDBGSLIST, sizeof(szDBGSLIST) - 1)) { pSrc += sizeof(szDBGSLIST) - 1; pSrc = ListDbgs(pSrc, pCGenState); } else if (!strncmp(pSrc, szDBGSSTRINGS, sizeof(szDBGSSTRINGS) - 1)) { pSrc += sizeof(szDBGSSTRINGS) - 1; WriteDbgsStrings(pSrc, pCGenState); } else if (!strncmp(pSrc, szDBGSMORE, sizeof(szDBGSMORE) - 1)) { pSrc += sizeof(szDBGSMORE) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->MoreApis); } else if (!strncmp(pSrc, szOFFSET, sizeof(szOFFSET) - 1)) { pSrc += sizeof(szOFFSET) - 1; pSrc = GetOffSet(pSrc, Buffer); pch = Buffer; } else if (!strncmp(pSrc, szCPPEXPORT, sizeof(szCPPEXPORT) - 1)) { pSrc += sizeof(szCPPEXPORT) - 1; pSrc = WriteMore(pSrc, pCGenState, iHandleCpp > 0 && pCGenState->ExportsDbg->CplusDecoration ); } else if (!strncmp(pSrc, szCEXPORT, sizeof(szCEXPORT) - 1)) { pSrc += sizeof(szCEXPORT) - 1; pSrc = WriteMore(pSrc, pCGenState, !(iHandleCpp > 0 && pCGenState->ExportsDbg->CplusDecoration) ); } else if (!strncmp(pSrc, szCPPOUTPUT, sizeof(szCPPOUTPUT) - 1)) { pSrc += sizeof(szCPPOUTPUT) - 1; if (pCGenState->CGen->FileNameCpp != NULL) { pCGenState->CGen->fp = pCGenState->CGen->fpCpp; } } else if (!strncmp(pSrc, szCOUTPUT, sizeof(szCOUTPUT) - 1)) { pSrc += sizeof(szCOUTPUT) - 1; pCGenState->CGen->fp = pCGenState->CGen->fpC; } else if (!strncmp(pSrc, szIF, sizeof(szIF) - 1)) { BOOLEAN result; pSrc += sizeof(szIF) - 1; pSrc = ExtractBoolean1(pSrc, pCGenState, &result); pSrc = WriteMore(pSrc, pCGenState, result ); ELSE(result); } else if (!strncmp(pSrc, szELSE, sizeof(szELSE) - 1)) { ExitErrMsg ( FALSE, "@Else not immediately following @If" ); } else if (!strncmp(pSrc, szOR, sizeof(szOR) - 1)) { BOOLEAN result1, result2; pSrc += sizeof(szOR) - 1; pSrc = ExtractBoolean2(pSrc, pCGenState, &result1, &result2); WriteBoolean ( Buffer, result1 || result2 ); pch = Buffer; } else if (!strncmp(pSrc, szAND, sizeof(szAND) - 1)) { BOOLEAN result1, result2; pSrc += sizeof(szAND) - 1; pSrc = ExtractBoolean2(pSrc, pCGenState, &result1, &result2); WriteBoolean ( Buffer, result1 && result2 ); pch = Buffer; } else if (!strncmp(pSrc, szNOT, sizeof(szNOT) - 1)) { BOOLEAN result1; pSrc += sizeof(szNOT) - 1; pSrc = ExtractBoolean1(pSrc, pCGenState, &result1); WriteBoolean ( Buffer, !result1); pch = Buffer; } else if (!strncmp(pSrc, szISINTFORWARD, sizeof(szISINTFORWARD) - 1)) { pSrc += sizeof(szISINTFORWARD) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->ExportsDbg->IntForward != NULL ); } else if (!strncmp(pSrc, szISNOTINTFORWARD, sizeof(szISNOTINTFORWARD) - 1)) { pSrc += sizeof(szISNOTINTFORWARD) - 1; pSrc = WriteMore(pSrc, pCGenState, pCGenState->ExportsDbg->IntForward == NULL ); } else { // // See if this is an '@macroname' // char MacroName[MAX_PATH]; char *p = MacroName; char *pIn = pSrc; SIZE_T Bytes; while (isalnum(*pIn)) { *p++ = *pIn++; } *p = '\0'; if (ExpandMacro(MacroName, pCGenState, &pIn, BufferPos, MaxLen, &Bytes)) { if (OutBuffer != NULL) { Bytes--; // subtract off terminating zero. BufferPos += Bytes; MaxLen -= Bytes; *BytesReturned += Bytes; } pSrc = pIn; } else { ExitErrMsg(FALSE, "%s(%d) Unknown keyword '@%s'", TemplateFileName, TemplateLine, MacroName); } } if (pch) { if (OutBuffer != NULL) { SIZE_T Bytes; CGenerateEx(pch, pCGenState, BufferPos, MaxLen, &Bytes); Bytes--; // subtract off terminating zero. BufferPos += Bytes; MaxLen -= Bytes; *BytesReturned += Bytes; } else { while (*pch) pch = CGeneratePrintChar(pch, pCGenState); } } } } if (OutBuffer != NULL) { if(MaxLen == 0) { ExitErrMsg(FALSE, "Out of Buffer space!\n"); } *BufferPos = '\0'; *BytesReturned += 1; } return pSrc; } int GetMemberOffset(char *sTypeName, char *sMemberName) { PKNOWNTYPES pkt = NULL; PMEMBERINFO pmi; int i; // // This is the same as running the lexer on a single identifier... // Tokens[0].TokenType = TK_IDENTIFIER; Tokens[0].Name = sTypeName; Tokens[1].TokenType = TK_EOS; CurrentTokenIndex = 0; if (ParseTypes(TypeDefsList, NULL, &pkt) && pkt != NULL) { pkt = GetBasicType(pkt->BaseName, TypeDefsList, StructsList); } else { CurrentTokenIndex = 0; ParseTypes(StructsList, NULL, &pkt); } if (pkt == NULL) { ExitErrMsg(FALSE, "GetOffSet: Unknown Type %s\n", sTypeName ); } pmi = pkt->pmeminfo; while (pmi) { if (!pmi->sName) { // // Found a nameless member. See if the member name we're // looking for is a member of this nameless member. // // ie. typedef struct { int bar; } FOO; // // typedef struct TEST { // union { // int i; // FOO; // } // } test; // // GetOffset(TEST, bar) will recurse when pmi points // at the memberinfo for the nameless member 'FOO'. // i = GetMemberOffset(pmi->sType, sMemberName); if (i != -1) { return i; } } else if (!strcmp(pmi->sName, sMemberName)) { return pmi->dwOffset; } pmi = pmi->pmeminfoNext; } return -1; } char * GetOffSet( char *pSrc, char *Buffer ) { char *pOrg = pSrc; char *pch; int Len; char TypeName[MAX_PATH]; char MemberName[MAX_PATH]; if (*pSrc != '(') { ExitErrMsg(TRUE, "GetOffset: Invalid %s\n", pSrc); return NULL; } while (IsSeparator(*pSrc)) { pSrc = GetNextToken(pSrc); if (!*pSrc || *pSrc == ')') { ExitErrMsg(TRUE, "GetOffset: Invalid %s\n", pOrg); return NULL; } } pch = TypeName; Len = sizeof(TypeName)-1; while ((*pSrc != ',') && (*pSrc != 0)) { if (!--Len) { *pch = '\0'; ExitErrMsg(TRUE, "GetOffset: Overflow %s\n", TypeName); return NULL; } *pch++ = *pSrc++; } *pch = '\0'; while (IsSeparator(*pSrc)) { pSrc = GetNextToken(pSrc); if (!*pSrc || *pSrc == ')') { ExitErrMsg(TRUE, "GetOffset: Invalid %s\n", pOrg); return NULL; } } pch = MemberName; Len = sizeof(MemberName)-1; while (!IsSeparator(*pSrc)) { if (!--Len) { *pch = '\0'; ExitErrMsg(TRUE, "GetOffset: Overflow %s\n", MemberName); return NULL; } *pch++ = *pSrc++; } *pch = '\0'; while (*pSrc && *pSrc++ != ')') { ; } Len = GetMemberOffset(TypeName, MemberName); if (Len < 0) { ExitErrMsg(FALSE, "GetOffSet: Unknown Member %s.%s\n", TypeName, MemberName ); return NULL; } _ltoa(Len, Buffer, 16); return(pSrc); } /* * GetRetSize * */ int GetRetSize(PCGENSTATE pCGenState) { PKNOWNTYPES pkt; int RetSize; if (!pCGenState->ApiTypes) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetRetSize: No Api defined\n\n" ); return -1; } // Get KnownTypes info for Return Type. Can't use the ApiTypes->pktRet // cache as ParseIndirection() needs the state of the parse. ResetLexer(); LexMacroArgs(pCGenState->ApiTypes->FuncRet); ConsumeConstVolatileOpt(); if (ParseTypes(TypeDefsList, NULL, &pkt) == FALSE) { CurrentTokenIndex = 0; if (ParseTypes(StructsList, NULL, &pkt) == FALSE ) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetRetSize: Undefind Type %s\n\n", pCGenState->ApiTypes->FuncRet ); return -1; } } if (pCGenState->ApiTypes->RetIndLevel) { RetSize = SIZEOFPOINTER; } else { RetSize = pkt->Size; } return RetSize; } /* * GetArgSize * */ int GetArgSize(PEXPORTSDEBUG ExportDebug) { PARGSLIST pArgsList; PLIST_ENTRY Next; int Total = 0; int ArgSize; if (IsListEmpty(&ExportDebug->ArgsListHead)) { return -1; } if (ExportDebug->ArgsSize >= 0) { return ExportDebug->ArgsSize; } if (ExportDebug->IntForward && ExportDebug->IntForward->ArgsSize >= 0) { ExportDebug->ArgsSize = ExportDebug->IntForward->ArgsSize; return ExportDebug->ArgsSize; } Next = ExportDebug->ArgsListHead.Flink; // check for void arg list pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry); if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) { return 0; } do { pArgsList = CONTAINING_RECORD(Next,ARGSLIST, ArgumentsEntry); ArgSize = (pArgsList->ArgSize + 3) & ~3; Total += ArgSize; Next= Next->Flink; } while (Next != &ExportDebug->ArgsListHead); ExportDebug->ArgsSize = Total; if (ExportDebug->IntForward) { ExportDebug->IntForward->ArgsSize = Total; } return Total; } /* * ApiStrings * */ void ApiStrings(PCGENSTATE pCGenState) { FILE *fp = pCGenState->CGen->fp; PLIST_ENTRY Next; PARGSLIST pArgsList; PKNOWNTYPES pkt; int ArgSize; char *pRet; char BaseName[MAX_PATH]; char *c; // copy in the DLL name and whack off the extension strcpy(BaseName, DllBaseName); c = strchr(BaseName, '.'); if (c) { *c = '\0'; } // // Write the ApiName <"ApiName", "> // fprintf(fp, "\"%s!%s\", \"", BaseName, pCGenState->ExportsDbg->ExportName); // // Write out the Args // if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) { fprintf(fp, "\n\t*** ERROR ***\n*** ArgFormat Missing argument List: %s\n\n", pCGenState->ApiTypes->TypeName ); return; } Next = pCGenState->ExportsDbg->ArgsListHead.Flink; do { pArgsList = CONTAINING_RECORD(Next,ARGSLIST, ArgumentsEntry); // check for void arg list if (!pArgsList->Name) { break; } fprintf(fp, "%s %s ", pArgsList->pKnownTypes->TypeName, pArgsList->Name ); // check for vargs if (!strcmp(pArgsList->Name, szVARGS)) { break; } ArgSize = pArgsList->ArgSize; while (ArgSize > 0) { ArgSize -= sizeof(int); fprintf(fp, "%s%s", "%x", ArgSize > 0 ? "." : "" ); } Next= Next->Flink; if (Next != &pCGenState->ExportsDbg->ArgsListHead) { fputc(',', fp); } } while (Next != &pCGenState->ExportsDbg->ArgsListHead); // // Write out Return Type <", "RetType %x"> // pRet = pCGenState->ApiTypes->FuncRet; fprintf(fp, "\", \"%s ", pRet); ResetLexer(); LexMacroArgs(pRet); ConsumeConstVolatileOpt(); // Get Known Types for size of Return Type if (ParseTypes(TypeDefsList, NULL, &pkt) == FALSE) { CurrentTokenIndex = 0; if (ParseTypes(StructsList, NULL, &pkt) == FALSE) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetRetSize: Undefind Type %s\n\n", pCGenState->ApiTypes->FuncRet ); return; } } ArgSize = pkt->Size; ParseIndirection(NULL, &ArgSize, NULL, NULL, NULL); while (ArgSize > 0) { ArgSize -= sizeof(int); fprintf(fp, "%s%s", "%x", ArgSize > 0 ? "." : "" ); } fprintf(fp, "\""); } char * GetAddrFirstArg( PCGENSTATE pCGenState, char *Buffer, int BuffLen) { PLIST_ENTRY pFirstEntry; PARGSLIST pArgsList; if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) { return "NULL"; } pFirstEntry = pCGenState->ExportsDbg->ArgsListHead.Flink; pArgsList = CONTAINING_RECORD(pFirstEntry, ARGSLIST, ArgumentsEntry); if (!pArgsList->Name) { return "NULL"; } Buffer[0] = '&'; BuffLen--; if ((int)strlen(pArgsList->Name) > BuffLen) { ExitErrMsg(TRUE, "gafa: Overflow %s\n", pArgsList->Name); } strcpy(&Buffer[1], pArgsList->Name); return Buffer; } /* * IfArgs * */ char *IfArgs(char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult) { PARGSLIST pArgsList; PLIST_ENTRY pFirstEntry; PKNOWNTYPES pkt; *pfResult = TRUE; // skip empty list, if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) { *pfResult = FALSE; } // check for void arg list else { pFirstEntry = pCGenState->ExportsDbg->ArgsListHead.Flink; pArgsList = CONTAINING_RECORD(pFirstEntry, ARGSLIST, ArgumentsEntry); if (!pArgsList->Name) { pkt = GetNameFromTypesList(TypeDefsList, pArgsList->Type); if (!pkt) { pkt = GetNameFromTypesList(StructsList, pArgsList->Type); } if (!pkt) { ExitErrMsg(FALSE, "ifArgs: Unknown Type %s\n", pArgsList->Type ); } if (!pkt->IndLevel && !strcmp(pkt->BasicType, szVOID)) { *pfResult = FALSE; } } } return WriteMore(pSrc,pCGenState, *pfResult); } /* * DoesApiReturnVoid * */ char *DoesApiReturnVoid(char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult) { PKNOWNTYPES pkt; *pfResult = FALSE; ResetLexer(); LexMacroArgs(pCGenState->ApiTypes->FuncRet); ConsumeConstVolatileOpt(); if (ParseTypes(TypeDefsList,NULL, &pkt) == FALSE) { CurrentTokenIndex = 0; if (ParseTypes(StructsList, NULL, &pkt) == FALSE) { *pfResult = TRUE; } } if (!*pfResult && CurrentToken()->TokenType != TK_STAR && !pkt->IndLevel && !strcmp(pkt->BasicType, szVOID)) { *pfResult = TRUE; } return pSrc; } /* * IfApiRet * */ char *IfApiRet(char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult) { pSrc = DoesApiReturnVoid(pSrc, pCGenState, pfResult); *pfResult = !*pfResult; pSrc = WriteMore(pSrc, pCGenState, *pfResult); return pSrc; } char * IfApiCode( char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult ) /*++ Routine Description: Expands an EFunc's codeburst, if it exists. ie. @IfApiCode(foo) will expand to the 'foo=' section of the current EFunc, if the current EFunc has a 'foo='. Otherwise, there is no expansion. Arguments: pSrc - pointer to character following '@IfApiCode' pCGenState - current code-gen state Return Value: pointer to character following the end of the ')' --*/ { char *pch; char *pEnd; size_t Len; int CodeBurstIndex; char CodeName[MAX_PATH]; char *CodeBurst; *pfResult = FALSE; pch = SkipSubExpression(pSrc, NULL); if (pSrc == pch) { return pSrc; } pEnd = pch; pch = pSrc+1; if (IsSeparator(*pch)) { return pSrc; } pSrc = pch; while (!IsSeparator(*pch)) { pch++; } Len = pch - pSrc; // Copy name to a buffer and null-terminate memcpy(CodeName, pSrc, Len); CodeName[Len] = '\0'; CodeBurstIndex = GetExistingCodeBurstIndex(CodeName); if (CodeBurstIndex == -1) { ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", CodeName); } if (pCGenState->ExTemplate) { CodeBurst = pCGenState->TempleEx->CodeBurst[CodeBurstIndex]; if (CodeBurst) { // // There is an [Efunc] with a non-empty codeburst for this API. // Generate its codeburst. // *pfResult = TRUE; CGenerate(CodeBurst, pCGenState); } } return pEnd; } /* * CheckFastCallArgs * */ BOOLEAN FastCallArgs( PLIST_ENTRY ArgsListHead, int ArgLimit, BOOL fCheckTypes, BOOL fCheckFirstArgType ) { PARGSLIST pArgsList; PTEMPLES pTypeTemple; PKNOWNTYPES pktTemple; int NumArgs, ArgSize; PLIST_ENTRY Next, NextTemple; if (IsListEmpty(ArgsListHead)) { return FALSE; } Next = ArgsListHead->Flink; // check for void arg list, or vargs as first arg pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry); if (!pArgsList->Name) { return strcmp(pArgsList->Type, szVARGS) ? TRUE : FALSE; } NumArgs = 0; while (Next != ArgsListHead) { pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry); // // Cannot have more than 4 args // if (++NumArgs > ArgLimit) { return FALSE; } // // arg size must be dword or less // ArgSize = (pArgsList->ArgSize + 3) & ~3; if (ArgSize < 0 || ArgSize > 4) { return FALSE; } // // vargs of any indlevel aren't allowed // if (!strcmp(pArgsList->pKnownTypes->BaseName, szVARGS)) { return FALSE; } // // floats of Zero IndLevel aren't allowed // if (pArgsList->IndLevel == 0 && !strcmp(pArgsList->pKnownTypes->BaseName, szFLOAT)) { return FALSE; } // // type templates are not allowed except for the first arg in methods // if ((fCheckTypes) && ((NumArgs != 1) || ((NumArgs == 1) && fCheckFirstArgType))) { NextTemple = TypeTempleList.Flink; while (NextTemple != &TypeTempleList) { pTypeTemple = CONTAINING_RECORD(NextTemple, TEMPLES, TempleEntry); // // get the Known types info for each type template. // pktTemple = pTypeTemple->pktType; if (!pktTemple) { // // Don't have the Known types info yet, fetch it // and save it in the TypeTemplate // pktTemple = GetNameFromTypesList(TypeDefsList, pTypeTemple->Name ); if (!pktTemple) { pktTemple = GetNameFromTypesList(StructsList, pTypeTemple->Name ); } pTypeTemple->pktType = pktTemple; } if (!pktTemple) { ExitErrMsg(FALSE, "Temple: Type not found %s\n", pTypeTemple->Name ); } // // See if arg matches this type template // if (IsSameType(pArgsList->pKnownTypes, pArgsList->IndLevel, TK_NONE, pTypeTemple->Name, pTypeTemple->IndLevel + pktTemple->IndLevel, TK_NONE, TRUE )) { return FALSE; } NextTemple = NextTemple->Flink; } } Next= Next->Flink; } return TRUE; } BOOLEAN IsFastCall( PCGENSTATE pCGenState ) { if (!pCGenState->ExportsDbg) { // can this occur ? return FALSE; } // // If first time, determine if Api can be a fastcall. // tri state flag, where: // -1 == Cannot be a fastcall // 0 == undetermined // 1 == Can be a fastcall // if (!pCGenState->ExportsDbg->FastCall) { int Size; pCGenState->ExportsDbg->FastCall = -1; // assume not a fastcall // // Fast call criteria: // 1. NOT have an exception template. // 2. each param up to 4 bytes (exclude structures) // 3. 0 to 4 params // 4. return 0 or 1 dword. // 5. Not be a float or a VARGS // 6. Not have have a type template // 7. Must not be in the EFastTemplate list // 8. Must not have a C++ linkage // if (!pCGenState->ExTemplate && !pCGenState->ExportsDbg->CplusDecoration) { Size = GetRetSize(pCGenState); if (Size >= 0 && Size <= 4 && !GetTemplate(&EFastTempleList, pCGenState->ExportsDbg->ExportName) && FastCallArgs(&pCGenState->ExportsDbg->ArgsListHead, 4, TRUE, TRUE)) { pCGenState->ExportsDbg->FastCall = 1; } } } return pCGenState->ExportsDbg->FastCall == 1; } METHODTYPE GetX2NMethodType( PCGENSTATE pCGenState ) { int RetSize; // // Fast X2N method criteria: // 1. NOT have an exception template. // 2. each param up to 4 bytes (exclude structures) // 3. Number of parameters between 1 and MAXX2NPARAMETERS // 4. return 0 or 1 dword. // 5. Not be a float or a VARGS // 6. Not have have a type template, except for this pointer // 7. Must not be in the EFastTemplate list // 8. Must not have a C++ linkage // // // Slow X2N method criteria: // 1. NOT have an exception template. // 2. each param up to 4 bytes (exclude structures) // 3. Number of parameters between 1 and MAX2NPARAMETERS // 4. return 0 or 1 dword. // 5. Not be a float or a VARGS // 6. Must not be in the EFastTemplate list // 7. Must not have a C++ linkage // // Fat X2N methods are neither Slow X2N methods or Fast X2N methods if (!pCGenState->ExportsDbg) { // can this occur ? return FALSE; } if (pCGenState->ExportsDbg->X2NMethodType == UNKNOWNMETHOD) { RetSize = GetRetSize(pCGenState); if (pCGenState->ExTemplate || pCGenState->ExportsDbg->CplusDecoration || GetTemplate(&EFastTempleList, pCGenState->ExportsDbg->ExportName) || (RetSize > 4) || (RetSize < 0)) { pCGenState->ExportsDbg->X2NMethodType = FATX2NMETHOD; } else if (FastCallArgs(&pCGenState->ExportsDbg->ArgsListHead, MAXX2NPARAMETERS, TRUE, FALSE)) { pCGenState->ExportsDbg->X2NMethodType = FASTX2NMETHOD; } else if (FastCallArgs(&pCGenState->ExportsDbg->ArgsListHead, MAXX2NPARAMETERS, FALSE, FALSE)) { pCGenState->ExportsDbg->X2NMethodType = SLOWX2NMETHOD; } else { pCGenState->ExportsDbg->X2NMethodType = FATX2NMETHOD; } } return(pCGenState->ExportsDbg->X2NMethodType); } /* * IfRetType * */ char *IfRetType(char *pSrc, PCGENSTATE pCGenState, BOOL * pfResult) { char *pch; *pfResult = FALSE; pch = GetNextToken(pSrc); if (pch != pSrc) { *pfResult = ( ! strncmp(pch, pCGenState->ApiTypes->FuncRet, strlen( pCGenState->ApiTypes->FuncRet))); } pSrc = GetNextToken(pch); pch = WriteMore(pSrc ,pCGenState, *pfResult); return(pch); } /* * IfNotRetType * */ char *IfNotRetType(char *pSrc, PCGENSTATE pCGenState) { char *pch; BOOL bMore = FALSE; pch = GetNextToken(pSrc); if (pch != pSrc) { bMore = (strncmp( pch, pCGenState->ApiTypes->FuncRet, strlen( pCGenState->ApiTypes->FuncRet ) ) != 0); } pSrc = GetNextToken(pch); pch = WriteMore(pSrc ,pCGenState, bMore); return(pch); } BOOL ExpandType( PCGENSTATE pCGenState, PKNOWNTYPES pkt, PLIST_ENTRY pTempleList, int CodeBurstIndex ) { PARGSLIST pArgsList; PKNOWNTYPES pktTemple; int tplIndLevel; PLIST_ENTRY NextTemple; PTEMPLES pTypeTemple; int i; pArgsList = pCGenState->pArgsList; i=2; while (i--) { NextTemple = pTempleList->Flink; while (NextTemple != pTempleList) { pTypeTemple = CONTAINING_RECORD(NextTemple, TEMPLES, TempleEntry); tplIndLevel = pTypeTemple->IndLevel; pktTemple = pTypeTemple->pktType; if (!pktTemple) { pktTemple = GetNameFromTypesList(TypeDefsList, pTypeTemple->Name ); if (!pktTemple) { pktTemple = GetNameFromTypesList(StructsList, pTypeTemple->Name ); } pTypeTemple->pktType = pktTemple; } if (!pktTemple) { ExitErrMsg(FALSE, "Temple: Type not found %s\n", pTypeTemple->Name ); } tplIndLevel += pktTemple->IndLevel; if (IsSameType(pkt, pArgsList->IndLevel, pArgsList->tkDirection, pTypeTemple->Name, tplIndLevel, pTypeTemple->tkDirection, i == 0 )) { DbgPrintf("ttpl: MEMBER %s.%s Type=%s IndLevel=%d\n", pCGenState->ApiTypes->FuncRet, pTypeTemple->Name, pTypeTemple->Name, pTypeTemple->IndLevel ); if(ExpandTemple(pTypeTemple, CodeBurstIndex, pCGenState)){ return TRUE; } } NextTemple = NextTemple->Flink; } } return FALSE; } BOOL IsInNoType(PCHAR *NoTypes, PMEMBERINFO pmi) { SIZE_T NoTypeCount; if (NoTypes == NULL || pmi->sName == NULL) { return FALSE; } for (NoTypeCount=0; NoTypeCountsName, NoTypes[NoTypeCount]) == 0) { return TRUE; } } } return FALSE; } SIZE_T CountNoTypes(PCHAR *NoTypes) { SIZE_T Count = 0; if (NoTypes == NULL) { return 0; } while(*NoTypes++ != NULL) { Count++; } return Count; } VOID pMemberTypes( PCGENSTATE pCGenState, int CodeBurstIndex, char *MemReference, BOOL bBtoT); void ExpandMemberType( PMEMBERINFO pmi, CGENSTATE CGenState, int CodeBurstIndex, PKNOWNTYPES pktStruct, char* pszStructName, char *pszHostCastedStructName, PARGSLIST pArgsList, FILE* fpLog, PARGSLIST pArgsListOld, char *pMemReference, BOOL bBtoT) { char *sName; char *sNameNew; char *sHostCastedName; int Len, HostCastedNameLen; PKNOWNTYPES pkt; BOOL bAddCast = TRUE; char Type[MAX_PATH]; PARGSLIST pArgsListTemp; // Determine if this member should be expanded by checking for a NoType entry. if (pmi->sName != NULL) { if(IsInNoType(CGenState.CurrentTemple->NoTypes, pmi) || IsInNoType(CGenState.MemberNoType, pmi)) { goto NextMember; } } // Get the pkt for the member type if ( pmi->pktCache ) { pkt = pmi->pktCache; } else { ResetLexer(); LexMacroArgs(pmi->sType); ConsumeConstVolatileOpt(); if (ParseTypes(TypeDefsList,NULL, &pkt) == FALSE) { CurrentTokenIndex = 0; if ( ParseTypes( StructsList, NULL, &pkt ) == FALSE ) { fprintf( fpLog, "%s *** WARNING *** Member %s->%s skipped - unknown type\n", CGenState.Temple->Comment, pszStructName, pmi->sType ); goto NextMember; } } pmi->pktCache = pkt; } if ( pktStruct == pkt ) { // // Rats! The structure contains a member which is a pointer // with the same type as this structure. ie. this struct // is self-referential. We can't expand it as the expansion // is recursive. // fprintf( fpLog, "%s *** WARNING *** Member %s->%s skipped - self-referencing structure\n", CGenState.Temple->Comment, pszStructName, pmi->sType ); goto NextMember; } // Build the new names. sName = pmi->sName; // This is a type without a name. No casting is needed. if (pktStruct->Flags & BTI_ANONYMOUS) { if (sName == NULL) { sHostCastedName = CheckHeapAlloc(strlen(pszHostCastedStructName) + 1); sNameNew = CheckHeapAlloc(strlen(pszStructName) + 1); strcpy(sHostCastedName, pszHostCastedStructName); strcpy(sNameNew, pszStructName); } else { sHostCastedName = CheckHeapAlloc(strlen(pszHostCastedStructName) + strlen(pMemReference) + strlen(sName) + 1); strcpy(sHostCastedName, pszHostCastedStructName); strcat(sHostCastedName, pMemReference); strcat(sHostCastedName, sName); sNameNew = CheckHeapAlloc(strlen(pszStructName) + strlen(pMemReference) + strlen(sName) + 1); strcpy(sNameNew, pszStructName); strcat(sNameNew, pMemReference); strcat(sNameNew, sName); } } else { pArgsListTemp = CGenState.pArgsList; CGenState.pArgsList = pArgsListOld; if (IsPointer(&CGenState)) { ArgTypeInd(Type, &CGenState, TRUE); strcat(Type, " *"); } else { ArgHostType(Type, &CGenState); } if (CGenState.pArgsList->bIsBitfield || (CGenState.pArgsList->IndLevel == 0 && CGenState.pArgsList->pKnownTypes->IndLevel == 0 && (strcmp(CGenState.pArgsList->pKnownTypes->BasicType, "struct") == 0 || strcmp(CGenState.pArgsList->pKnownTypes->BasicType, "enum") == 0 || strcmp(CGenState.pArgsList->pKnownTypes->BasicType, "union") == 0) ) ) { bAddCast = FALSE; } else { bAddCast = TRUE; } CGenState.pArgsList = pArgsListTemp; HostCastedNameLen = strlen(pszHostCastedStructName) + strlen(Type) + 8; Len = strlen(pszStructName) + 1; if (sName != NULL) { HostCastedNameLen += strlen(pMemReference) + strlen(sName); Len += strlen(pMemReference) + strlen(sName); } if (Len >= MAX_PATH || HostCastedNameLen >= MAX_PATH) { fprintf( fpLog, "%s *** WARNING *** Member %s->%s skipped - name is too long\n", CGenState.Temple->Comment, pszStructName, pmi->sType ); goto NextMember; } sHostCastedName = CheckHeapAlloc(HostCastedNameLen); sHostCastedName[0] = '\0'; if (bAddCast) { strcpy(sHostCastedName, "(("); strcat(sHostCastedName, Type); strcat(sHostCastedName, ")("); strcat(sHostCastedName, pszHostCastedStructName); strcat(sHostCastedName, "))"); } else { strcat(sHostCastedName, pszHostCastedStructName); } if(sName != NULL) { strcat(sHostCastedName, pMemReference); strcat(sHostCastedName, sName); } sNameNew = CheckHeapAlloc(Len); strcpy(sNameNew, pszStructName); if(sName != NULL) { strcat(sNameNew, pMemReference); strcat(sNameNew, sName); } } pArgsList->pKnownTypes = pkt; pArgsList->ArgSize = pkt->Size; pArgsList->IsPtr64 = pmi->bIsPtr64; pArgsList->OffSet = -1; // there is no stack offset for this member pArgsList->IndLevel = pmi->IndLevel; // pArgsList->tkDirection is same as the original arg pArgsList->Type = pmi->sType; pArgsList->pStructType = NULL; pArgsList->Mod = TK_NONE; pArgsList->SUEOpt = TK_NONE; pArgsList->PostMod = TK_NONE; pArgsList->PrePostMod = TK_NONE; pArgsList->Name = sNameNew; pArgsList->ArgLocal = sNameNew; pArgsList->HostCastedName = sHostCastedName; pArgsList->fIsMember = TRUE; pArgsList->bIsBitfield = pmi->bIsBitfield; pArgsList->BitsRequired= pmi->BitsRequired; pArgsList->bIsArray = pmi->bIsArray; pArgsList->ArrayElements=pmi->ArrayElements; pArgsList->fRequiresThunk = ((pkt->Flags & BTI_CONTAINSFUNCPTR) != 0); if (sName != NULL) { CGenState.MemberNoType = NULL; ExpandType(&CGenState, pArgsList->pKnownTypes, &TypeTempleList, CodeBurstIndex); } else { // This field is a nameless field in a structure or union. // Example: // struct foobar { // int x; // }; // struct foobar2 { // struct foobar; // int y; // }; // foobar2 will import all the fields of foobar. // // When walking down the structure, we want to continue expanding foobar when we reach the nameless field. SIZE_T NumNoTypes1, NumNoTypes2; PCHAR *NewNoTypes; NumNoTypes1 = CountNoTypes(CGenState.MemberNoType); NumNoTypes2 = CountNoTypes(CGenState.CurrentTemple->NoTypes); if (NumNoTypes1 + NumNoTypes2 + 1 > MAX_NOTYPE) { ExitErrMsg(FALSE, "ExpandMemberType: too many notypes.\n"); } NewNoTypes = CheckHeapAlloc((NumNoTypes1 + NumNoTypes2 + 1)*sizeof(PCHAR)); memcpy(NewNoTypes, CGenState.MemberNoType, NumNoTypes1 * sizeof(PCHAR)); memcpy(NewNoTypes + NumNoTypes1, CGenState.CurrentTemple->NoTypes, NumNoTypes2 * sizeof(PCHAR)); NewNoTypes[NumNoTypes1 + NumNoTypes2] = NULL; CGenState.MemberNoType = NewNoTypes; pMemberTypes( &CGenState, CodeBurstIndex, pMemReference, bBtoT); GenHeapFree(NewNoTypes); } GenHeapFree(sNameNew); GenHeapFree(sHostCastedName); NextMember:; } void ExpandMemberTypesBackwards( PMEMBERINFO pmi, CGENSTATE CGenState, int CodeBurstIndex, PKNOWNTYPES pktStruct, char* pszStructName, char *pszHostCastedStructName, PARGSLIST pArgsList, FILE* fpLog, PARGSLIST pArgsListOld, char *pMemReference, BOOL bBtoT) { if ( pmi->pmeminfoNext != NULL ) { ExpandMemberTypesBackwards( pmi->pmeminfoNext, CGenState, CodeBurstIndex, pktStruct, pszStructName, pszHostCastedStructName, pArgsList, fpLog, pArgsListOld, pMemReference, bBtoT); } ExpandMemberType( pmi, CGenState, CodeBurstIndex, pktStruct, pszStructName, pszHostCastedStructName, pArgsList, fpLog, pArgsListOld, pMemReference, bBtoT); } VOID pMemberTypes( PCGENSTATE pCGenState, int CodeBurstIndex, char *MemReference, BOOL bBtoT) { PCGENERATE pCGen; CGENSTATE CGenState; PKNOWNTYPES pkt; ARGSLIST ArgsListOld; PMEMBERINFO pmi; pCGen = CheckHeapAlloc(sizeof(CGENERATE)+strlen(pCGenState->CGen->TempleName)+1); InitializeListHead(&pCGen->CGenerateEntry); pCGen->fp = pCGenState->CGen->fp; pCGen->FileNameC = pCGenState->CGen->FileNameC; pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC; pCGen->fpCpp = pCGenState->CGen->fpCpp; pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp; pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp; strcpy(pCGen->TempleName, pCGenState->CGen->TempleName); CGenState = *pCGenState; CGenState.CGen = pCGen; pkt = pCGenState->pArgsList->pKnownTypes; while(pkt->pTypedefBase != NULL) { pkt = pkt->pTypedefBase; } pCGenState->pArgsList->pStructType = pkt; // Save the old ARGSLIST away ArgsListOld = *(pCGenState->pArgsList); // get a ptr to the member list for the struct pmi = pkt->pmeminfo; if ( !pmi ) { ExitErrMsg(FALSE, "Type '%s' is not a struct", pCGenState->pArgsList->Type); } if(strcmp(pkt->BasicType, "union") == 0) { PMEMBERINFO pmiTemp; // check if any of the members of this union are in the notype list. for (pmiTemp = pkt->pmeminfo; pmiTemp != NULL; pmiTemp = pmiTemp->pmeminfoNext) { if (IsInNoType(pCGenState->MemberNoType, pmiTemp) || IsInNoType(pCGenState->CurrentTemple->NoTypes, pmiTemp)) { //A member of the union is in the notype list, skip union. goto done; } } } // loop over each member variable within the type if ( bBtoT ) { do { ExpandMemberType( pmi, CGenState, CodeBurstIndex, ArgsListOld.pKnownTypes, ArgsListOld.Name, ArgsListOld.HostCastedName, pCGenState->pArgsList, pCGenState->CGen->fp, &ArgsListOld, MemReference, bBtoT); pmi = pmi->pmeminfoNext; } while ( pmi != NULL ); } else { ExpandMemberTypesBackwards( pmi, CGenState, CodeBurstIndex, ArgsListOld.pKnownTypes, ArgsListOld.Name, ArgsListOld.HostCastedName, pCGenState->pArgsList, pCGenState->CGen->fp, &ArgsListOld, MemReference, bBtoT); } done: // Restore the old ARGSLIST *pCGenState->pArgsList = ArgsListOld; GenHeapFree(pCGen); } char* MemberTypes( char *pSrc, PCGENSTATE pCGenState, BOOL bBtoT) /*++ Routine Description: Expands [Type] templates for the return value of an API call. Arguments: pSrc - pointer to character following '@RetType' pCGenState - current code-gen state Return Value: pointer to character following the end of the ')' --*/ { char *pEnd; char *pch; char BurstName[MAX_PATH]; int CodeBurstIndex; PMACROARGSLIST pMArgsList = NULL; SIZE_T BytesReturned; char MemReference[MAX_PATH]; pch = SkipSubExpression(pSrc, NULL); if (pSrc == pch) { return pSrc; } pEnd = pch; ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList); if (pMArgsList->NumArgs < 1 || pMArgsList->NumArgs > 2) { ExitErrMsg(FALSE, "MemberTypes: 1 or 2 arguments are required.\n"); } CGenerateEx(pMArgsList->ArgText[0], pCGenState, BurstName, MAX_PATH, &BytesReturned); CodeBurstIndex = GetExistingCodeBurstIndex(BurstName); if (CodeBurstIndex == -1) { ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", BurstName); } //handle optional member reference symbol if (pMArgsList->NumArgs == 2) { CGenerateEx(pMArgsList->ArgText[1], pCGenState, MemReference, MAX_PATH, &BytesReturned); } else { strcpy(MemReference, "->"); } pMemberTypes(pCGenState, CodeBurstIndex, MemReference, bBtoT); FreeMacroArgsList(pMArgsList); return pEnd; } char* ForceTypeExpand( char *pSrc, PCGENSTATE pCGenState) { char *pEnd; char *pch; PCGENERATE pCGen; CGENSTATE CGenState; char BurstName[MAX_PATH]; char ArgName[MAX_PATH]; char ArgHostName[MAX_PATH]; char TypeName[MAX_PATH]; char Direction[MAX_PATH]; int CodeBurstIndex; PARGSLIST pArgsList; ARGSLIST ArgsListOld; ARGSLIST ArgsListNew; TOKENTYPE tkDirection; PMACROARGSLIST pMArgsList = NULL; SIZE_T BytesReturned; BOOL bHasArgsList=FALSE; pch = SkipSubExpression(pSrc, NULL); if (pSrc == pch) { return pSrc; } pEnd = pch; ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList); if (pMArgsList->NumArgs != 5) { ExitErrMsg(FALSE, "ForceTypeExpand: 5 arguments are required.\n"); } CGenerateEx(pMArgsList->ArgText[0], pCGenState, BurstName, MAX_PATH, &BytesReturned); CodeBurstIndex = GetExistingCodeBurstIndex(BurstName); if (CodeBurstIndex == -1) { ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", BurstName); } pCGen = GenHeapAlloc(sizeof(CGENERATE)+strlen(pCGenState->CGen->TempleName)+1); if (!pCGen) { ExitErrMsg(TRUE, "mt: %s\n", pSrc); } CGenerateEx(pMArgsList->ArgText[1], pCGenState, ArgName, MAX_PATH, &BytesReturned); CGenerateEx(pMArgsList->ArgText[2], pCGenState, ArgHostName, MAX_PATH, &BytesReturned); CGenerateEx(pMArgsList->ArgText[3], pCGenState, TypeName, MAX_PATH, &BytesReturned); CGenerateEx(pMArgsList->ArgText[4], pCGenState, Direction, MAX_PATH, &BytesReturned); // Parse the direction if(strcmp(Direction, "IN OUT") == 0) { tkDirection = TK_INOUT; } else if (strcmp(Direction, "IN") == 0) { tkDirection = TK_IN; } else if (strcmp(Direction, "OUT") == 0) { tkDirection = TK_OUT; } else if (strcmp(Direction, "none") == 0) { tkDirection = TK_NONE; } else { ExitErrMsg(FALSE, "FORCETYPE: Unknown direction %s\n", Direction); return NULL; } InitializeListHead(&pCGen->CGenerateEntry); pCGen->fp = pCGenState->CGen->fp; pCGen->FileNameC = pCGenState->CGen->FileNameC; pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC; pCGen->fpCpp = pCGenState->CGen->fpCpp; pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp; pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp; strcpy(pCGen->TempleName, pCGenState->CGen->TempleName); CGenState = *pCGenState; CGenState.CGen = pCGen; // Save the old ARGSLIST away pArgsList = pCGenState->pArgsList; if (pArgsList == NULL) { CGenState.pArgsList = &ArgsListNew; pArgsList = &ArgsListOld; *pArgsList = *(PARGSLIST)pCGenState->ExportsDbg->ArgsListHead.Flink; } else { ArgsListOld = *pArgsList; bHasArgsList = TRUE; } pArgsList->pKnownTypes = NULL; pArgsList->ArgSize = 0; pArgsList->IsPtr64 = FALSE; pArgsList->OffSet = -1; // there is no stack offset for this member pArgsList->IndLevel = 0; pArgsList->tkDirection = tkDirection; pArgsList->Type = TypeName; pArgsList->pStructType = NULL; pArgsList->Mod = TK_NONE; pArgsList->SUEOpt = TK_NONE; pArgsList->PostMod = TK_NONE; pArgsList->PrePostMod = TK_NONE; pArgsList->Name = ArgName; pArgsList->ArgLocal = ArgName; pArgsList->HostCastedName = ArgHostName; pArgsList->fIsMember = TRUE; pArgsList->bIsBitfield = FALSE; pArgsList->BitsRequired= FALSE; pArgsList->bIsArray = FALSE; pArgsList->ArrayElements=0; pArgsList->fRequiresThunk = FALSE; SetArgListToTypeForArg(CGenState.pArgsList, pArgsList, TypeName); ExpandType(&CGenState, CGenState.pArgsList->pKnownTypes, &TypeTempleList, CodeBurstIndex); // Restore the old ARGSLIST if (bHasArgsList) { *pCGenState->pArgsList = ArgsListOld; } else { pCGenState->pArgsList = NULL; } GenHeapFree(pCGen); FreeMacroArgsList(pMArgsList); return pEnd; } char * IncludeRetType( char *pSrc, PCGENSTATE pCGenState ) /*++ Routine Description: Expands [Type] templates for the return value of an API call. Arguments: pSrc - pointer to character following '@RetType' pCGenState - current code-gen state Return Value: pointer to character following the end of the ')' --*/ { char *pEnd; char *pch; PCGENERATE pCGen; CGENSTATE CGenState; PKNOWNTYPES pkt; int i; int tplIndLevel; PTEMPLES pTypeTemple; PKNOWNTYPES pktTemple; PLIST_ENTRY NextTemple; char BurstName[MAX_PATH]; int CodeBurstIndex; char *CodeBurst; PMACROARGSLIST pMArgsList = NULL; SIZE_T BytesReturned; pch = SkipSubExpression(pSrc, NULL); if (pSrc == pch) { return pSrc; } pEnd = pch; ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList); if (pMArgsList->NumArgs != 1) { ExitErrMsg(FALSE, "IncludeRetTypes: exactly 1 argument is required.\n"); } CGenerateEx(pMArgsList->ArgText[0], pCGenState, BurstName, MAX_PATH, &BytesReturned); CodeBurstIndex = GetExistingCodeBurstIndex(BurstName); if (CodeBurstIndex == -1) { ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", BurstName); } pCGen = GenHeapAlloc(sizeof(CGENERATE)+strlen(pCGenState->CGen->TempleName)+1); if (!pCGen) { ExitErrMsg(TRUE, "it: %s\n", pSrc); } InitializeListHead(&pCGen->CGenerateEntry); pCGen->fp = pCGenState->CGen->fp; pCGen->FileNameC = pCGenState->CGen->FileNameC; pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC; pCGen->fpCpp = pCGenState->CGen->fpCpp; pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp; pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp; strcpy(pCGen->TempleName, pCGenState->CGen->TempleName); CGenState = *pCGenState; CGenState.CGen = pCGen; if (pCGenState->ExTemplate) { CodeBurst = pCGenState->TempleEx->CodeBurst[CodeBurstIndex]; if (CodeBurst) { // // The [EFunc] template for this API has a return-type codeburst. // That is expanded in lieu of a [Types] template. // CGenerate(CodeBurst, &CGenState); return pEnd; } } pkt = pCGenState->ApiTypes->pktRet; pkt = pCGenState->ApiTypes->pktRet; i=2; while (i--) { for (NextTemple = TypeTempleList.Flink ; NextTemple != &TypeTempleList ; NextTemple = NextTemple->Flink) { pTypeTemple = CONTAINING_RECORD(NextTemple, TEMPLES, TempleEntry); tplIndLevel = pTypeTemple->IndLevel; pktTemple = pTypeTemple->pktType; if (!pktTemple) { pktTemple = GetNameFromTypesList(TypeDefsList, pTypeTemple->Name ); if (!pktTemple) { pktTemple = GetNameFromTypesList(StructsList, pTypeTemple->Name ); } pTypeTemple->pktType = pktTemple; } if (!pktTemple) { if (bIgnorePrototypeError) { /* fprintf(pCGenState->CGen->fp, "%s Error:3 Ignoring type %s\n", pCGenState->Temple->Comment, pTypeTemple->Name ); */ continue; } else { ExitErrMsg(FALSE, "Temple: Type not found %s\n", pTypeTemple->Name ); } } tplIndLevel += pktTemple->IndLevel; if (IsSameType(pkt, pCGenState->ApiTypes->RetIndLevel, TK_NONE, pTypeTemple->Name, tplIndLevel, TK_NONE, i == 0 )) { DbgPrintf("ttpl: RETURN %s.%s Type=%s IndLevel=%d\n", CGenState.ApiTypes->FuncRet, pTypeTemple->Name, pTypeTemple->Name, pTypeTemple->IndLevel ); if (pTypeTemple->CodeBurst[CodeBurstIndex]) { pSrc = pTypeTemple->CodeBurst[CodeBurstIndex]; while (*pSrc && !isgraph(*pSrc)) { pSrc++; } if (*pSrc) { CGenerate(pSrc, &CGenState); } } i = 0; break; // break from while loop over all templates } } } GenHeapFree(pCGen); FreeMacroArgsList(pMArgsList); return pEnd; } VOID SetArgListToTypeForArg( PARGSLIST pArgsList, PARGSLIST pArgsListOld, char * pTypeName ) { int IndLevel = 0; char TypeNameCopy[MAX_PATH]; PKNOWNTYPES pkt; char *p; BOOL bIsTypedef = TRUE; *pArgsList = *pArgsListOld; p = pTypeName; strcpy(TypeNameCopy, p); p = TypeNameCopy; while(*p != '\0') { if (*p == '*') { IndLevel++; *p = ' '; } p++; } ResetLexer(); LexMacroArgs(TypeNameCopy); ConsumeConstVolatileOpt(); if (ParseTypes(TypeDefsList, NULL, &pkt) == FALSE) { CurrentTokenIndex = 0; bIsTypedef = FALSE; if (ParseTypes(StructsList, NULL, &pkt) == FALSE ) { ExitErrMsg(FALSE, "SetArgListToType: %s is not a valid type\n", TypeNameCopy); } } pArgsList->pKnownTypes = pkt; pArgsList->pStructType = NULL; //DWORD ArgSize; // size of this arg (should be unchanged) pArgsList->IsPtr64 = (IndLevel == 0 && (pkt->Flags & BTI_PTR64)); //BOOL IsPtr64; // TRUE if this arg is __ptr64 (should be unchanged) //int OffSet; // offset from stack for this arg(should be unchanged) pArgsList->IndLevel = IndLevel; //TOKENTYPE tkDirection; // TK_NONE, TK_IN, TK_OUT, TK_INOUT(should be unchanged) //TOKENTYPE Mod; // modifier (TK_CONST/VOLATILE/NONE)(should be unchanged) if (!bIsTypedef) { if (strcmp(pkt->BasicType, szSTRUCT) == 0) { pArgsList->SUEOpt = TK_STRUCT; } else if (strcmp(pkt->BasicType, szUNION) == 0) { pArgsList->SUEOpt = TK_UNION; } else if (strcmp(pkt->BasicType, szENUM) == 0) { pArgsList->SUEOpt = TK_ENUM; } else { pArgsList->SUEOpt = TK_NONE; } } pArgsList->Type = pkt->TypeName; //TOKENTYPE PostMod; // modifier (TK_CONST/VOLATILE/NONE) //TOKENTYPE PrePostMod; // modifier (TK_CONST/VOLATILE/NONE) //char *Name; // argument name (may be a nonameX) //char *ArgLocal; // name of local var containing copy of arg //char *HostCastedName; // Contains full name of struct member with // host casts or NULL pArgsList->fRequiresThunk = pkt->Flags & BTI_CONTAINSFUNCPTR; pArgsList->fNoType = FALSE; // TRUE if types templates should *not* // be expanded for this param. //BOOL fIsMember; // This arg is actually a member of an array //BOOL bIsBitfield; // Determines if this is a bitfield //int BitsRequired; // Number of bits required for bitfield //BOOL bIsArray; // This member is an array //int ArrayElements; // Number of elements in the array } BOOL ExpandTypesForApi( PLIST_ENTRY ArgsListHead, PCGENSTATE CGenState, PLIST_ENTRY pTypesList, int CodeBurstIndex, BOOL bExpandAll, BOOL bRtoL ) { PKNOWNTYPES pktArgs; PLIST_ENTRY NextArg; BOOL fKeepGoing = TRUE; // // For each argument process a type template if any. // if ( bRtoL ) { NextArg = &CGenState->ExportsDbg->ArgsListHead; NextArg = NextArg->Blink; } else { NextArg = ArgsListHead; } do { CGenState->pArgsList = CONTAINING_RECORD(NextArg,ARGSLIST,ArgumentsEntry); if (CGenState->pArgsList->fNoType) { // // This arg is listed in this API's [EFunc] NoTypes list. // Do not expand [Types] templates for it. // goto NextArg; } ResetLexer(); LexMacroArgs(CGenState->pArgsList->Type); ConsumeConstVolatileOpt(); // Get KnownTypes info for Argument if (ParseTypes(TypeDefsList, NULL, &pktArgs) == FALSE) { CurrentTokenIndex = 0; if (ParseTypes(StructsList, NULL, &pktArgs) == FALSE ) { ErrMsg( "Args: Type not found %s %s\n", CGenState->pArgsList->Type, CGenState->ApiTypes->TypeName ); return fKeepGoing; } } fKeepGoing = !ExpandType(CGenState, CGenState->pArgsList->pKnownTypes, pTypesList, CodeBurstIndex); fKeepGoing = fKeepGoing | bExpandAll; NextArg: if ( bRtoL ) { if ( NextArg == ArgsListHead ) { break; } NextArg = NextArg->Blink; } else { NextArg = NextArg->Flink; if ( NextArg == &CGenState->ExportsDbg->ArgsListHead ) { break; } } } while (fKeepGoing); return fKeepGoing; } /* * IncludeTypes * */ char *IncludeTypes(char *pSrc, PCGENSTATE pCGenState, BOOL bRtoL) { char *pEnd; char *pch; PCGENERATE pCGen; CGENSTATE CGenState; PARGSLIST pArgsList; PLIST_ENTRY NextArg; char BurstName[MAX_PATH]; PMACROARGSLIST pMArgsList = NULL; SIZE_T BytesReturned; int CodeBurstIndex; pch = SkipSubExpression(pSrc, NULL); if (pSrc == pch) { return pSrc; } pEnd = pch; // // Functions must have an argument list (at least void) // if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n IncludeTypes Missing argument List: %s\n", pCGenState->ApiTypes->TypeName ); return pEnd; } // // If void arg list, nothing to do! // NextArg = pCGenState->ExportsDbg->ArgsListHead.Flink; pArgsList = CONTAINING_RECORD(NextArg, ARGSLIST, ArgumentsEntry); if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) { return pEnd; } ParseMacroArgs(pSrc, pEnd - pSrc, &pMArgsList); if (pMArgsList->NumArgs < 1) { ExitErrMsg(FALSE, "IncludeTypes: CodeBurst name required\n"); } CGenerateEx(pMArgsList->ArgText[0], pCGenState, BurstName, MAX_PATH, &BytesReturned); CodeBurstIndex = GetExistingCodeBurstIndex(BurstName); if (CodeBurstIndex == -1) { ExitErrMsg(FALSE, "CodeBurst '%s' unknown.\n", BurstName); } pCGen = GenHeapAlloc(sizeof(CGENERATE)+strlen(pCGenState->CGen->TempleName)+1); if (!pCGen) { ExitErrMsg(TRUE, "it: %s\n", pSrc); } InitializeListHead(&pCGen->CGenerateEntry); pCGen->fp = pCGenState->CGen->fp; pCGen->FileNameC = pCGenState->CGen->FileNameC; pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC; pCGen->fpCpp = pCGenState->CGen->fpCpp; pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp; pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp; strcpy(pCGen->TempleName, pCGenState->CGen->TempleName); CGenState = *pCGenState; CGenState.CGen = pCGen; if (pMArgsList->NumArgs >= 2) { char ArgName[MAX_PATH]; char TypeName[MAX_PATH]; char CastedArgName[MAX_PATH]; size_t ArgNameLen; size_t ArgTypeLen; char *p; BOOL bHasType = FALSE; //extract arg name to expand types for CGenerateEx(pMArgsList->ArgText[1], pCGenState, ArgName, MAX_PATH, &BytesReturned); if (BytesReturned == 0) { ExitErrMsg(FALSE, "IncludeTypes: Empty arg name is not allowed.\n"); } ArgNameLen = BytesReturned - 1; if (pMArgsList->NumArgs == 3) { //extract the type name CGenerateEx(pMArgsList->ArgText[2], pCGenState, TypeName, MAX_PATH, &BytesReturned); if (BytesReturned == 0) { ExitErrMsg(FALSE, "IncludeTypes: Empty type name is not allowed.\n"); } ArgTypeLen = BytesReturned - 1; bHasType = TRUE; if (ArgTypeLen + ArgNameLen + 4 >= MAX_PATH) { ExitErrMsg(FALSE, "ArgType + ArgName is too long\n"); } memcpy(CastedArgName, "((", 2); p = CastedArgName + 2; memcpy(p, TypeName, ArgTypeLen); p += ArgTypeLen; memcpy(p, ")", 1); p++; memcpy(p, ArgName, ArgNameLen); p += ArgNameLen; memcpy(p, ")", 2); } else { ExitErrMsg(FALSE, "IncludeTypes: Too many arguments\n"); } //Find arg in the arglist. do { pArgsList = CONTAINING_RECORD(NextArg, ARGSLIST, ArgumentsEntry); if (pArgsList->Name != NULL) { if (strcmp(pArgsList->Name, ArgName) == 0) { //Expand this argument if (bHasType) { CGenState.pArgsList = GenHeapAlloc(sizeof(ARGSLIST)); if(NULL == CGenState.pArgsList) ExitErrMsg(FALSE, "IncludeTypes: out of memory.\n"); SetArgListToTypeForArg(CGenState.pArgsList, pArgsList, TypeName); CGenState.pArgsList->Name = CastedArgName; } else { CGenState.pArgsList = pArgsList; } if (!ExpandType(&CGenState, CGenState.pArgsList->pKnownTypes, &FailTempleList, CodeBurstIndex)) ExpandType(&CGenState, CGenState.pArgsList->pKnownTypes, &TypeTempleList, CodeBurstIndex); if (bHasType) { GenHeapFree(CGenState.pArgsList); } GenHeapFree(pCGen); FreeMacroArgsList(pMArgsList); return pEnd; } } NextArg = NextArg->Flink; } while (NextArg != &CGenState.ExportsDbg->ArgsListHead); ExitErrMsg(FALSE, "IncludeTypes: %s is not a known argument for %s\n", ArgName, pCGenState->ExportsDbg->ExportName); } else { if (ExpandTypesForApi(NextArg, &CGenState, &FailTempleList, CodeBurstIndex, FALSE, bRtoL)) { ExpandTypesForApi(NextArg, &CGenState, &TypeTempleList, CodeBurstIndex, TRUE, bRtoL); } } GenHeapFree(pCGen); FreeMacroArgsList(pMArgsList); return pEnd; } /* * IsSameType * */ PKNOWNTYPES IsSameType( PKNOWNTYPES pktArgs, int IndLevel, TOKENTYPE tkArgDirection, char *tplTypeName, int tplIndLevel, TOKENTYPE tkTypeDirection, BOOL bScanBaseTypes ) { if (*tplTypeName != '*' && strcmp(tplTypeName, "default") != 0 && IndLevel + pktArgs->IndLevel != tplIndLevel) { // // Not a generic '*' or 'default' types template, and levels of indirection // don't match // return NULL; } if (!bUseDirection) { tkArgDirection = TK_NONE; } if (tkTypeDirection != TK_EOS && tkArgDirection != tkTypeDirection) { // // Direction-sensitivity enabled, type template isn't generic to // all directions, and IN, OUT, IN/OUT don't match // return NULL; } if (!strcmp(pktArgs->TypeName, tplTypeName)) { // // type names match // return pktArgs; } if (bScanBaseTypes) { PKNOWNTYPES pkt; if (strcmp(tplTypeName, "struct") == 0 && strcmp(pktArgs->BasicType, "struct") == 0) { // // This matches a generic 'struct' template. // return pktArgs; } if (strcmp(tplTypeName, "union") == 0 && strcmp(pktArgs->BasicType, "union") == 0) { // // This matches a generic 'union' template. // return pktArgs; } if (*tplTypeName == '*' && IndLevel+pktArgs->IndLevel) { // // The template is a generic pointer template, and the arg type // is a pointer to something. Match. // return pktArgs; } if (!strcmp(pktArgs->BaseName, pktArgs->TypeName)) { // // Base name of the arg type matches this arg type, no // possiblity of a match. // pkt = NULL; goto try_default; } // // Get the knowntype for basetype of the arg // if (pktArgs->pktBase) { // the knowntype is already cached pkt = pktArgs->pktBase; } else { pkt = GetNameFromTypesList(TypeDefsList, pktArgs->BaseName); if (!pkt) { pkt = GetNameFromTypesList(StructsList, pktArgs->BaseName); } if (!pkt) { goto try_default; } pktArgs->pktBase = pkt; } IndLevel += pktArgs->IndLevel - pkt->IndLevel; pkt = IsSameType(pkt, IndLevel, tkArgDirection, tplTypeName, tplIndLevel, tkTypeDirection, TRUE ); if (NULL == pkt) { try_default: // The default type template matches everything if (strcmp(tplTypeName, "default") == 0) { //printf("Applying default template to %s\n", pktArgs->TypeName); return pktArgs; } } return pkt; } return NULL; } /* * GetAltExportName * * Fetches the forward name if one exists, returns NULL if none. * */ char *GetAltExportName(char *Buffer, PCGENSTATE pCGenState, int Len) { PEXPORTSDEBUG pExportDebug; int i; pExportDebug = pCGenState->ExportsDbg; if (pExportDebug->ExtForward) { i = _snprintf(Buffer, Len, "=%s", pExportDebug->ExtForward); } else if (pExportDebug->IntForward) { if (bNoFuzzyLogic && !strchr(pExportDebug->IntForward->ExportName, '@')) { i = _snprintf(Buffer, Len, "=%s%s@%d", szINTFORWARD, pExportDebug->IntForward->ExportName, GetArgSize(pExportDebug) ); } else { i = _snprintf(Buffer, Len, "=%s%s", szINTFORWARD, pExportDebug->IntForward->ExportName ); } } else if (bNoFuzzyLogic && !strchr(pExportDebug->ExportName, '@') && !strstr(pCGenState->ApiTypes->FuncMod, "cdecl")) { i = _snprintf(Buffer, Len, "=%s@%d", pExportDebug->ExportName, GetArgSize(pExportDebug) ); } else { return NULL; } if (i < 0) { ExitErrMsg(FALSE, "GetAltExportName: Overflow %s\n", pExportDebug->ExportName ); } return Buffer; } /* * IncludeTemplate * */ char *IncludeTemplate(char *pSrc, PCGENSTATE pCGenState) { char *pEnd; char *pch; size_t Len; PCGENERATE pCGen; CGENSTATE CGenState; pch = SkipSubExpression(pSrc, NULL); if (pSrc == pch) { return pSrc; } pEnd = pch; pch = pSrc + 1; if (IsSeparator(*pch)) { return pSrc; } pSrc = pch; while (!IsSeparator(*pch)) { pch++; } Len = pch - pSrc; pCGen = GenHeapAlloc(Len + 1 + sizeof(CGENERATE)); if (!pCGen) { ExitErrMsg(TRUE, "it: %s\n", pSrc); } InitializeListHead(&pCGen->CGenerateEntry); pCGen->fp = pCGenState->CGen->fp; pCGen->fpC = pCGenState->CGen->fpC; pCGen->FileNameC = pCGenState->CGen->FileNameC; pCGen->FileBaseNameC = pCGenState->CGen->FileBaseNameC; pCGen->fpCpp = pCGenState->CGen->fpCpp; pCGen->FileNameCpp = pCGenState->CGen->FileNameCpp; pCGen->FileBaseNameCpp = pCGenState->CGen->FileBaseNameCpp; memcpy(pCGen->TempleName, pSrc, Len); *(pCGen->TempleName + Len) = '\0'; memset(&CGenState, 0, sizeof(CGENSTATE)); CGenState.CGen = pCGen; CGenState.ExportsDbg = pCGenState->ExportsDbg; CGenState.DebugStrings = pCGenState->DebugStrings; CGenState.ApiTypes = pCGenState->ApiTypes; CGenState.ApiNum = pCGenState->ApiNum; CGenState.pArgsList = pCGenState->pArgsList; CGenState.ListCol = pCGenState->ListCol; CGenState.MoreApis = pCGenState->MoreApis; CGenState.CodeBurstIndex = pCGenState->CodeBurstIndex; ProcessTemple(&CGenState); GenHeapFree(pCGen); return pEnd; } /* * WriteMore */ char *WriteMore(char *pSrc, PCGENSTATE pCGenState, BOOL bMore) { char *pch; char *pExpression = 0; CGENSTATE CGenState; pch = SkipSubExpression(pSrc, bMore ? &pExpression : NULL); if (pSrc == pch) { return pSrc; } pSrc = pch; if (!bMore || !pExpression) { return pSrc; } CGenState = *pCGenState; CGenerate(pExpression, &CGenState); GenHeapFree(pExpression); return pSrc; } /* * WriteArgLocal */ BOOL WriteArgLocal( PCGENSTATE pCGenState, char *Buffer, int BuffLen) { char *pch; int i, Len; if (pCGenState->pArgsList->ArgLocal) { ErrMsg("Type Template error multiple ArgLocals\n"); return FALSE; } // format the local var name Len = _snprintf(Buffer, BuffLen, "%s", pCGenState->pArgsList->Name); if (Len <= 0) { ErrMsg( "WriteArgLocal buffer overflow %s\n", pCGenState->pArgsList->Name ); return FALSE; } // alloc space for the local var name, and stash it away pCGenState->pArgsList->ArgLocal = GenHeapAlloc(Len + 1); if (!pCGenState->pArgsList->ArgLocal) { ErrMsg("GenHeapAlloc(ArgLocal) %s\n", pCGenState->pArgsList->Name); return FALSE; } strcpy(pCGenState->pArgsList->ArgLocal, Buffer); // // format the declarator statement: "ArgType IndLevel *ArgName" // pch = Buffer; i = strlen(pCGenState->pArgsList->Type) + strlen(TokenString[pCGenState->pArgsList->SUEOpt]) + 1; if (i >= BuffLen) { ErrMsg( "WriteArgLocal buffer overflow %s\n", pCGenState->pArgsList->Name ); return FALSE; } if (pCGenState->pArgsList->SUEOpt != TK_NONE) { strcpy(pch, TokenString[pCGenState->pArgsList->SUEOpt]); strcat(pch, " "); strcat(pch, pCGenState->pArgsList->Type); } else { strcpy(pch, pCGenState->pArgsList->Type); } if (pCGenState->pArgsList->PrePostMod != TK_NONE) { strcat(pch, " "); strcat(pch, TokenString[pCGenState->pArgsList->PrePostMod]); } i = strlen(pch); Len = BuffLen - i - 1; pch += i; i = pCGenState->pArgsList->IndLevel; if (!Len || i > Len) { ErrMsg( "WriteArgLocal buffer overflow %s\n", pCGenState->pArgsList->Name ); return FALSE; } if (i) { *pch++ = ' '; while (i) { *pch++ = '*'; i--; } } *pch++ = ' '; i = strlen(pCGenState->pArgsList->ArgLocal); if (!Len || i > Len) { ErrMsg( "WriteArgLocal buffer overflow %s\n", pCGenState->pArgsList->Name ); return FALSE; } strcpy(pch, pCGenState->pArgsList->ArgLocal); // // Record that some kind of exception template has been used // during generation of this argument. // pCGenState->pArgsList->fRequiresThunk = FALSE; return TRUE; } /* * WriteArgAddr */ char * WriteArgAddr( char *pSrc, PCGENSTATE pCGenState, char *Buffer, int BuffLen) { char *pEnd; char *pch; size_t Len; pch = SkipSubExpression(pSrc, NULL); if (pSrc == pch) { return pSrc; } pEnd = pch; Len = --pch - ++pSrc; if (Len + 32 >= (size_t)BuffLen) { ExitErrMsg(FALSE, "WriteArgAddr buffer overflow %s\n", pSrc ); } while (pSrc < pch) { *Buffer++ = *pSrc++; } *Buffer++ = ' '; *Buffer++ = '+'; *Buffer++ = ' '; _itoa(pCGenState->pArgsList->OffSet, Buffer, 10); return pEnd; } BOOLEAN TempleHasNoCodeBursts( PTEMPLES pTemple ) /*++ Routine Description: Determines if a template has no codebursts at all or not. Arguments: pTemple - template to examine Return Value: TRUE if template has no codebursts, FALSE if there is at least one. --*/ { int i; for (i=0; iCodeBurst[i]) { return FALSE; } } return TRUE; } /* * ListApis */ char *ListApis(char *pSrc, PCGENSTATE pCGenState, BOOL bExports) { char *pch; char *pExpression; PLIST_ENTRY Next; CGENSTATE CGenState; PTEMPLES pTemple; BYTE ApiPlatform; BOOL ExcludedApi; pch = SkipSubExpression(pSrc, &pExpression); if (pSrc == pch || !pExpression) { return pch; } pSrc = pch; memset(&CGenState, 0, sizeof(CGenState)); CGenState.CGen = pCGenState->CGen; CGenState.Temple = pCGenState->Temple; CGenState.MoreApis = TRUE; CGenState.ListCol = pCGenState->ListCol; CGenState.CodeBurstIndex = pCGenState->CodeBurstIndex; Next = ExportsList.Flink; while (Next != &ExportsList) { CGenState.ExportsDbg = CONTAINING_RECORD(Next, EXPORTSDEBUG, ExportsDbgEntry ); Next= Next->Flink; if (Next == &ExportsList) { CGenState.MoreApis = FALSE; } // // Switch this API in or out depending on the platform info // ApiPlatform = CGenState.ExportsDbg->ApiPlatform; PlatformSwitchStart(&CGenState, ApiPlatform); CGenState.ApiTypes = GetApiTypes(CGenState.ExportsDbg); pTemple = GetTemplate(&EFuncTempleList, CGenState.ExportsDbg->ExportName ); ExcludedApi = FALSE; // skip this api if ex template, but no code if (!bExports && pTemple && TempleHasNoCodeBursts(pTemple)) { ExcludedApi = TRUE; fprintf(pCGenState->CGen->fp, "%s *** WARNING *** Excluded Api %s\n", CGenState.Temple->Comment, CGenState.ExportsDbg->ExportName ); } // // skip this api if: // - external forward reference // - internal forward which does not define the function. // (exportname != forwardname) // else if (!bExports && (CGenState.ExportsDbg->ExtForward || (CGenState.ExportsDbg->IntForward && CGenState.ExportsDbg->IntForward != CGenState.ExportsDbg))) { ExcludedApi = TRUE; fprintf(pCGenState->CGen->fp, "%s %s forwarded to %s\n", CGenState.Temple->Comment, CGenState.ExportsDbg->ExportName, CGenState.ExportsDbg->ExtForward ? CGenState.ExportsDbg->ExtForward : CGenState.ExportsDbg->IntForward->ExportName ); } // skip this api if DATA and no ex template else if (!pTemple && CGenState.ExportsDbg->Data) { ExcludedApi = TRUE; fprintf(pCGenState->CGen->fp, "%s *** WARNING *** Excluded Data Export %s\n", CGenState.Temple->Comment, CGenState.ExportsDbg->ExportName ); } // skip this api if CPP export and we aren't setup for CPP exports, else if (!pTemple && !iHandleCpp && CGenState.ExportsDbg->CplusDecoration) { ExcludedApi = TRUE; fprintf(pCGenState->CGen->fp, "%s *** WARNING *** Excluding CPP Api: %s\n", CGenState.Temple->Comment, CGenState.ExportsDbg->ExportName ); } // skip this api if members are unknown else if (!CGenState.ApiTypes->pfuncinfo) { ExcludedApi = TRUE; // members unknown - skip the API if (bIgnorePrototypeError) { fprintf(pCGenState->CGen->fp, "%s Error:4 Ignoring Api %s\n", CGenState.Temple->Comment, CGenState.ExportsDbg->ExportName ); } else { ExitErrMsg(FALSE, "API %s has no function prototype - unable to generate code.", CGenState.ExportsDbg->ExportName ); } } // gen code for this api else { if (pTemple) { CGenState.ExTemplate= TRUE; } else { CGenState.ExTemplate= FALSE; } BuildArgsList(pTemple, CGenState.ApiTypes->pfuncinfo, &CGenState.ExportsDbg->ArgsListHead ); if (GetArgSize(CGenState.ExportsDbg) < 0) { ExcludedApi = TRUE; // members unknown - skip the API if (bIgnorePrototypeError) { fprintf(pCGenState->CGen->fp, "%s Error:5 Ignoring Api %s\n", CGenState.Temple->Comment, CGenState.ExportsDbg->ExportName ); } else { ExitErrMsg(FALSE, "API %s has no function prototype - unable to generate code.", CGenState.ExportsDbg->ExportName ); } } else { CGenerate(pExpression, &CGenState); if (bExports) { // // we're generating the .DEF file. Mark some APIs // as private so the linker doesn't warn us. // if (strcmp(CGenState.ExportsDbg->ExportName, "DllGetClassObject") == 0 || strcmp(CGenState.ExportsDbg->ExportName, "DllCanUnloadNow") == 0 || strcmp(CGenState.ExportsDbg->ExportName, "DllRegisterServer") == 0 || strcmp(CGenState.ExportsDbg->ExportName, "DllRegisterServerEx") == 0 || strcmp(CGenState.ExportsDbg->ExportName, "DllInstall") == 0 || strcmp(CGenState.ExportsDbg->ExportName, "DllUnregisterServer") == 0) { fprintf(pCGenState->CGen->fp, " PRIVATE"); } } CGenState.ApiNum++; } } if (bExports) PlatformSwitchEnd(&CGenState, ApiPlatform); else{ if (ExcludedApi) PlatformSwitchEnd(&CGenState, ApiPlatform); else PlatformSwitchEndTable(&CGenState, ApiPlatform); } if (CGenState.ListCol) { WriteListColumn(&CGenState); } } GenHeapFree(pExpression); return pSrc; } PKNOWNTYPES BuildFakeTypesInfo( PEXPORTSDEBUG pExportsDbg, PKNOWNTYPES pKnownTypes ) { TYPESINFO ti; int ArgsSize, i; size_t Len; PFUNCINFO funcinfo; char *pch; memset(&ti, 0, sizeof(TYPESINFO)); strcpy(ti.TypeName, pExportsDbg->ExportName); if (pKnownTypes) { strcpy(ti.BasicType, pKnownTypes->BasicType); strcpy(ti.BaseName, pKnownTypes->BaseName); strcpy(ti.FuncRet, pKnownTypes->FuncRet); strcpy(ti.FuncMod, pKnownTypes->FuncMod); pExportsDbg->UnKnownApi = -1; // incomplete fn declaration /* * WARNING: * The type is added to the FakeFuncsList with args * info from the dll symbols. The type is NOT removed * from the FuncsList. */ } else { strcpy(ti.BasicType, szFUNC); strcpy(ti.FuncRet, szINT); pExportsDbg->UnKnownApi = 1; // missing fn declaration } ArgsSize = pExportsDbg->ArgsSize; if (!ArgsSize) { ti.TypeKind = TypeKindFunc; ti.dwMemberSize = sizeof(FUNCINFO) + strlen(szVOID) + 1; ti.pfuncinfo = (PFUNCINFO)ti.Members; pch = ti.Members + sizeof(FUNCINFO); strcpy(pch, szVOID); ti.pfuncinfo->sType = pch; } else if (ArgsSize < 0) { ; } else { ti.TypeKind = TypeKindFunc; pch = ti.Members + sizeof(FUNCINFO); Len = sizeof(ti.Members) - 1 - sizeof(FUNCINFO); funcinfo = (PFUNCINFO)ti.Members; ti.pfuncinfo = funcinfo; while (ArgsSize && Len) { ti.dwMemberSize+=sizeof(FUNCINFO); i = _snprintf(pch, Len, "Fake%x", ArgsSize); if (i < 0) { return NULL; } i++; Len -= i; funcinfo->sName = pch; pch += i; ti.dwMemberSize+=i; strcpy(pch, szINT); funcinfo->sType = pch; i = strlen(szINT) + 1; pch += i; ti.dwMemberSize+=i; ArgsSize -= sizeof(int); if (ArgsSize) { PFUNCINFO funcinfoNext; INT_PTR Realignment; // // Allocate space for another FUNCINFO, ensuring that // it is DWORD-aligned. // Len -= sizeof(FUNCINFO); Realignment = 4 - ((INT_PTR)pch & 3); Len -= Realignment; funcinfoNext = (PFUNCINFO)(pch + Realignment); pch += sizeof(FUNCINFO)+Realignment; ti.dwMemberSize += (DWORD)Realignment; if ((INT_PTR)Len < 0) { return NULL; } funcinfo->pfuncinfoNext = funcinfoNext; funcinfo = funcinfoNext; } } } return AddToTypesList(&FakeFuncsList, &ti); } /* * GetFuncArgNum */ int GetFuncArgNum(PCGENSTATE pCGenState) { PARGSLIST pArgsList; PKNOWNTYPES pkt; int NumArgs; PFUNCINFO funcinfo; pArgsList = pCGenState->pArgsList; if (!pArgsList) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetFuncArgNum Missing argument List\n\n" ); return -1; } pkt = pArgsList->pKnownTypes; while (!pkt->Members || !pkt->pfuncinfo) { if (pkt->pktBase) { // the knowntype is already cached pkt = pkt->pktBase; } else { PKNOWNTYPES pktOrg = pkt; pkt = GetNameFromTypesList(TypeDefsList, pkt->BaseName); if (!pkt) { if (pArgsList->pKnownTypes) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetFuncArgNum BaseType Not found:<%s:%s>\n\n", pArgsList->pKnownTypes->TypeName, pArgsList->pKnownTypes->BasicType ); } else { fprintf(pCGenState->CGen->fp, "\n\t*** ERRR ***\n*** GetFuncArgNum BaseType Not found: no KnownTypes\n\n" ); } return -1; } pktOrg->pktBase = pkt; } if (!strcmp(pkt->BasicType, pkt->TypeName)) { break; } } funcinfo = pkt->pfuncinfo; if (!pkt->Members || !funcinfo) { fprintf(pCGenState->CGen->fp, "/*** WARN gfan No Members:<%s:%s> ***/ ", pArgsList->pKnownTypes->TypeName, pkt->BasicType ); return 0; } // // "..." vargs is nonsense can't do it! // if (strcmp(funcinfo->sType, szVARGS) == 0) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetFuncArgNum variable Args:<%s:%s>\n\n", pArgsList->pKnownTypes->TypeName, pkt->BasicType ); return -1; } // // void arg list, Zero Args // if (strcmp(funcinfo->sType, szVOID) == 0) { return 0; } NumArgs = 0; do { NumArgs++; funcinfo = funcinfo->pfuncinfoNext; } while(funcinfo); return NumArgs; } /* * GetFuncIndex */ int GetFuncIndex(PCGENSTATE pCGenState, char *FuncTypeName) { PKNOWNTYPES pkt, pktFunc; int Len, LenExpr, LenArgs, LenRet; char *pch; char Args[1024]; PFUNCINFO funcinfo; PDEBUGSTRINGS DebugStrings; if (!FuncTypeName || !*FuncTypeName) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetFuncIndex TypeName Not specified\n\n" ); return -1; } pkt = GetNameFromTypesList(TypeDefsList, FuncTypeName); if (!pkt) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetFuncIndex Type Not found:<%s>\n\n", FuncTypeName ); return -1; } pktFunc = pkt; while (!pkt->Members || !pkt->pfuncinfo) { // NOTE: we cannot look at pkt->pktBase as it may point to a struct // knowntype instead of a typedef pkt = GetNameFromTypesList(TypeDefsList, pkt->BaseName); if (!pkt) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetFuncIndex BaseType Not found:<%s:%s>\n\n", FuncTypeName, pktFunc->BaseName ); return -1; } if (!strcmp(pkt->BasicType, pkt->TypeName)) { break; } } LenArgs = 1; Args[0] = '\0'; funcinfo = pkt->pfuncinfo; if (pkt->Members && funcinfo) { // // "..." vargs is nonsense can't do it! // if (strcmp(funcinfo->sType, szVARGS) == 0) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** GetFuncIndex variable Args:<%s:%s>\n\n", FuncTypeName, pkt->BasicType ); return -1; } // // void arg list means no args // if (strcmp(funcinfo->sType, szVOID) != 0) { pch = Args; do { // // Copy in the typename // Len = strlen(funcinfo->sType); LenArgs += Len; if (LenArgs >= sizeof(Args)-3) { break; } strcpy(pch, funcinfo->sType); pch += Len; // // Copy in the levels of indirection // LenArgs += funcinfo->IndLevel; if (LenArgs >= sizeof(Args)-3) { break; } for (Len = 0; LenIndLevel; ++Len) { *pch++ = '*'; } // // Copy in the argument name, if present // if (funcinfo->sName) { Len = strlen(funcinfo->sName) + 1; LenArgs += Len; if (LenArgs >= sizeof(Args)-3) { break; } *pch = ' '; strcpy(pch+1, funcinfo->sName); pch += Len; } // // Copy in the printf-style formatting for this argument // LenArgs += 3; *pch++ = ' '; *pch++ = '%'; *pch++ = 'x'; funcinfo = funcinfo->pfuncinfoNext; if (funcinfo) { LenArgs+=2; *pch++ = ','; *pch++ = ' '; } } while (funcinfo); if (LenArgs >= sizeof(Args)-5) { ExitErrMsg(FALSE, "GetFuncIndex overflow %s.%s\n", FuncTypeName, pkt->Members ); } } // // Null-terminate the Args[] string. // Args[LenArgs-1] = '\0'; } LenExpr = strlen(FuncTypeName) + 1; LenRet = strlen(pkt->FuncRet) + 4; DebugStrings = GenHeapAlloc(LenExpr + LenRet + LenArgs + sizeof(DEBUGSTRINGS)); if (!DebugStrings) { ExitErrMsg(TRUE, "GetFuncIndex: GenHeapAlloc(DebugStrings) %s.%s\n", FuncTypeName, pkt->Members ); } Len = 0; DebugStrings->Name = DebugStrings->Buffer; strcpy(DebugStrings->Name, FuncTypeName); Len += LenExpr; DebugStrings->ArgFormat = DebugStrings->Buffer + Len; strcpy(DebugStrings->ArgFormat, Args); Len += LenArgs; DebugStrings->RetFormat = DebugStrings->Buffer + Len; strcpy(DebugStrings->RetFormat, pkt->FuncRet); strcat(DebugStrings->RetFormat, " %x"); Len += LenRet; InsertTailList(&DebugStringsList, &DebugStrings->DebugStringsEntry); return NumDebugStringsEntries++; } /* * WriteDbgsStrings * */ void WriteDbgsStrings(char *pSrc, PCGENSTATE pCGenState) { DEBUGSTRINGS DebugStrings; char BaseName[MAX_PATH]; char *c; // copy in the DLL name and whack off the extension strcpy(BaseName, DllBaseName); c = strchr(BaseName, '.'); if (c) { *c = '\0'; } if (!pCGenState->DebugStrings) { pCGenState->DebugStrings = &DebugStrings; DebugStrings.Name = DebugStrings.ArgFormat = DebugStrings.RetFormat = ""; } fprintf(pCGenState->CGen->fp, "\"%s!%s\",\"%s\",\"%s\"", BaseName, pCGenState->DebugStrings->Name, pCGenState->DebugStrings->ArgFormat, pCGenState->DebugStrings->RetFormat ); } /* * ListDbgs */ char *ListDbgs(char *pSrc, PCGENSTATE pCGenState) { char *pch; char *pExpression; PLIST_ENTRY Next; CGENSTATE CGenState; pch = SkipSubExpression(pSrc, &pExpression); if (pSrc == pch || !pExpression) { return pch; } pSrc = pch; memset(&CGenState, 0, sizeof(CGenState)); CGenState.CGen = pCGenState->CGen; CGenState.Temple = pCGenState->Temple; CGenState.ListCol = pCGenState->ListCol; if (!IsListEmpty(&DebugStringsList)) { Next = DebugStringsList.Flink; while (Next != &DebugStringsList) { CGenState.DebugStrings = CONTAINING_RECORD(Next, DEBUGSTRINGS, DebugStringsEntry ); Next= Next->Flink; CGenState.MoreApis = (Next != &DebugStringsList) ? TRUE : FALSE; CGenerate(pExpression, &CGenState); if (CGenState.ListCol) { WriteListColumn(&CGenState); } } } else { CGenState.MoreApis = FALSE; CGenerate(pExpression, &CGenState); if (CGenState.ListCol) { WriteListColumn(&CGenState); } } GenHeapFree(pExpression); return pSrc; } /* * ListArgs */ char *ListArgs(char *pSrc, PCGENSTATE pCGenState, BOOL Always) { PARGSLIST pArgsList; PLIST_ENTRY Next; char *pch; char *pExpression; CGENSTATE CGenState; if (IsListEmpty(&pCGenState->ExportsDbg->ArgsListHead)) { fprintf(pCGenState->CGen->fp, "\n\t*** ERROR ***\n*** ListArgs Missing argument List: %s\n\n", pCGenState->ApiTypes->TypeName ); return SkipSubExpression(pSrc, NULL); } Next = pCGenState->ExportsDbg->ArgsListHead.Flink; // check for void arg list if (!Always) { pArgsList = CONTAINING_RECORD(Next, ARGSLIST, ArgumentsEntry); if (!pArgsList->Name && strcmp(pArgsList->Type, szVARGS)) { return SkipSubExpression(pSrc, NULL); } } CGenState = *pCGenState; pch = SkipSubExpression(pSrc, &pExpression); if (pSrc == pch || !pExpression) { return pch; } pSrc = pch; do { CGenState.pArgsList = CONTAINING_RECORD(Next,ARGSLIST, ArgumentsEntry); CGenerate(pExpression, &CGenState); if (!g_fLessTrailingWhitespace || Next->Flink != &CGenState.ExportsDbg->ArgsListHead) if (CGenState.ListCol) { WriteListColumn(&CGenState); } Next= Next->Flink; } while (Next != &CGenState.ExportsDbg->ArgsListHead); GenHeapFree(pExpression); return pSrc; } /* * WriteListColumn */ void WriteListColumn(PCGENSTATE pCGenState) { int Len; FILE *fp = pCGenState->CGen->fp; OutputColumn = pCGenState->ListCol; Len = OutputColumn - 1; if (fputc('\n', fp) != '\n') { ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC); return; } while (Len--) { if (fputc(' ', fp) != ' ') { ExitErrMsg(TRUE, "fputc %s\n", pCGenState->CGen->FileNameC); } } } /* * SkipSubExpression * */ char *SkipSubExpression(char *pSrc, char **pSubExpression) { char *pOrg = pSrc; char *pSave; int Len = 0; int ParenLevel; if ((*pSrc != '(') && (*pSrc != ',')) { return pOrg; } pSrc++; pSave = pSrc; ParenLevel = 1; Len = 0; while (*pSrc) { if (*pSrc == '(') { ParenLevel++; } else if (*pSrc == ')') { ParenLevel--; } pSrc++; if (!ParenLevel) { break; } Len++; } if (pSubExpression) { if (Len) { *pSubExpression = GenHeapAlloc(Len + 1); if (!*pSubExpression) { ExitErrMsg(TRUE, "GenHeapAlloc(SubExpression) %s\n", pOrg); } if (Len) { memcpy(*pSubExpression, pSave, Len); } *(*pSubExpression + Len) = '\0'; } else { *pSubExpression = NULL; } } return pSrc; } /* * GetTemplate */ PTEMPLES GetTemplate(PLIST_ENTRY pHeadList, char *TempleName) { PTEMPLES ptpl; PLIST_ENTRY Next; Next = pHeadList->Flink; while (Next != pHeadList) { ptpl = CONTAINING_RECORD(Next, TEMPLES, TempleEntry); if (!strcmp(ptpl->Name, TempleName)) { return ptpl; } Next= Next->Flink; } return NULL; } void UseLogMacros(char *LogName) { DWORD Len; char FullLogName[MAX_PATH+1]; char *LogBaseName; Len = GetFullPathName(LogName, sizeof(FullLogName) - 1, FullLogName, &LogBaseName ); if (Len == 0 || Len >= sizeof(FullLogName) - 1) { ExitErrMsg(TRUE, "Could not fully-qualify log filename '%s'\n", LogName); } fpLog = fopen(FullLogName, "w"); if (!fpLog) { ExitErrMsg(TRUE, "fopen(%s) failed\n", FullLogName); } if (!AddOpenFile(FullLogName, fpLog, NULL)) { ExitErrMsg(FALSE, "AddOpenFile failed\n"); } } char * UpdateLog( char *pSrc, PCGENSTATE pCGenState ) { FILE *fpOld; BOOL bMore; if (fpLog) { fpOld = pCGenState->CGen->fp; pCGenState->CGen->fp = fpLog; bMore = TRUE; } else { fpOld = NULL; bMore = FALSE; } pSrc = WriteMore(pSrc,pCGenState,bMore); if (bMore) { pCGenState->CGen->fp = fpOld; fprintf(fpLog, "\n"); } return pSrc; } /* * ExtractCGenerate */ BOOL ExtractCGenerate(char *pNames) { FILE *fp=NULL, *fpCpp=NULL; size_t Len; DWORD SizeFileName, SizeTempleName; DWORD SizeFileNameCpp = 0; char *pch; char *pchColon, *pchComma; PCGENERATE pCGen; char *OutputBaseNameCpp = 0; char FullOutputNameCpp[MAX_PATH+1]; char *OutputBaseName; char FullOutputName[MAX_PATH+1]; char OutputName[MAX_PATH+1]; char OutputNameCpp[MAX_PATH+1]; char TempleName[MAX_PATH]; DbgPrintf("CGenerate: %s\n", pNames); pchComma = strchr(pNames, ','); pchColon = strchr(pNames, ':'); if (pchComma != NULL) { pch = pchComma; } else { pch = pchColon; } Len = pch - pNames; if (!pch || !Len || Len >= sizeof(OutputName) - 1) { return FALSE; } strncpy(OutputName, pNames, Len); *(OutputName + Len) = '\0'; // // Extract the CPP filename, and initialize iHandleCPP // OutputNameCpp[0] = '\0'; if (pchComma) { size_t LenCpp; LenCpp = pchColon - ++pchComma; if (LenCpp >= sizeof(OutputNameCpp) - 1) { return(FALSE); } if (LenCpp) { iHandleCpp = 1; // use CPP macros strncpy(OutputNameCpp, pchComma, LenCpp); *(OutputNameCpp + LenCpp) = '\0'; } else { iHandleCpp = -1; // ignore CPP macros, and don't warn } Len += LenCpp + 1; } pNames += Len; if (*pNames != ':') { // no template name! return FALSE; } Len = GetFullPathName(OutputName, sizeof(FullOutputName) - 1, FullOutputName, &OutputBaseName ); if (Len >= sizeof(FullOutputName) - 1) { return FALSE; } SizeFileName = Len + 1; fp = fopen(FullOutputName, "w"); if (!fp) { ExitErrMsg(TRUE, "fopen(%s) failed\n", FullOutputName); } if (!AddOpenFile(FullOutputName, fp, NULL)) { ExitErrMsg(FALSE, "AddOpenFile failed\n"); } if (fseek(fp, 0, SEEK_SET)) { ExitErrMsg(TRUE, "ExtractCGenerate: fseek to 0 failed\n"); } // // Open the CPP file name // //if (iHandleCpp > 0) { if (OutputNameCpp[0]) { Len = GetFullPathName(OutputNameCpp, sizeof(FullOutputNameCpp) - 1, FullOutputNameCpp, &OutputBaseNameCpp ); if (!Len || (Len >= sizeof(FullOutputNameCpp) - 1)) { return FALSE; } SizeFileNameCpp = Len + 1; fpCpp = fopen(FullOutputNameCpp, "w"); if (!fpCpp) { ExitErrMsg(TRUE, "fopen(%s) failed\n", FullOutputNameCpp); } if (!AddOpenFile(FullOutputNameCpp, fpCpp, NULL)) { ExitErrMsg(FALSE, "AddOpenFile failed\n"); } if (fseek(fpCpp, 0, SEEK_SET)) { ExitErrMsg(TRUE, "ExtractCGenerate fseek #2 to 0 failed\n"); } } pch = GetNextToken(pNames); if (pch == pNames || !*pch) { return FALSE; } Len = CopyToken(TempleName, pch, sizeof(TempleName) - 1); if (!Len || Len >= sizeof(TempleName) - 1) { return FALSE; } SizeTempleName = Len + 1; Len = sizeof(CGENERATE) + 1; Len += SizeFileName + SizeTempleName + SizeFileNameCpp; pCGen = GenHeapAlloc(Len); if (!pCGen) { ExitErrMsg(TRUE, "GenHeapAlloc(CGENERATE)"); } memset(pCGen, 0, Len); if (bDebug) { setvbuf(fp, NULL, _IONBF, 0); } pCGen->fp = fp; pCGen->fpC = fp; strcpy(pCGen->TempleName, TempleName); pCGen->FileNameC = pCGen->TempleName + SizeTempleName; pCGen->FileBaseNameC = pCGen->FileNameC; pCGen->FileBaseNameC += OutputBaseName - FullOutputName; strcpy(pCGen->FileNameC, FullOutputName); // // Save the CPP filename, and file handle. // if (iHandleCpp > 0 && OutputNameCpp[0]) { if (bDebug) { setvbuf(fpCpp, NULL, _IONBF, 0); } pCGen->fpCpp = fpCpp; pCGen->FileNameCpp = pCGen->FileNameC + SizeFileName; pCGen->FileBaseNameCpp = pCGen->FileNameCpp; pCGen->FileBaseNameCpp += OutputBaseNameCpp - FullOutputNameCpp; strcpy(pCGen->FileNameCpp, FullOutputNameCpp); } InsertTailList(&CGenerateList, &pCGen->CGenerateEntry); return TRUE; } /* * ExtractTemples * */ BOOL ExtractTemples(char *FileName) { FILE *fp; int FileSize; BOOL bRet = FALSE; char *pSrc; char *pch; size_t Len; int CGenLen; LPSTR pCCode[MAX_CODEBURST]; char Comment[MAX_PATH]; char IndLevel[MAX_PATH]; char TempleType[MAX_PATH]; char TempleName[MAX_PATH]; char CodeBurstName[MAX_PATH]; LPSTR Also[MAX_ALSO]; int AlsoCount; LPSTR NoType[MAX_NOTYPE]; int NoTypeCount; PLIST_ENTRY pCaseList; char Line[1024]; int CodeBurstIndex; TOKENTYPE tkDirection; PTEMPLES tpl; BOOL fFreeCCode = TRUE; int i; DbgPrintf("Template: %s\n", FileName); fp = fopen(FileName, "r"); if (!fp) { ExitErrMsg(TRUE, "fopen(%s) failed\n", FileName); } if (fseek(fp, 0, SEEK_END)) { ExitErrMsg(TRUE, "fseek to EOF failed\n"); } FileSize = ftell(fp); if (fseek(fp, 0, SEEK_SET)) { ExitErrMsg(TRUE, "fseek to 0 failed\n"); } // Record the filename/line number information for error messages TemplateFileName = FileName; TemplateLine = 1; if (!fgets(Line, sizeof(Line) - 1, fp)) { if (ferror(fp)) { ExitErrMsg(TRUE, "Failed to get Types from %s\n", FileName); } else if (feof(fp)) { ExitErrMsg(TRUE, "Premature EOF %s\n", FileName); } } // reset the TempleType: no [TempleType] is active *TempleType = '\0'; // reset all variables used within a [TempleType] CGenLen = 0; *IndLevel = 0; *TempleName = '\0'; strcpy(Comment, "//"); memset(pCCode, 0, sizeof(LPSTR)*MAX_CODEBURST); tkDirection = TK_EOS; // assume template handles all flavors of IN/OUT AlsoCount=0; NoTypeCount=0; pCaseList = NULL; // loop over all lines in the template file do { pSrc = Line; // skip whitespace at the start of the line while (*pSrc && isspace(*pSrc)) { pSrc++; } // if at end-of-line or encountered ';' (comment-to-EOL), go to // next line. if (!*pSrc || *pSrc == ';') { goto GetNextLine; } if (*pSrc == '[') { // encountered new [TempleType]. If there was a previous template, // add it now. if (*TempleName && !AddTemple(TempleType, TempleName, Comment, IndLevel, pCCode, tkDirection, Also, AlsoCount, NoType, NoTypeCount, pCaseList)) { ExitErrMsg(FALSE, "%s(%d) %s %s\n", TemplateFileName, TemplateLine, TempleType, pSrc); } // free the previous template's memory if (fFreeCCode) { for (i=0; i < MAX_CODEBURST; ++i) { if (pCCode[i]) { GenHeapFree(pCCode[i]); } } } fFreeCCode = TRUE; // reset the vars used for each template CGenLen = 0; memset(pCCode, 0, sizeof(LPSTR)*MAX_CODEBURST); *IndLevel = 0; *TempleName = '\0'; strcpy(Comment, "//"); tkDirection = TK_EOS; // assume template handles all flavors of IN/OUT pCaseList = NULL; for (i=0; i= sizeof(TempleType) - 1) { goto ETPLExit; } pch = pSrc + Len; if (*pch != ']') { *TempleType = '\0'; } goto GetNextLine; } // if no active [TempleType], ignore the line if (!*TempleType) { goto GetNextLine; } // a [TempleType] is active. Scan for known property names if ( ((pch = SkipKeyWord(pSrc, szTEMPLENAME)) != pSrc || (pch = SkipKeyWord(pSrc, szMACRONAME)) != pSrc || (pch = SkipKeyWord(pSrc, szTYPENAME)) != pSrc) && *pch == '=') { // found: TemplateName= // or MacroName= // or TypeName= // They all mean the same thing. // If a template is outstanding, add it now. if (*TempleName && !AddTemple(TempleType, TempleName, Comment, IndLevel, pCCode, tkDirection, Also, AlsoCount, NoType, NoTypeCount, pCaseList)) { ExitErrMsg(FALSE, "%s(%d) %s %s\n", TemplateFileName, TemplateLine, TempleType, pSrc); } // free the previous template's memory if (fFreeCCode) { for (i=0; i < MAX_CODEBURST; ++i) { if (pCCode[i]) { GenHeapFree(pCCode[i]); } } } fFreeCCode = TRUE; // reset the vars used for each template CGenLen = 0; memset(pCCode, 0, sizeof(LPSTR)*MAX_CODEBURST); *IndLevel = 0; *TempleName = '\0'; tkDirection = TK_EOS; // assume template handles all flavors of IN/OUT pCaseList = NULL; for (i=0; ipMArgs = pMArgsList; InsertTailList(pCaseList, &(pMLListEntry->ListEntry)); pch += Len; } else if ((pch = SkipKeyWord(pSrc, szALSO)) != pSrc && *pch == '=') { char *t; if (NoTypeCount) { ExitErrMsg(FALSE, "%s(%d) Cannot have both Also= and NoType= in the same template\n", TemplateFileName, TemplateLine); } // skip '=' and any leading spaces do { pch++; if (*pch == '\0') { goto ETPLExit; } } while (isspace(*pch) && *pch != '\0'); // get length of the Also= name t = pch; while (isgraph(*t)) { t++; } Len= t-pch; // copy the name t = GenHeapAlloc(Len + 1); memcpy(t, pch, Len); t[Len] = '\0'; if (AlsoCount == MAX_ALSO) { ExitErrMsg(FALSE, "%s(%d) Max. of %d Also= clauses allowed. Also=%s\n", TemplateFileName, TemplateLine, MAX_ALSO, t); } Also[AlsoCount++] = t; pch += Len; } else { GetNextCodeBurst: // grab the name, and if the next thing isn't '=', error out. pch = GetNextToken(pSrc); if (*pch != '=') { goto ETPLExit; } Len = CopyToken(CodeBurstName, pSrc, pch-pSrc); pch += Len; // convert the name into an index CodeBurstIndex = GetCodeBurstIndex(CodeBurstName); if (pCCode[CodeBurstIndex]) { // Two codebursts with the same name in this template goto ETPLExit; } pCCode[CodeBurstIndex] = GenHeapAlloc(FileSize*2 + 1); CGenLen = 0; pSrc = pCCode[CodeBurstIndex]; while (fgets(pSrc, FileSize*2 - CGenLen, fp)) { char buffer[MAX_PATH]; int len; TemplateLine++; len = CopyToken(buffer, pSrc, sizeof(buffer)); pch = pSrc; if (len && pSrc[len] == '=') { // The line starts with some keyword and is followed by // an '=' sign. if (strcmp(buffer, szCGENEND) == 0 || strcmp(buffer, "CGenEnd") == 0) { // The string is 'End=' or 'CGenEnd='. The CodeBurst // is done. *pSrc = '\0'; CGenLen++; pch += len+1; break; } // See if it is the start of a new CodeBurst: CodeBurstIndex = GetExistingCodeBurstIndex(buffer); if (CodeBurstIndex != -1) { strcpy(Line, pSrc); *pSrc = '\0'; CGenLen++; pSrc = Line; goto GetNextCodeBurst; } } Len = strlen(pSrc); CGenLen += Len; pSrc += Len; } if (!CGenLen) { GenHeapFree(pCCode[CodeBurstIndex]); pCCode[CodeBurstIndex] = NULL; } } while (*pch && *pch != ';' && IsSeparator(*pch)) { pch++; } if (*pch) { if (*pch == ';') { // comment to end-of-line goto GetNextLine; } goto ETPLExit; } GetNextLine: TemplateLine++; } while (fgets(Line, sizeof(Line) - 1, fp)); // If there is an outstanding template when EOF is hit, add it now. if (*TempleName && !AddTemple(TempleType, TempleName, Comment, IndLevel, pCCode, tkDirection, Also, AlsoCount, NoType, NoTypeCount, pCaseList)) { ExitErrMsg(FALSE, "%s(%d) %s %s\n", TemplateFileName, TemplateLine, TempleType, pSrc); } if (!feof(fp) && ferror(fp)) { ExitErrMsg(TRUE, "%s(%d) Read error: %s\n", TemplateFileName, TemplateLine, TempleName); } bRet = TRUE; ETPLExit: if (!bRet) { ErrMsg("%s(%d) ETPL: Invalid Line <%s>\n%s\n", TemplateFileName, TemplateLine, pSrc, Line); } if (fFreeCCode) { for (i=0; i < MAX_CODEBURST; ++i) { if (pCCode[i]) { GenHeapFree(pCCode[i]); } } } for (i=0; iExportName)) { return pexportsdbg; } pNext = pNext->Flink; } return NULL; } PLIST_ENTRY ListFromTempleType( char *TempleType ) { if (!TempleType || !*TempleType) { return NULL; } if (!strcmp(TempleType, szIFUNC)) { return &IFuncTempleList; } else if (!strcmp(TempleType, szEFUNC)) { return &EFuncTempleList; } else if (!strcmp(TempleType, szTYPES)) { return &TypeTempleList; } else if (!strcmp(TempleType, szCODE)) { return &CodeTempleList; } else if (!strcmp(TempleType, szEFAST)) { return &EFastTempleList; } else if (!strcmp(TempleType, szMACROS)) { return &MacroList; } else if (!strcmp(TempleType, szFAILTYPES)) { return &FailTempleList; } return NULL; } /* * AddTemple * * worker function for ExtractTemple, to verify and store template. */ #pragma optimize("", off) BOOL AddTemple( char *TempleType, char *TempleName, char *Comment, char *IndLevel, char *pCCode[MAX_CODEBURST], TOKENTYPE tkDirection, char *Also[MAX_ALSO], int AlsoCount, char *NoType[MAX_NOTYPE], int NoTypeCount, PLIST_ENTRY pCaseList ) { PLIST_ENTRY pHeadList = NULL; PTEMPLES ptpl; char *pch; int SizeCGen, SizeTempleName, SizeComment, SizeNoType; int Len; int i; int AlsoIndex; if (!*TempleName) { return FALSE; } pHeadList = ListFromTempleType(TempleType); if (!pHeadList) { return FALSE; } SizeCGen = 0; for (i=0; iIndLevel = strtoul(IndLevel, &pch, 10); ptpl->tkDirection = tkDirection; Len = 0; ptpl->Name = ptpl->Buffer; strcpy(ptpl->Name, TempleName); Len += SizeTempleName; ptpl->Comment = ptpl->Buffer + Len; strcpy(ptpl->Comment, Comment); Len += SizeComment; for (i=0; iCodeBurst[i] = ptpl->Buffer + Len; Len++; strcpy(ptpl->CodeBurst[i], pCCode[i]); Len += strlen(pCCode[i]); if (g_fLessTrailingWhitespace) StripTrailingWhitespaceFromString(ptpl->CodeBurst[i]); } } for (i=0; iNoTypes[i] = ptpl->Buffer + Len; Len++; strcpy(ptpl->NoTypes[i], NoType[i]); Len += strlen(NoType[i]); } ptpl->pCaseList = pCaseList; InsertTailList(pHeadList, &ptpl->TempleEntry); if (bDebug && Len >= SizeCGen+SizeTempleName+SizeComment+SizeNoType) { ExitErrMsg(FALSE, "Buffer overrun in AddTemple! Heap is trashed! ptpl=%x\n", ptpl); } if (bDebug) { DumpTemplate(ptpl, stdout); } if (AlsoIndex == AlsoCount) { break; } // there are Also= lines, add those template, too strcpy(TempleName, Also[AlsoIndex]); AlsoIndex++; } return TRUE; } #pragma optimize("", on) /* * */ void DumpTemplate(PTEMPLES ptpl, FILE *fp) { int i; fprintf(fp,"Temple: %d Name<%s>\n", ptpl->IndLevel, ptpl->Name ); for (i=0; i\n", TemplateFileName, TemplateLine, CodeBursts[i].Name, ptpl->CodeBurst[i]); } } } ULONG EndianSwitch( PULONG pul ) { ULONG NewValue; PBYTE pbValue = (PBYTE)pul; PBYTE pbNewValue = (PBYTE) &NewValue; *pbNewValue++ = *(pbValue + 3); *pbNewValue++ = *(pbValue + 2); *pbNewValue++ = *(pbValue + 1); *pbNewValue = *pbValue; return NewValue; } /* MapViewDll * * Creates a Mapped view of a Dll and intializes * Dll global variables for easy access to the Export Directory * * DllMappedBase * DllRvaOffset * DllExportDir * DllExportDirSize * DllFunctions * DllNameOrdinals * DllNameTable * * */ BOOL MapViewDll(char *DllName) { ULONG_PTR RvaOffset; HANDLE hFile; HANDLE hMapFile; PVOID MappedBase; PIMAGE_EXPORT_DIRECTORY ExportDir; ULONG ExportDirSize; // // open and map the file to get the exports info // hFile = CreateFile(DllName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if (hFile == INVALID_HANDLE_VALUE) { ErrMsg("MapViewDll CreateFile(%s) gle %d\n", DllName, GetLastError()); return FALSE; } hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0,NULL); if (!hMapFile) { ErrMsg("MapViewDll CreateFileMapping(%s) gle %d\n", DllName, GetLastError()); return FALSE; } MappedBase = MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); if (!MappedBase) { ErrMsg("MapViewDll MapViewOfFile(%s) gle %d\n", DllName, GetLastError()); return FALSE; } ExportDir = ImageDirectoryEntryToData( MappedBase, TRUE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportDirSize ); if (!ExportDir) { ErrMsg("MapViewDll ImageDirectoryEntryToData=NULL\n"); return FALSE; } // // Initialize the global variables. // RvaOffset = (ULONG_PTR)ExportDir - (ULONG_PTR)MappedBase; ExportDir = ImageDirectoryEntryToData( MappedBase, FALSE, IMAGE_DIRECTORY_ENTRY_EXPORT, &ExportDirSize ); if (!ExportDir) { ErrMsg("MapViewDll ImageDirectoryEntryToData=NULL on the second call\n"); return FALSE; } DllExportDirSize = ExportDirSize; DllMappedBase = MappedBase; DllRvaOffset = RvaOffset; DllExportDir = ExportDir; DllFunctions = (PULONG)((ULONG_PTR)ExportDir + (ULONG_PTR)ExportDir->AddressOfFunctions - RvaOffset ); DllNameTable = (PULONG)((ULONG_PTR)ExportDir + (ULONG_PTR)ExportDir->AddressOfNames - RvaOffset ); DllNameOrdinals = (PUSHORT)((ULONG_PTR)ExportDir + (ULONG_PTR)ExportDir->AddressOfNameOrdinals - RvaOffset ); fprintf(stdout, "Name %s Base %x Ver %x.%x NumberOfFunctions %x NumberOfNames %x\n", (PCHAR)((ULONG_PTR)ExportDir + (ULONG_PTR)ExportDir->Name - RvaOffset), ExportDir->Base, (ULONG)ExportDir->MajorVersion, (ULONG)ExportDir->MinorVersion, ExportDir->NumberOfFunctions, ExportDir->NumberOfNames ); return TRUE; } ULONG DllOrdinalByName( char *ExportName ) { PULONG pNames; ULONG NumNames; PUSHORT pNameOrdinals; char *Name; pNames = DllNameTable; pNameOrdinals = DllNameOrdinals; NumNames = DllExportDir->NumberOfNames; while (NumNames--) { Name = (char *)((ULONG_PTR)DllExportDir + *pNames - DllRvaOffset); if (!strcmp(Name, ExportName)) { return *pNameOrdinals + DllExportDir->Base; } pNames++; pNameOrdinals++; } return 0; } /* MapViewImplib * * Creates a Mapped view of an import library and intializes * ImpLib global variables for access to symbols in the first * special linker member. * * ImplibMappedBase * ImplibNumSymbols * ImplibSymbolMembers * ImplibSymbolNames * */ BOOL MapViewImplib(char *LibName) { HANDLE hFile; HANDLE hMapFile; PBYTE MappedBase; PBYTE VirtualOffset; ULONG MemberSize; PIMAGE_ARCHIVE_MEMBER_HEADER ArchiveMemberHeader; // // open and map the file. // hFile = CreateFile(LibName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if (hFile == INVALID_HANDLE_VALUE) { ErrMsg("MapViewImplib CreateFile(%s) gle %d\n", LibName, GetLastError()); return FALSE; } hMapFile = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, 0,NULL); if (!hMapFile) { ErrMsg("MapViewImplib CreateFileMapping(%s) gle %d\n", LibName, GetLastError()); return FALSE; } MappedBase = (PBYTE)MapViewOfFile(hMapFile, FILE_MAP_READ, 0, 0, 0); if (!MappedBase) { ErrMsg("MapViewImplib MapViewOfFile(%s) gle %d\n", LibName, GetLastError()); return FALSE; } // // Verify the file is an archive // if (memcmp(MappedBase, IMAGE_ARCHIVE_START, IMAGE_ARCHIVE_START_SIZE)) { ErrMsg("MapViewImplib IMAGE_ARCHIVE_START_SIZE invalid(%s)\n", LibName); return FALSE; } VirtualOffset = MappedBase + IMAGE_ARCHIVE_START_SIZE; ArchiveMemberHeader = (PIMAGE_ARCHIVE_MEMBER_HEADER) VirtualOffset; if (sscanf((char *) ArchiveMemberHeader->Size, "%ld", &MemberSize) != 1) { ErrMsg("MapViewImplib ArchiveMemberHeader->Size '%s' corrupt\n", (char *) ArchiveMemberHeader->Size); return FALSE; } // // Verify first special linker member exists (name == "\\") // if (memcmp(ArchiveMemberHeader->Name, IMAGE_ARCHIVE_LINKER_MEMBER, sizeof(ArchiveMemberHeader->Name))) { ErrMsg("MapViewImplib first special linker member missing (%s)\n", LibName); return FALSE; } // // First Linker Member format (Big endian!) // NumberOfSymbols, 4 bytes // Offsets, 4 bytes * NumSymbols // StringTable NumSymbols == NumStrings // VirtualOffset += sizeof(IMAGE_ARCHIVE_MEMBER_HEADER); ImplibNumSymbols = EndianSwitch((PULONG)VirtualOffset); VirtualOffset += 4; ImplibSymbolMembers = (PULONG)VirtualOffset; VirtualOffset += ImplibNumSymbols * sizeof(ULONG); ImplibSymbolNames = (PCHAR)VirtualOffset; ImplibMappedBase = MappedBase; fprintf(stdout, "Implib: %s Base %p\n", LibName, ImplibMappedBase); return TRUE; } BOOL ExtractMember( ULONG MemberOffset, PULONG Ordinal, BOOLEAN *Data ) { PIMAGE_FILE_HEADER ImageFileHeader; PBYTE VirtualOffset; BOOL Idata5Found, TextFound; VirtualOffset = (PBYTE)ImplibMappedBase + MemberOffset; VirtualOffset += sizeof(IMAGE_ARCHIVE_MEMBER_HEADER); ImageFileHeader = (PIMAGE_FILE_HEADER) VirtualOffset; *Ordinal = 0; Idata5Found = FALSE; TextFound = FALSE; if (ImageFileHeader->Machine == 0 && ImageFileHeader->NumberOfSections == 0xffff) { // // VC6 format import lib found. // PVC6_IMAGE_IMPORT_HEADER pHdr; pHdr = (PVC6_IMAGE_IMPORT_HEADER)ImageFileHeader; if (pHdr->NameType == IMPORT_ORDINAL) { // // pHdr->wOrdinal specifies the ordinal for this import. // *Ordinal = 0x80000000 | (ULONG)pHdr->Ordinal; } if (pHdr->Type == IMPORT_DATA) { // // This is a data import // *Data = TRUE; } Idata5Found = TRUE; } else { // // Pre-VC6 import lib. // ULONG NumSections; ULONG UNALIGNED *RawDataPointer; IMAGE_SECTION_HEADER UNALIGNED *ImageSectionHeader; NumSections = ImageFileHeader->NumberOfSections; // // Carefull, librarian doesn't align the Image section header according // to normal rules for images. // VirtualOffset += sizeof(IMAGE_FILE_HEADER) + ImageFileHeader->SizeOfOptionalHeader; ImageSectionHeader = (IMAGE_SECTION_HEADER UNALIGNED *)VirtualOffset; while (NumSections--) { // // Implib provides .idata5, and .idata4 (duplicate) which // contains the ordinal number with the hi bit set if it // was specified in the module definition file. Otherwise // the ordinal number is not specified in the implib. // if (!Idata5Found && !strncmp(ImageSectionHeader->Name, szIDATA5, sizeof(szIDATA5)-1)) { // // Carefull, librarian doesn't align the begining of raw data // according to normal rules for images. // RawDataPointer = (ULONG UNALIGNED *)((PBYTE)ImageFileHeader + ImageSectionHeader->PointerToRawData); if (*RawDataPointer & 0x80000000) { *Ordinal = *RawDataPointer; } Idata5Found = TRUE; } else if (!TextFound && !strncmp(ImageSectionHeader->Name, szTEXT, sizeof(szTEXT)-1)) { TextFound = TRUE; } ImageSectionHeader++; } *Data = (!TextFound) ? TRUE : FALSE; // if no text section, must be data export } return Idata5Found; } BOOL InitExportDebug( PEXPORTSDEBUG ExportDebug, char *SymbolName, ULONG SymbolMember ) { ULONG_PTR Forward; ULONG OrdinalIndex; char *pch = SymbolName; // we assume __implib_ prefix not present // // C fn begins with "_" // C++ fn begins with "?" // Data export begins with "??_C" in real symbols, // but in implib looks a C function // if (*pch == '?') { ExportDebug->CplusDecoration = pch; DbgPrintf("C++ export %s\n", SymbolName); } else { ExportDebug->CplusDecoration = NULL; } // // Copy out the ExportName. // if (*pch == '_' || *pch == '?' || *pch == '@') { pch++; // skip lead char (underscor, qmark) } strcpy(ExportDebug->ExportName, pch); pch = strchr(ExportDebug->ExportName, '@'); if (SymbolName[0] == '?' && SymbolName[1] == '?') { // // Found a "real" C++ name: a mangled version of // "classname::membername". Use the fully-mangled function name, // instead of the name with the leading '?' stripped, and don't // truncate after the '@'. // strcpy(ExportDebug->ExportName, SymbolName); pch = NULL; } if (pch && ExportDebug->CplusDecoration && pch[1] != '@') { // // This export is '?membername@classname@@...'. Don't truncate! // strcpy(ExportDebug->ExportName, SymbolName); pch = NULL; } if (pch && !bNoFuzzyLogic) { // truncate the symbol from ExportName *pch = '\0'; } // // Get the decoration, for synthetic args // cdecl has no decoration // stdcall has total arg size // if (pch && !ExportDebug->CplusDecoration) { ExportDebug->ArgsSize = strtol(pch + 1, NULL, 10); } else { ExportDebug->ArgsSize = -1; } // // Fetch the ordinal from the implib. In an Implib the ordinal // only appears if an ordinal is specifed in the def file. // if (!ExtractMember(SymbolMember, &ExportDebug->Ordinal, &ExportDebug->Data)) { ErrMsg("InitExportDebug: %s Member not found\n", SymbolName); return FALSE; } if (ExportDebug->Data) { DbgPrintf("DATA export %s\n", SymbolName); } // // If we don't yet have an ordinal, search the ExportNameTable // for the Ordinal number. Note that Ordinals which *must* appear // in generated def files have the hi-bit set! // if (!ExportDebug->Ordinal) { ExportDebug->Ordinal = DllOrdinalByName(ExportDebug->ExportName); if (!ExportDebug->Ordinal) { ErrMsg("InitExportDebug: %s Ordinal not found\n", SymbolName); return FALSE; } } // // Look up function using ordinal as index to function table. // OrdinalIndex = IMPORDINAL(ExportDebug->Ordinal) - DllExportDir->Base; ExportDebug->Function = *(DllFunctions + OrdinalIndex); // // Check for references forwarded externally, we only need // external forwards which are really internal forwards. // // e.g rpcrt4.dll has following def file entries: // // I_RpcBindingInqDynamicEndpoint=RPCRT4.I_RpcBindingInqDynamicEndpointW // I_RpcBindingInqDynamicEndpointW // // Our thunk dll will use the following: // // I_RpcBindingInqDynamicEndpoint=I_RpcBindingInqDynamicEndpointW // I_RpcBindingInqDynamicEndpointW // // It is important to strip the "rpcrt4." as this adds an extra // loader reference to rpcrt4.dll. // // ExportDebug->ExtForward = NULL; Forward = (ULONG_PTR)DllExportDir + ExportDebug->Function - DllRvaOffset; if (Forward > (ULONG_PTR)DllExportDir && Forward < (ULONG_PTR)DllExportDir + DllExportDirSize) { char *pSrc; pSrc = (char *) Forward; pch = DllBaseName; while (*pSrc && *pSrc != '.' && toupper(*pSrc) == toupper(*pch)) { pSrc++; pch++; } if (*pSrc == *pch) { ExportDebug->ExtForward = pSrc + 1; } } DbgPrintf("%4.1d %8.1x(%4.1d) %8.1x %s(%s)\n", ExportDebug->ArgsSize, ExportDebug->Ordinal, IMPORDINAL(ExportDebug->Ordinal), ExportDebug->Function, ExportDebug->ExportName, ExportDebug->ExtForward ? ExportDebug->ExtForward : "" ); return TRUE; } /* * SetInternalForwards * * * */ void SetInternalForwards(void) { PLIST_ENTRY NextExport; PEXPORTSDEBUG ExportDebug; // // check each export in the list for multiple exports to same function. // For each set of internal forwards identify which export defines the api, // and save this in the IntForward field. // NextExport= ExportsList.Flink; while (NextExport != &ExportsList) { ExportDebug = CONTAINING_RECORD(NextExport, EXPORTSDEBUG, ExportsDbgEntry ); if (ExportDebug->Function && !ExportDebug->ExtForward && !ExportDebug->IntForward) { PLIST_ENTRY Next; PEXPORTSDEBUG pexdbg; PEXPORTSDEBUG KnownApi =NULL; int ArgSize = ExportDebug->ArgsSize; // // Walk the rest of the list to find first duplicate function // Next = NextExport->Flink; while (Next != &ExportsList) { pexdbg = CONTAINING_RECORD(Next, EXPORTSDEBUG, ExportsDbgEntry ); if (pexdbg->Function == ExportDebug->Function) { if (pexdbg->ArgsSize >= 0) { ArgSize = pexdbg->ArgsSize; } break; } Next = Next->Flink; } if (Next != &ExportsList) { // // We found one dup function. Temporarily link together this set // of dup functions using the IntForward field, and determine // the first KnownApi. // if (GetNameFromTypesList(FuncsList, ExportDebug->ExportName)) { KnownApi = ExportDebug; } do { pexdbg = CONTAINING_RECORD(Next, EXPORTSDEBUG, ExportsDbgEntry ); if (pexdbg->Function == ExportDebug->Function) { pexdbg->IntForward = ExportDebug->IntForward; ExportDebug->IntForward = pexdbg; if (pexdbg->ArgsSize >= 0) { ArgSize = pexdbg->ArgsSize; } if (!KnownApi && GetNameFromTypesList(FuncsList, pexdbg->ExportName)) { KnownApi = pexdbg; } } Next = Next->Flink; } while (Next != &ExportsList); // // If we found multiple entries, walk the temp links, and insert // the KnownApi, which is used to define the api. If we didn't // find a known api, use ExportDebug, and hope for the best // (since its not known). // if (!KnownApi) { KnownApi = ExportDebug; } pexdbg = ExportDebug; while (pexdbg) { PEXPORTSDEBUG NextForward; NextForward = pexdbg->IntForward; pexdbg->IntForward = KnownApi; pexdbg->ArgsSize = ArgSize; DbgPrintf("IntForward: %s to %s\n", pexdbg->ExportName, KnownApi->ExportName ); pexdbg = NextForward; } } } NextExport = NextExport->Flink; } } /* * ExtractExports - * * reads the exports debug info from a dll, * and builds the exports list. * */ BOOL ExtractExports(void) { ULONG NumNames; PULONG pNames; PUSHORT pNameOrdinals; PULONG ImpSymbolMember; PCHAR ImpSymbolName; EXPORTSDEBUG ExportDebug; char ExportName[MAX_PATH+1]; // // For each "__imp_" in the implib, gather name, symbol and ordinal // and determine its forward status. This will pick up all exports // except those which are marked "PRIVATE". // NumNames = ImplibNumSymbols; ImpSymbolMember = ImplibSymbolMembers; ImpSymbolName = ImplibSymbolNames; while (NumNames--) { if (!strncmp(szIMPPREFIX, ImpSymbolName, sizeof(szIMPPREFIX) - 1)) { memset(&ExportDebug, 0, sizeof(ExportDebug)); ExportDebug.ApiPlatform = API_ALL; ExportDebug.ExportName = ExportName; if (!InitExportDebug(&ExportDebug, ImpSymbolName + sizeof(szIMPPREFIX) - 1, EndianSwitch(ImpSymbolMember) )) { return FALSE; } if (!AddToExportsList(&ExportDebug)) { return FALSE; } } ImpSymbolMember++; ImpSymbolName += strlen(ImpSymbolName) + 1; } // // Search the Export name table for exports which haven't been added yet. // These are "PRIVATE" exports with names. We will still be missing // exports which are "PRIVATE NONAME", and we won't have symbolic info // for the private named exports. // NumNames = DllExportDir->NumberOfNames; pNames = DllNameTable; pNameOrdinals = DllNameOrdinals; while (NumNames--) { memset(&ExportDebug, 0, sizeof(ExportDebug)); ExportDebug.Ordinal = *pNameOrdinals + DllExportDir->Base; ExportDebug.Ordinal |= 0x80000000; ExportDebug.Function = *(DllFunctions + *pNameOrdinals); ExportDebug.ExportName = (char *)((ULONG_PTR)DllExportDir + *pNames - DllRvaOffset); ExportDebug.ApiPlatform = API_ALL; if (!FindInExportsList(ExportDebug.ExportName)) { ULONG_PTR Forward; char *pch; // // Check for references forwarded externally, we only need // external forwards which are really internal forwards. // ExportDebug.ExtForward = NULL; Forward = (ULONG_PTR)DllExportDir + ExportDebug.Function - DllRvaOffset; if (Forward > (ULONG_PTR)DllExportDir && Forward < (ULONG_PTR)DllExportDir + DllExportDirSize) { char *pSrc; pSrc = (char *)Forward; pch = DllBaseName; while (*pSrc && *pSrc != '.' && *pSrc == *pch) { pSrc++; pch++; } if (*pSrc == '.' && *pSrc == *pch) { ExportDebug.ExtForward = pSrc + 1; } } // // Check for decorations embedded in the exportname // pch = strchr(ExportDebug.ExportName, '@'); if (pch++ && *pch != '@') { ExportDebug.ArgsSize = strtol(pch, NULL, 10); } else { ExportDebug.ArgsSize = -1; } ExportDebug.PrivateNamed = TRUE; DbgPrintf("Private Named Export: %4.1d %8.1x(%4.1d) %8.1x %s(%s)\n", ExportDebug.ArgsSize, ExportDebug.Ordinal, IMPORDINAL(ExportDebug.Ordinal), ExportDebug.Function, ExportDebug.ExportName, ExportDebug.ExtForward ? ExportDebug.ExtForward : "" ); if (!AddToExportsList(&ExportDebug)) { return FALSE; } } // advance to next name\ordinal pNames++; pNameOrdinals++; } return TRUE; } /* ExtractServicesTab- Used as a replacement to ExtractXpt. Extracts file list from a services.tab file as used in the ntos project. */ void ExtractServicesTab(char *pch) { FILE *fp; char pTemp; EXPORTSDEBUG ExportDebug; char Line[MAX_PATH]; char ExportName[MAX_PATH]; char *ApiName; char *Prepend; char *FileName; size_t len, PrependLen; //extract filename and optional prepend name FileName = pch; while(*pch != ':' && *pch != '\0') pch++; pTemp = *pch; *pch = '\0'; if (pTemp == ':') { pch++; Prepend = pch; while(*pch != '\0') { pch++; } PrependLen = pch-Prepend; } else { Prepend = pch; PrependLen = 0; } if (PrependLen > MAX_PATH - 1) { ExitErrMsg(FALSE, "ExSt: Text to prepend to functions names is too long\n"); } memcpy(ExportName, Prepend, PrependLen); DbgPrintf("ExST: %s,%s\n", FileName, Prepend); fp = fopen(FileName, "r"); if (!fp) { ExitErrMsg(TRUE, "ExST: fopen(%s) failed\n", FileName); } if (fseek(fp, 0, SEEK_SET)) { ExitErrMsg(TRUE, "ExST: fseek to 0 failed\n"); } if (!fgets(Line, sizeof(Line) - 1, fp)) { if (ferror(fp)) { ExitErrMsg(FALSE, "ExST: Failed to get Defs from %s\n", FileName); } else if (feof(fp)) { ExitErrMsg(FALSE, "ExST: Premature EOF %s\n", FileName); } } do { // skip leading spaces pch = Line; while (*pch && isspace(*pch)) { pch++; } if (*pch == '\0') continue; // Grab the function name ApiName = pch; while(*pch != ',' && *pch != '\0') pch++; len = pch - ApiName; if (len + PrependLen + 1 > sizeof(ExportName)) { ErrMsg("ExST: ExportName Buffer overflow\n"); } //Copy everything over memcpy(ExportName + PrependLen, ApiName, len); ExportName[PrependLen + len] = '\0'; if (FindInExportsList(ExportName)) { // // Name is already in the Exports list. Ignore the second // one. // DbgPrintf("Warning: API %s was listed more than once in the services.tab. Ignoring subsequent copies.\n", ExportName); continue; } memset(&ExportDebug, 0, sizeof(ExportDebug)); ExportDebug.ExportName = ExportName; ExportDebug.MethodNumber = 3; ExportDebug.ApiPlatform = API_ALL; ExportDebug.Ordinal = 0; ExportDebug.ArgsSize = -1; if (!AddToExportsList(&ExportDebug)) { ExitErrMsg(FALSE, "ExST: Invalid Line %s\n", Line); } } while (fgets(Line, sizeof(Line) - 1, fp)); if (!feof(fp) && ferror(fp)) { ExitErrMsg(FALSE, "ExST: File Read error: %s\n", FileName); } fclose(fp); return; } /* * ExtractXpt- * * reads the exports from a ".xpt" file and builds the exports list. * An ".xpt" file is simply a list of all of the exports. * */ BOOL ExtractXpt(char *XptListName, char *DllName) { FILE *fp=NULL; BOOL bRet = FALSE; char *pch; char *pSrc=NULL; EXPORTSDEBUG ExportDebug; ULONG MethodNumber = 3; char Line[MAX_PATH]; char ExportName[MAX_PATH]; char ApiName[MAX_PATH]; char Platform[MAX_PATH]; BYTE ApiPlatform; size_t len; DbgPrintf("ExXpt: %s\n", XptListName); fp = fopen(XptListName, "r"); if (!fp) { ErrMsg("ExXpt: fopen(%s) failed\n", XptListName); goto ExSrcExit; } if (fseek(fp, 0, SEEK_SET)) { ErrMsg("ExXpt: fseek failed.\n"); goto ExSrcExit; } if (!fgets(Line, sizeof(Line) - 1, fp)) { if (ferror(fp)) { ErrMsg("ExXpt: Failed to get Defs from %s\n", XptListName); goto ExSrcExit; } else if (feof(fp)) { ErrMsg("ExXpt: Premature EOF %s\n", XptListName); goto ExSrcExit; } } do { // skip leading spaces pSrc = Line; while (*pSrc && isspace(*pSrc)) { pSrc++; } if (!*pSrc) { // line was blank. Reset OLE method stuff for start of new // interface then get the next line. MethodNumber = 3; continue; } if (*pSrc == ';') { // line starts with comment. If the comment indicates the // ole method number, grab that, then ignore the rest of the line. pSrc++; if (*pSrc++ == '*') { MethodNumber = atoi(pSrc); } continue; } // Grab the exported function name len = CopyToken(ApiName, pSrc, sizeof(ApiName)-1); if (len >= sizeof(ApiName) -1) { ErrMsg("ExXpt: ExportName Buffer overflow\n"); } pSrc += len; if (FindInExportsList(ApiName)) { // // Name is already in the Exports list. Ignore the second // one. // DbgPrintf("Warning: API %s was listed more than once in the .xpt. Ignoring subsequent copies.\n", ApiName); continue; } // skip over any whitespace after the export name while (*pSrc && isspace(*pSrc)) { pSrc++; } if (*pSrc == '\0' || *pSrc == ';') { // nothing else interresting on the line. This API is supported // on all platoforms. ApiPlatform = API_ALL; } else { // next non-whitespace is not a comment. This API has an explicit // list of supported platforms. ApiPlatform = API_NONE; do { len = CopyToken(Platform, pSrc, sizeof(Platform)-1); if (_stricmp(Platform, "win95") == 0) { ApiPlatform |= API_WIN95; } else if (_stricmp(Platform, "win98") == 0) { ApiPlatform |= API_WIN98; } else if (_stricmp(Platform, "nt4") == 0) { ApiPlatform |= API_NT4; } else if (_stricmp(Platform, "nt5") == 0) { ApiPlatform |= API_NT5; } else if (_stricmp(Platform, "ntx") == 0) { ApiPlatform |= API_NTx; } else if (_stricmp(Platform, "win9x") == 0) { ApiPlatform |= API_WIN9x; } else { ExitErrMsg(FALSE, "Error: %s(%d) Unknown platform name '%s'.\n", TemplateFileName, TemplateLine, Platform); } pSrc += len; while (*pSrc && isspace(*pSrc)) { pSrc++; } } while (*pSrc && *pSrc != ';'); DbgPrintf("API %s has Platform %x\n", ExportName, ApiPlatform); } memset(&ExportDebug, 0, sizeof(ExportDebug)); ExportDebug.ExportName = ExportName; ExportDebug.MethodNumber = MethodNumber++; ExportDebug.ApiPlatform = ApiPlatform; // // Look up the export in the implib // if (ImplibMappedBase) { int Len; ULONG SymbolMember=0; ULONG ImpNumSymbols = ImplibNumSymbols; PULONG ImpSymbolMember = ImplibSymbolMembers; PCHAR ImpSymbolName = ImplibSymbolNames; while (ImpNumSymbols--) { Len = strlen(ApiName); pch = ImpSymbolName + 1 + Len; if (!strncmp(ApiName, ImpSymbolName + 1, Len) && (!*pch || *pch == '@')) { SymbolMember = EndianSwitch(ImpSymbolMember); break; } ImpSymbolMember++; ImpSymbolName += strlen(ImpSymbolName) + 1; } if (SymbolMember) { if (!InitExportDebug(&ExportDebug, ImpSymbolName, SymbolMember)) { goto ExSrcExit; } } else { // // The export was not found in the implib, and for // flexibility we don't required it to be in implib. // fill up what we know. // ExportDebug.Ordinal = 0; ExportDebug.ArgsSize = -1; strcpy(ExportName, ApiName); } } else { // most info is unknown! ExportDebug.Ordinal = 0; ExportDebug.ArgsSize = -1; strcpy(ExportName, ApiName); } if (!AddToExportsList(&ExportDebug)) { goto ExSrcExit; } } while (fgets(Line, sizeof(Line) - 1, fp)); if (!feof(fp) && ferror(fp)) { ErrMsg("ExXpt: File Read error: %s\n", XptListName); goto ExSrcExit; } bRet = TRUE; ExSrcExit: if (!bRet) { ErrMsg("ExXpt: Invalid Line <%s>\n%s\n", pSrc, Line); } if (fp) { fclose(fp); } return bRet; } BOOL AddToExportsList(PEXPORTSDEBUG pExportsDebug) { PEXPORTSDEBUG pexdbg; int Len; int SizeExportName; SizeExportName = strlen(pExportsDebug->ExportName) + 1; Len = sizeof(EXPORTSDEBUG) + SizeExportName + 1; pexdbg = GenHeapAlloc(Len); if (!pexdbg) { ExitErrMsg(TRUE, "GenHeapAlloc(EXPORTSDEBUG)"); } memset(pexdbg, 0, Len); *pexdbg = *pExportsDebug; pexdbg->ExportName = pexdbg->Buffer; strcpy(pexdbg->ExportName, pExportsDebug->ExportName); InitializeListHead(&pexdbg->ArgsListHead); InsertTailList(&ExportsList, &pexdbg->ExportsDbgEntry); return TRUE; } /* * ExtractPpm. The on-disk .PPM file is opened as read-only, but * the pages are copy-on-write to the pagefile, so genthnk * can make changes to the in-memory version which go away * when it exits. * */ BOOL ExtractPpm(char *PpmName) { HANDLE hFile; HANDLE hMapFile = NULL; PVOID pvBaseAddress; ULONG Version; PVOID MappedBase; ULONG BytesRead; BOOL bSuccess; PCVMHEAPHEADER pHeader; DbgPrintf("PpmName: %s\n", PpmName); hFile = CreateFile(PpmName, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, 0, NULL ); if (hFile == INVALID_HANDLE_VALUE) { hFile = NULL; ErrMsg("ExtractPpm CreateFile(%s) gle %d\n", PpmName, GetLastError()); return FALSE; } bSuccess = ReadFile(hFile, &Version, sizeof(ULONG), &BytesRead, NULL ); if (!bSuccess || BytesRead != sizeof(ULONG)) { ErrMsg("ExtractPpm ReadFile(%s) gle %d\n", PpmName, GetLastError()); return FALSE; } if (Version != VM_TOOL_VERSION) { ErrMsg("ExtractPpm: .PPM version %x does not match genthnk version %x\n", Version, VM_TOOL_VERSION); return FALSE; } #if _WIN64 // Read and ignore the 4-byte padding between the Version and the Base bSuccess = ReadFile(hFile, &Version, sizeof(ULONG), &BytesRead, NULL ); if (!bSuccess || BytesRead != sizeof(ULONG)) { ErrMsg("ExtractPpm ReadFile(%s) gle %d\n", PpmName, GetLastError()); return FALSE; } #endif bSuccess = ReadFile(hFile, &pvBaseAddress, sizeof(ULONG_PTR), &BytesRead, NULL ); if (!bSuccess || BytesRead != sizeof(ULONG_PTR)) { ErrMsg("ExtractPpm ReadFile(%s) gle %d\n", PpmName, GetLastError()); return FALSE; } hMapFile = CreateFileMapping(hFile, NULL, PAGE_WRITECOPY, 0, 0,NULL); if (!hMapFile) { ErrMsg("ExtractPpm CreateFileMapping(%s) gle %d\n", PpmName, GetLastError()); return FALSE; } MappedBase = MapViewOfFileEx(hMapFile, FILE_MAP_COPY, 0, 0, 0, pvBaseAddress); if (!MappedBase || MappedBase != pvBaseAddress) { ErrMsg("ExtractPpm MapViewOfFile(%s) gle %d\n", PpmName, GetLastError()); return FALSE; } pHeader = (PCVMHEAPHEADER)pvBaseAddress; FuncsList = &pHeader->FuncsList; StructsList = &pHeader->StructsList; TypeDefsList = &pHeader->TypeDefsList; NIL = &pHeader->NIL; // This must be done after NIL is initialized. RBInitTree(&FakeFuncsList); return TRUE; } void HandlePreprocessorDirective( char *p ) { ExitErrMsg(FALSE, "Preprocessor directives not allowed: '%s'\n", p); } char * LexMacroArgs( char *pch ) { BOOL fLexDone; char *pchNew; ResetLexer(); pchNew = LexOneLine(pch, FALSE, &fLexDone); CurrentTokenIndex = 0; if (fLexDone) { return pchNew; } else { return pch; } } BOOLEAN ExpandMacro( char *MacroName, PCGENSTATE pCGenState, char **ppIn, char *OutBuffer, SIZE_T MaxLen, SIZE_T *BytesReturned ) /*++ Routine Description: Expands an @MacroName(arg1, arg2, ...). Arguments: MacroName - name of macro to expand pCGenState - current code-gen state ppIn - pointer to pointer to character following '@MacroName' Return Value: TRUE if macro expanded OK, FALSE if not. *ppIn will be updated to point to the character following the end of the macro. --*/ { PTEMPLES pMacroTemple = 0; PLIST_ENTRY NextMacro; char *pIn; PMACROARGSLIST NewMacroArgsList; int ArgCount; NextMacro = MacroList.Flink; while (NextMacro != &MacroList) { pMacroTemple = CONTAINING_RECORD(NextMacro, TEMPLES, TempleEntry); if (strcmp(MacroName, pMacroTemple->Name) == 0) { // // Found a macro by that name // break; } NextMacro = NextMacro->Flink; } if (NextMacro == &MacroList) { // // No macro by that name. // return FALSE; } pIn = *ppIn; ArgCount = pMacroTemple->IndLevel; NewMacroArgsList = GenHeapAlloc(sizeof(MACROARGSLIST) + sizeof(LPSTR) * ArgCount); if (!NewMacroArgsList) { ExitErrMsg(TRUE, "ExpandMacro out of memory"); } NewMacroArgsList->NumArgs = ArgCount; if (!ArgCount) { // // This macro doesn't expect arguments // } else { // // // This macro expects arguments. Parse the arguments. // pIn = ParseMacroArgs(pIn, 0, &NewMacroArgsList); if (NewMacroArgsList->NumArgs != ArgCount) { ExitErrMsg(FALSE, "Macro %s expects %d arguments\n", MacroName, ArgCount); } } // swap out the currently active macro (if any) and swap in the new macro MacroStack[MacroStackTop++] = pCGenState->pMacroArgsList; pCGenState->pMacroArgsList = NewMacroArgsList; // generate code for the Begin=/End= section of the macro if (!pMacroTemple->CodeBurst[BeginCBI]) { ExitErrMsg(FALSE, "%s(%d) Macro %s has no Begin= section: %s\n", TemplateFileName, TemplateLine, MacroName, *ppIn); } CGenerateEx(pMacroTemple->CodeBurst[BeginCBI], pCGenState, OutBuffer, MaxLen, BytesReturned); // swap the previously active macro back in pCGenState->pMacroArgsList = MacroStack[--MacroStackTop]; FreeMacroArgsList(NewMacroArgsList); *ppIn = pIn; return TRUE; } void WriteBoolean ( char *pSrc, BOOL Value ) { if (pSrc){ if ( Value ){ *pSrc++ = '1'; } else{ *pSrc++ = '0'; } *pSrc = '\0'; } } char * ExtractBoolean ( char *expression, BOOLEAN *result ) { char thischar = 0; expression = SkipLeadingWhitespace(expression); *result = FALSE; thischar = *expression; if ( thischar != '\0') { char nextchar =*(expression+1); if ( nextchar != '\0' && nextchar != ')' && nextchar != ',' && !IsWhitespaceCharacter(nextchar)) { ExitErrMsg(FALSE,"%s(%d): Invalid Expression \"%s\"", __FILE__, __LINE__, expression); return expression; } } if (thischar == '0') { *result = FALSE; return expression+1; } else if (thischar == '1') { *result = TRUE; return expression+1; } else{ ExitErrMsg(FALSE,"%s(%d): Invalid Expression \"%s\"", __FILE__, __LINE__, expression); return expression; } } char * ExtractBoolean1( char *pSrc, PCGENSTATE pCGenState, BOOLEAN *result ) /*++ Routine Description: Arguments: Return Value: --*/ { char *pExpression; char *pch; char Buffer[MAX_PATH]; SIZE_T BytesReturned; *result = FALSE; pch = SkipSubExpression(pSrc, &pExpression); if (pSrc == pch) { return pSrc; } pSrc = pch; if (pExpression) { CGenerateEx(pExpression, pCGenState, Buffer, MAX_PATH, &BytesReturned); ExtractBoolean ( Buffer, result ); GenHeapFree(pExpression); } return pSrc; } char * ExtractBoolean2( char *pSrc, PCGENSTATE pCGenState, BOOLEAN *result1, BOOLEAN *result2 ) /*++ Routine Description: Arguments: Return Value: --*/ { char *pExpression; char *pch; char Buffer[MAX_PATH]; SIZE_T BytesReturned; *result1 = FALSE; *result2 = FALSE; pch = SkipSubExpression(pSrc, &pExpression); if (pSrc == pch) { return pSrc; } pSrc = pch; if (pExpression) { CGenerateEx(pExpression, pCGenState, Buffer, MAX_PATH, &BytesReturned); pch = Buffer; pch = ExtractBoolean ( Buffer, result1 ); if ( *pch == ',') { pch++; } else { ExitErrMsg(FALSE,"%s(%d): Invalid Expression \"%s\"", __FILE__, __LINE__, Buffer); } ExtractBoolean ( pch, result2 ); GenHeapFree(pExpression); } return pSrc; } void RestoreTrailingWhitespaceToString(char * s, char * originalEnd) { *(s + strlen(s)) = ' '; } void StripTrailingWhitespaceFromString(char * s) { char * t; char * w = 0; if (s == NULL || *s == 0) return; t = s + strlen(s) - 1; while (t != s && strchr(" \t\r\n", *t) != NULL && (w = t)) { --t; } if (w) *w = 0; } char * SkipLeadingWhitespace(char * s) { return s + strspn(s, " \t\r\n"); } BOOL IsWhitespaceCharacter(char c) { return (strchr(" \t\r\n", c) != NULL); }