diff --git a/Source/ExternalCommands.cpp b/Source/ExternalCommands.cpp new file mode 100644 index 00000000..619d2531 --- /dev/null +++ b/Source/ExternalCommands.cpp @@ -0,0 +1,349 @@ + + +#include "ExternalCommands.h" +#include + + +extern FILE *g_output; + + +struct COFFHeader +{ + unsigned short Machine; + unsigned short NumberOfSections; + unsigned long TimeDateStamp; + unsigned long PointerToSymbolTable; + unsigned long NumberOfSymbols; + unsigned short SizeOfOptionalHeader; + unsigned short Characteristics; +}; +const int COFFHeaderSize = 20; + +struct StandardHeader +{ + unsigned short Magic; + unsigned char MajorLinkerVersion; + unsigned char MinorLinkerVersion; + unsigned long SizeOfCode; + unsigned long SizeOfInitializedData; + unsigned long SizeOfUninitializedData; + unsigned long AddressOfEntryPoint; + unsigned long BaseOfCode; + unsigned long BaseOfData; // PE32+ +}; +const int StandardHeaderSize = 24; +const int StandardHeaderSizePlus = 28; + +struct WindowsSpecificFields +{ + unsigned long ImageBase; + unsigned long SectionAlignment; + unsigned long FileAlignment; + unsigned short MajorOperatingSystemVersion; + unsigned short MinorOperatingSystemVersion; + unsigned short MajorImageVersion; + unsigned short MinorImageVersion; + unsigned short MajorSubsystemVersion; + unsigned short MinorSubsystemVersion; + unsigned long Reserved; + unsigned long SizeOfImage; + unsigned long SizeOfHeaders; + unsigned long CheckSum; + unsigned short Subsystem; + unsigned short DllCharacteristics; + unsigned long SizeOfStackReserve; + unsigned long SizeOfStackCommit; + unsigned long SizeOfHeapReserve; + unsigned long SizeOfHeapCommit; + unsigned long LoaderFlags; // Obsolete + unsigned long NumberOfRvaAndSizes; +}; +struct WindowsSpecificFieldsPlus +{ + unsigned long ImageBase; + unsigned long ImageBasePlus; // PE32+ + unsigned long SectionAlignment; + unsigned long FileAlignment; + unsigned short MajorOperatingSystemVersion; + unsigned short MinorOperatingSystemVersion; + unsigned short MajorImageVersion; + unsigned short MinorImageVersion; + unsigned short MajorSubsystemVersion; + unsigned short MinorSubsystemVersion; + unsigned long Reserved; + unsigned long SizeOfImage; + unsigned long SizeOfHeaders; + unsigned long CheckSum; + unsigned short Subsystem; + unsigned short DllCharacteristics; + unsigned long SizeOfStackReserve; + unsigned long SizeOfStackReservePlus; // PE32+ + unsigned long SizeOfStackCommit; + unsigned long SizeOfStackCommitPlus; // PE32+ + unsigned long SizeOfHeapReserve; + unsigned long SizeOfHeapReservePlus; // PE32+ + unsigned long SizeOfHeapCommit; + unsigned long SizeOfHeapCommitPlus; // PE32+ + unsigned long LoaderFlags; // Obsolete + unsigned long NumberOfRvaAndSizes; +}; +const int WindowsHeaderSize = 68; +const int WindowsHeaderSizePlus = 88; + +struct DataDirectory +{ + unsigned long Rva; + unsigned long Size; +}; +const int DataDirectorySize = 8; + +struct SectionHeader +{ + unsigned char Name[8]; // null terminated ONLY if + unsigned long VirtualSize; // all 8 bytes are NOT used + unsigned long VirtualAddress; + unsigned long SizeOfRawData; + unsigned long PointerToRawData; + unsigned long PointerToRelocations; + unsigned long PointerToLineNumbers; + unsigned short NumberOfRelocations; + unsigned short NumberOfLineNumbers; + unsigned long Characteristics; +}; +const int SectionHeaderSize = 40; + +struct ExportTable +{ + unsigned long ExportFlags; + unsigned long TimeDateStamp; + unsigned short MajorVersion; + unsigned short MinorVersion; + unsigned long NameRVA; + unsigned long OrdinalBase; + unsigned long AddressTableEntries; + unsigned long NumberOfNamePointers; + unsigned long ExportAddressTableRVA; + unsigned long NamePointerRVA; + unsigned long OrdinalTableRVA; +}; + +#define IMAGE_FILE_DLL 0x2000 + +enum +{ + EXPORT, IMPORT, RESOURCE, EXCEPTION, CERTIFICATES, DEBUG, BASERELOCATION, + ARCHITECTURE, SPECIAL, THREADSTORAGE, LOADCONFIG, BOUND, IMPORTADDRESS, + DELAYIMPORT, RESERVED1, RESERVED2 +}; + + +void ExternalCommands::FindCommands(char* path,bool displayInfo) +{ + if (path) + { + int length = strlen(path); + + if (length > 0) + { + WIN32_FIND_DATA data; + HANDLE handle; + char* slashPtr; + + slashPtr = strrchr(path,'\\'); + if (slashPtr && slashPtr-path < length) + length = slashPtr-path; + + slashPtr = strrchr(path,'/'); + if (slashPtr && slashPtr-path < length) + length = slashPtr-path; + + char* basePath = new char [length+1]; + strncpy(basePath,path,length); + basePath[length] = 0; + + char* pathAndWildcard = new char [length+7]; + strcpy(pathAndWildcard,basePath); + strcat(pathAndWildcard,"\\*.dll"); + + handle = FindFirstFile(pathAndWildcard,&data); + if (handle != INVALID_HANDLE_VALUE) + { + do + { + char* dllPath = new char [length+strlen(data.cFileName)+2]; + strcpy(dllPath,basePath); + strcat(dllPath,"\\"); + strcat(dllPath,data.cFileName); + GetExports(dllPath,displayInfo); + delete[] dllPath; + } while (FindNextFile(handle,&data)); + } + + delete[] pathAndWildcard; + delete[] basePath; + } + } +} + +void ExternalCommands::GetExports(char* pathToDll,bool displayInfo) +{ + if (pathToDll) + { + unsigned char* dlldata = 0; + long dlldatalen = 0; + bool loaded = false; + char dllName[100]; + + dllName[0] = 0; + char* ptr = strrchr(pathToDll,'\\'); + if (ptr && *ptr && *(ptr+1)) strcpy(dllName,ptr+1); + + FILE* dll = fopen(pathToDll,"rb"); + if (dll) + { + fseek(dll,0,SEEK_END); + dlldatalen = ftell(dll); + fseek(dll,0,SEEK_SET); + if (dlldatalen > 0) + { + dlldata = new unsigned char [dlldatalen]; + if (dlldata) + { + size_t bytesread = fread((void*)dlldata,1,dlldatalen,dll); + if ((long)bytesread == dlldatalen) + loaded = true; + } + } + fclose(dll); + } + + if (!loaded) + { + if (dlldata) delete[] dlldata; + return; + } + + // read the file offset stored at 0x3c (a single byte) + // then find the pe signature bytes stored at that offset + unsigned char peheaderoffset = dlldata[0x3c]; + unsigned char pesignature[4] = { + dlldata[peheaderoffset+0], + dlldata[peheaderoffset+1], + dlldata[peheaderoffset+2], + dlldata[peheaderoffset+3], + }; + + if (pesignature[0] == 'P' && + pesignature[1] == 'E' && + pesignature[2] == '\0' && + pesignature[3] == '\0') + { + // after the signature comes the COFF header + COFFHeader* coffHeader = (COFFHeader*)&dlldata[peheaderoffset+4]; + + if (coffHeader->Characteristics & IMAGE_FILE_DLL) + { + // after the COFF header comes the Optional Header magic number + // (two bytes) + unsigned char ohmagicnumber[2] = { + dlldata[peheaderoffset+4+COFFHeaderSize+0], + dlldata[peheaderoffset+4+COFFHeaderSize+1] + }; + + // 0x10b means a PE header, but 0x20b means a PE+ header + // not sure if I need to care yet. + if ((ohmagicnumber[0] == 0x0b && + ohmagicnumber[1] == 0x01) || + (ohmagicnumber[0] == 0x0b && + ohmagicnumber[1] == 0x02)) + { + bool plus = (ohmagicnumber[0] == 0x0b && + ohmagicnumber[1] == 0x02); + + if (!plus) + { + const int standardHeaderSize = (plus ? StandardHeaderSizePlus : StandardHeaderSize); + const int windowsHeaderSize = (plus ? WindowsHeaderSizePlus : WindowsHeaderSize); + + int optionalHeaderOffset = peheaderoffset+4+COFFHeaderSize; + StandardHeader* standardHeader = (StandardHeader*)&dlldata[optionalHeaderOffset]; + WindowsSpecificFields* windowsHeader = (WindowsSpecificFields*)&dlldata[optionalHeaderOffset+standardHeaderSize+4]; + DataDirectory* directories = (DataDirectory*)&dlldata[optionalHeaderOffset+standardHeaderSize+windowsHeaderSize+4]; + + DataDirectory* exportHeader = directories; + SectionHeader* sectionTable = + (SectionHeader*) &dlldata[ + peheaderoffset + + 4 + + COFFHeaderSize + + coffHeader->SizeOfOptionalHeader]; + + SectionHeader* section = sectionTable; + for (unsigned long i = 0; i < coffHeader->NumberOfSections; i++) + { + DataDirectory* directory = directories; + for (unsigned long i = 0; i < windowsHeader->NumberOfRvaAndSizes; i++) + { + if (directory->Rva >= section->VirtualAddress && + (directory->Rva+directory->Size) <= (section->VirtualAddress+section->VirtualSize) && + i == EXPORT) + { + unsigned char* ptr = dlldata+section->PointerToRawData; + ExportTable* exports = (ExportTable*)(dlldata+section->PointerToRawData+(directory->Rva-section->VirtualAddress)); + + // find the start of the name table + unsigned long* nameTableEntry = (unsigned long*)(ptr+exports->NamePointerRVA-section->VirtualAddress); + + // walk the name table + for (unsigned long i = 0; i < exports->NumberOfNamePointers; i++) + { + char* namePointer = (char*)(ptr+(*nameTableEntry)-section->VirtualAddress); + m_commands.add(namePointer,pathToDll); + if (displayInfo) + fprintf(g_output," - %s::%s\n",dllName,namePointer); + nameTableEntry++; + } + } + + directory++; + } + + section++; + } + } + } + } + } + + delete[] dlldata; + } +} + +bool ExternalCommands::IsExternalCommand(char* token) +{ + return GetExternalCommandDll(token) ? true : false; +} + +char* ExternalCommands::GetExternalCommandDll(char* command) +{ + return m_commands.find(command); +} + +void ExternalCommands::StoreDllDataHandle(char* command,int handle) +{ + int idx = -1; + m_commands.defines.find(command,0,&idx); + if (idx > -1) + { + m_dataHandles.reserve(idx+1); + m_dataHandles[idx] = handle; + } +} + +int ExternalCommands::GetDllDataHandle(char* command) +{ + int idx = -1; + if (-1 != m_commands.defines.find(command,0,&idx)) + return m_dataHandles[idx]; + return -1; +} \ No newline at end of file diff --git a/Source/ExternalCommands.h b/Source/ExternalCommands.h new file mode 100644 index 00000000..f5d3eaf1 --- /dev/null +++ b/Source/ExternalCommands.h @@ -0,0 +1,30 @@ + + +#ifndef __X18_EXTERNALCOMMANDS_H +#define __X18_EXTERNALCOMMANDS_H + + +#include +#include +#include "strlist.h" +#include + + +class ExternalCommands +{ + public: + void FindCommands(char*,bool); + bool IsExternalCommand(char*); + char* GetExternalCommandDll(char*); + int GetDllDataHandle(char*); + void StoreDllDataHandle(char*,int); + + protected: + DefineList m_commands; + std::vector m_dataHandles; + + void GetExports(char*,bool); +}; + + +#endif \ No newline at end of file diff --git a/Source/build.cpp b/Source/build.cpp index d3d051ac..7a431908 100644 --- a/Source/build.cpp +++ b/Source/build.cpp @@ -352,10 +352,7 @@ int CEXEBuild::preprocess_string(char *out, const char *in) else if (i == '$') { if (*p == '$') - { - i='$'; p++; // Can simply convert $$ to $ now - } else { const char *pVarName; @@ -1824,3 +1821,23 @@ void CEXEBuild::print_warnings() } fflush(g_output); } + +// Added by Ximon Eighteen 5th August 2002 +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT +void CEXEBuild::build_external_command_table(void) +{ + char* nsisdir = definedlist.find("NSISDIR"); + if (nsisdir) + { + char* searchPath = new char [strlen(nsisdir)+12]; + if (searchPath) + { + strcpy(searchPath,nsisdir); + strcat(searchPath,"\\dlls\\*.dll"); + INFO_MSG("\nProcessing plugin dlls: \"%s\"\n",searchPath); + m_externalCommands.FindCommands(searchPath,display_info?true:false); + delete[] searchPath; + } + } +} +#endif // NSIS_CONFIG_PLUGIN_SUPPORT \ No newline at end of file diff --git a/Source/build.h b/Source/build.h index e2dd7a2e..b915fe93 100644 --- a/Source/build.h +++ b/Source/build.h @@ -19,6 +19,10 @@ using namespace std; #endif//NSIS_CONFIG_COMPRESSION_SUPPORT +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT +#include "ExternalCommands.h" +#endif //NSIS_CONFIG_PLUGIN_SUPPORT + #ifdef NSIS_CONFIG_CRC_SUPPORT extern "C" { @@ -46,6 +50,11 @@ class CEXEBuild { // to add a defined thing. void define(const char *p, const char *v=""); +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + // Added by Ximon Eighteen 5th August 2002 + void build_external_command_table(void); +#endif //NSIS_CONFIG_PLUGIN_SUPPORT + // process a script (you can process as many scripts as you want, // it is as if they are concatenated) int process_script(FILE *fp, char *curfilename, int *lineptr); @@ -97,6 +106,11 @@ class CEXEBuild { int make_sure_not_in_secorfunc(const char *str); +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + // Added by Ximon Eighteen 5th August 2002 + ExternalCommands m_externalCommands; +#endif //NSIS_CONFIG_PLUGIN_SUPPORT + // build.cpp functions used mostly within build.cpp int datablock_optimize(int start_offset); void printline(int l); diff --git a/Source/exehead/Main.c b/Source/exehead/Main.c index eb8e2a78..f3077ff8 100644 --- a/Source/exehead/Main.c +++ b/Source/exehead/Main.c @@ -31,9 +31,12 @@ #include "fileform.h" #include "state.h" #include "ui.h" - #include "lang.h" +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT +#include "dllpaths.h" +#endif // NSIS_CONFIG_PLUGIN_SUPPORT + extern unsigned long CRC32(unsigned long crc, const unsigned char *buf, unsigned int len); #if !defined(NSIS_CONFIG_VISIBLE_SUPPORT) && !defined(NSIS_CONFIG_SILENT_SUPPORT) @@ -359,6 +362,11 @@ end: if (dbd_hFile!=INVALID_HANDLE_VALUE) CloseHandle(dbd_hFile); #endif if (m_Err) MessageBox(NULL,m_Err,g_caption,MB_OK|MB_ICONSTOP); + +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + DllPathsCleanup(); +#endif // NSIS_CONFIG_PLUGIN_SUPPORT + ExitProcess(ret); } diff --git a/Source/exehead/config.h b/Source/exehead/config.h index d1763c7c..82e5e253 100644 --- a/Source/exehead/config.h +++ b/Source/exehead/config.h @@ -178,6 +178,29 @@ // NSIS_SUPPORT_MESSAGEBOX enables support for MessageBox #define NSIS_SUPPORT_MESSAGEBOX +// Added by Ximon Eighteen 5th August 2002 +// If this is uncommented the following changes/new features are +// turned on :- +// - At the start of compilation a directory called dlls in +// the directory where makensis.exe is running from will be +// scanned for .dll files. +// - Any functions in the detected dll files that are exported +// by name will be remembered. These names are then legal +// command keywords in an NSIS script. +// - Any command that is unrecognised is checked against the +// list of external dll command names. If matched the dll will +// be packed into the installer. +// - On the installer machine (rather than the build machine) +// on first use of a command that requires a plugin dll that +// dll will be extracted to the temporary directory with a +// temporary file name. +// - Any parameters following the command will be pushed onto +// the stack in left to right order. +// - The command will then be invoked in the dll as if +// "CallInstDLL dll command" had been invoked. +// - When the installer exits any extracted temporary dlls will +// be deleted. +//#define NSIS_CONFIG_PLUGIN_SUPPORT // fixes diff --git a/Source/exehead/dllpaths.c b/Source/exehead/dllpaths.c new file mode 100644 index 00000000..6fd66300 --- /dev/null +++ b/Source/exehead/dllpaths.c @@ -0,0 +1,91 @@ + + +#include "dllpaths.h" +#include +#include "util.h" + + +static int initialised = 0; +static int numPackedPathIds; +static int* packedPathIds; +static char** newPaths; + + +void* DllPathsAlloc(long bytes) +{ + return HeapAlloc( + GetProcessHeap(), + HEAP_ZERO_MEMORY, + bytes); +} + +void DllPathsFree(void* ptr) +{ + HeapFree(GetProcessHeap(),0,ptr); +} + +void DllPathsCleanup(void) +{ + if (initialised) + { + if (packedPathIds) + { + int i; + DllPathsFree(packedPathIds); + for (i = 0; i < numPackedPathIds; i++) + { + DeleteFile(newPaths[i]); + DllPathsFree(newPaths[i]); + } + DllPathsFree(newPaths); + } + + numPackedPathIds = 0; + packedPathIds = 0; + newPaths = 0; + initialised = 0; + } +} + +void DllPathsInitialise(void) +{ + if (!initialised) + { + numPackedPathIds = 0; + packedPathIds = 0; + newPaths = 0; + initialised = 1; + } +} + +void DllPathsAdd(int n,char* path) +{ + DllPathsInitialise(); + if (!DllPathsDetermined(n)) + { + int* newIntArray = (int*)DllPathsAlloc(sizeof(int)*(numPackedPathIds+1)); + char** newCharArray = (char**)DllPathsAlloc(sizeof(char*)*(numPackedPathIds+1)); + mini_memcpy(newIntArray,packedPathIds,numPackedPathIds*sizeof(int)); + mini_memcpy(newCharArray,newPaths,numPackedPathIds*sizeof(char*)); + DllPathsFree(packedPathIds); + DllPathsFree(newPaths); + packedPathIds = newIntArray; + newPaths = newCharArray; + packedPathIds[numPackedPathIds] = n; + newPaths[numPackedPathIds] = (char*)DllPathsAlloc(sizeof(char)*(lstrlen(path)+1)); + lstrcpy(newPaths[numPackedPathIds],path); + numPackedPathIds++; + } +} + +char* DllPathsDetermined(int n) +{ + int i; + DllPathsInitialise(); + for (i = 0; i < numPackedPathIds; i++) + { + if (packedPathIds[i] == n) + return newPaths[i]; + } + return 0; +} diff --git a/Source/exehead/dllpaths.h b/Source/exehead/dllpaths.h new file mode 100644 index 00000000..4ef449fd --- /dev/null +++ b/Source/exehead/dllpaths.h @@ -0,0 +1,13 @@ + + +#ifndef __X18_DLLPATHS_H +#define __X18_DLLPATHS_H + + +void DllPathsCleanup(void); +void DllPathsInitialise(void); +void DllPathsAdd(int,char*); +char* DllPathsDetermined(int); + + +#endif \ No newline at end of file diff --git a/Source/exehead/exec.c b/Source/exehead/exec.c index 4032db41..a6ef631e 100644 --- a/Source/exehead/exec.c +++ b/Source/exehead/exec.c @@ -9,6 +9,10 @@ #include "lang.h" #include "resource.h" +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT +#include "dllpaths.h" +#endif // NSIS_CONFIG_PLUGIN_SUPPORT + #define EXEC_ERROR 0x7FFFFFFF #ifdef NSIS_CONFIG_COMPONENTPAGE @@ -1418,6 +1422,71 @@ static int ExecuteEntry(entry *entries, int pos) } return 0; #endif //NSIS_CONFIG_VISIBLE_SUPPORT +// Added by Ximon Eighteen 5th August 2002 +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + case EW_EXTERNALCOMMANDPREP: + { + // parms[0] - dll name + // parms[1] - function name + // parms[2] - compressed data handle + char* dllPath = DllPathsDetermined(parms[0]); + if (!dllPath) + { + HANDLE hOut; + + if (!GetTempPath(NSIS_MAX_STRLEN,buf2) || + !GetTempFileName(buf2,"nst",0,buf)) + { + exec_errorflag++; + return 0; + } + + hOut = myOpenFile(buf,GENERIC_WRITE,CREATE_ALWAYS); + GetCompressedDataFromDataBlock(parms[2],hOut); + CloseHandle(hOut); + + DllPathsAdd(parms[0],buf); + } + + // leave buf containing the dll path + // and buf2 containing the function name + process_string_fromtab(buf2,parms[1]); + } + return 0; + case EW_EXTERNALCOMMAND: + { + // parms contain command arguments + FARPROC funke; + HANDLE h; + int i; + + // Place the command arguments on the stack, then invoke a CallInstDLL + // command on behalf of the user. Error handling needs improving, this + // won't fail gracefully, instead it could leave the stack in a state + // the user script won't expect. + for (i = 0; parms[i] != -1 && i < MAX_ENTRY_OFFSETS; i++) + { + stack_t* s = (stack_t*)GlobalAlloc(GPTR,sizeof(stack_t)); + process_string_fromtab(s->text,parms[i]); + s->next = g_st; + g_st = s; + } + + h = LoadLibrary(buf); + if (h) + { + funke = GetProcAddress(h,buf2); + if (funke) + { + void (*func)(HWND,int,char*,void*); + func = (void*)funke; + func(g_hwnd,NSIS_MAX_STRLEN,(char*)g_usrvars,(void*)&g_st); + } + FreeLibrary(h); + } + } + return 0; +#endif // NSIS_CONFIG_PLUGIN_SUPPORT } MessageBox(g_hwnd,LANG_INSTCORRUPTED,g_caption,MB_OK|MB_ICONSTOP); return EXEC_ERROR; diff --git a/Source/exehead/exehead-bzip2.dsp b/Source/exehead/exehead-bzip2.dsp index 0009ff2f..16a96ca7 100644 --- a/Source/exehead/exehead-bzip2.dsp +++ b/Source/exehead/exehead-bzip2.dsp @@ -40,7 +40,7 @@ RSC=rc.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O1 /Oy /D "_WINDOWS" /D "EXEHEAD" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN" /D "NSIS_COMPRESS_USE_BZIP2" /FD /c -# SUBTRACT CPP /YX /Yc /Yu +# SUBTRACT CPP /Fr /YX /Yc /Yu # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -152,6 +152,10 @@ SOURCE=..\crc32.c # End Source File # Begin Source File +SOURCE=.\dllpaths.c +# End Source File +# Begin Source File + SOURCE=.\exec.c # End Source File # Begin Source File @@ -180,6 +184,10 @@ SOURCE=.\config.h # End Source File # Begin Source File +SOURCE=.\dllpaths.h +# End Source File +# Begin Source File + SOURCE=.\exec.h # End Source File # Begin Source File diff --git a/Source/exehead/exehead-zlib.dsp b/Source/exehead/exehead-zlib.dsp index 2dd7e7af..2ba2bed0 100644 --- a/Source/exehead/exehead-zlib.dsp +++ b/Source/exehead/exehead-zlib.dsp @@ -40,7 +40,7 @@ RSC=rc.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_WINDOWS" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O1 /Oy /D "_WINDOWS" /D "EXEHEAD" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN" /D "NSIS_COMPRESS_USE_ZLIB" /FD /c -# SUBTRACT CPP /YX /Yc /Yu +# SUBTRACT CPP /Fr /YX /Yc /Yu # ADD BASE MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD MTL /nologo /D "NDEBUG" /mktyplib203 /win32 # ADD BASE RSC /l 0x409 /d "NDEBUG" @@ -152,6 +152,10 @@ SOURCE=..\crc32.c # End Source File # Begin Source File +SOURCE=.\dllpaths.c +# End Source File +# Begin Source File + SOURCE=.\exec.c # End Source File # Begin Source File diff --git a/Source/exehead/fileform.h b/Source/exehead/fileform.h index 7e00590d..1f40474a 100644 --- a/Source/exehead/fileform.h +++ b/Source/exehead/fileform.h @@ -122,6 +122,8 @@ enum EW_GETLABELADDR, // both of these get converted to EW_ASSIGNVAR EW_GETFUNCTIONADDR, + EW_EXTERNALCOMMANDPREP, + EW_EXTERNALCOMMAND }; diff --git a/Source/makenssi.cpp b/Source/makenssi.cpp index b70bac1f..71c3e10e 100644 --- a/Source/makenssi.cpp +++ b/Source/makenssi.cpp @@ -109,9 +109,13 @@ int main(int argc, char **argv) } atexit(myatexit); - signal(SIGINT,sigint); +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + // Added by Ximon Eighteen 5th August 2002 + build.build_external_command_table(); +#endif //NSIS_CONFIG_PLUGIN_SUPPORT + if (!g_output) g_output=stdout; while (argpos < argc) { diff --git a/Source/makenssi.dsp b/Source/makenssi.dsp index 8976889a..b0e382b5 100644 --- a/Source/makenssi.dsp +++ b/Source/makenssi.dsp @@ -39,7 +39,7 @@ RSC=rc.exe # PROP Target_Dir "" # ADD BASE CPP /nologo /W3 /GX /O2 /D "WIN32" /D "NDEBUG" /D "_CONSOLE" /D "_MBCS" /YX /FD /c # ADD CPP /nologo /W3 /GX /O2 /Ob2 /D "_CONSOLE" /D "WIN32" /D "NDEBUG" /D "_MBCS" /D "WIN32_LEAN_AND_MEAN" /FD /c -# SUBTRACT CPP /YX /Yc /Yu +# SUBTRACT CPP /Fr /YX /Yc /Yu # ADD BASE RSC /l 0x409 /d "NDEBUG" # ADD RSC /l 0x409 /d "NDEBUG" BSC32=bscmake.exe @@ -152,6 +152,10 @@ SOURCE=.\exedata.cpp # End Source File # Begin Source File +SOURCE=.\ExternalCommands.cpp +# End Source File +# Begin Source File + SOURCE=.\lang.cpp # End Source File # Begin Source File @@ -208,6 +212,10 @@ SOURCE=.\exedata.h # End Source File # Begin Source File +SOURCE=.\ExternalCommands.h +# End Source File +# Begin Source File + SOURCE=.\lang.h # End Source File # Begin Source File diff --git a/Source/script.cpp b/Source/script.cpp index 36f65274..74c44e8f 100644 --- a/Source/script.cpp +++ b/Source/script.cpp @@ -92,8 +92,23 @@ parse_again: line.eattoken(); goto parse_again; } - ERROR_MSG("Invalid command: %s\n",line.gettoken_str(0)); - return PS_ERROR; + +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + // Added by Ximon Eighteen 5th August 2002 + // We didn't recognise this command, could it be the name of a + // function exported from a dll? + if (m_externalCommands.IsExternalCommand(line.gettoken_str(0))) + { + np = 0; // parameters are optional + op = -1; // unlimited number of optional parameters + tkid = TOK__EXTERNALCOMMAND; + } + else +#endif + { + ERROR_MSG("Invalid command: %s\n",line.gettoken_str(0)); + return PS_ERROR; + } } int v=line.getnumtokens()-(np+1); @@ -290,6 +305,7 @@ int CEXEBuild::parseScript(FILE *fp, const char *curfilename, int *lineptr, int int ret=doParse((char*)linedata.get(),fp,curfilename,lineptr,ignore); if (ret != PS_OK) return ret; } + return PS_EOF; } @@ -3173,6 +3189,65 @@ int CEXEBuild::doCommand(int which_token, LineParser &line, FILE *fp, const char // end of instructions /////////////////////////////////////////////////////////////////////////////// + // Added by Ximon Eighteen 5th August 2002 + case TOK__EXTERNALCOMMAND: +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + { + if (line.getnumtokens()-1 > MAX_ENTRY_OFFSETS) + { + ERROR_MSG("Error: Too many arguments (%d max) to command %s!\n",MAX_ENTRY_OFFSETS,line.gettoken_str(0)); + return PS_ERROR; + } + + char* dllPath = m_externalCommands.GetExternalCommandDll(line.gettoken_str(0)); + if (dllPath) + { + int dataHandle = m_externalCommands.GetDllDataHandle(dllPath); + if (dataHandle == -1) + { + int error; + if (PS_OK != (error = do_add_file(dllPath,0,0,-1,&dataHandle,0))) + { + ERROR_MSG("Error: Failed to auto include plugin file \"%s\"\n",dllPath); + return error; + } + + m_externalCommands.StoreDllDataHandle(line.gettoken_str(0),dataHandle); + } + + // Create the runtime command to execute the custom instruction + ent.which = EW_EXTERNALCOMMANDPREP; + ent.offsets[0] = add_string(dllPath); + ent.offsets[1] = add_string(line.gettoken_str(0)); + ent.offsets[2] = dataHandle; + add_entry(&ent); + + SCRIPT_MSG("Plugin Command: %s",line.gettoken_str(0)); + ent.which = EW_EXTERNALCOMMAND; + + for (int i = 0; i < MAX_ENTRY_OFFSETS && i+1 < line.getnumtokens(); i++) + { + ent.offsets[i] = add_string(line.gettoken_str(i+1)); + SCRIPT_MSG(" %s",line.gettoken_str(i+1)); + } + SCRIPT_MSG("\n"); + + // since the runtime code won't know how many arguments to expect (why + // should it, an arbitrary command is being executed so it has no way + // of knowing) if it's less than the max + if (i < MAX_ENTRY_OFFSETS) + ent.offsets[i] = -1; + + return add_entry(&ent); + } + ERROR_MSG("Error: Plugin dll for command \"%s\" not found.\n",line.gettoken_str(0)); + return PS_ERROR; + } +#else + ERROR_MSG("Error: %s specified, NSIS_CONFIG_PLUGIN_SUPPORT not defined.\n",line.gettoken_str(0)); + return PS_ERROR; +#endif// NSIS_CONFIG_PLUGIN_SUPPORT + default: break; } @@ -3180,6 +3255,9 @@ int CEXEBuild::doCommand(int which_token, LineParser &line, FILE *fp, const char return PS_ERROR; } +// If linecnt == -1 no decompress command will be created in the installer, +// instead some action during execution of the installer should cause the file +// to be decompressed manually - Ximon Eighteen 5th August 2002 int CEXEBuild::do_add_file(const char *lgss, int attrib, int recurse, int linecnt, int *total_files, const char *name_override) { char dir[1024]; @@ -3235,7 +3313,7 @@ int CEXEBuild::do_add_file(const char *lgss, int attrib, int recurse, int linecn ent.offsets[0]=add_string(cur_out_path); ent.offsets[1]=1; a=add_entry(&ent); - if (a != PS_OK) + if (a != PS_OK) { FindClose(h); return a; @@ -3312,11 +3390,14 @@ int CEXEBuild::do_add_file(const char *lgss, int attrib, int recurse, int linecn section_add_size_kb((len+1023)/1024); if (name_override) SCRIPT_MSG("File: \"%s\"->\"%s\"",d.cFileName,name_override); +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + else if (linecnt == -1) SCRIPT_MSG("File: Auto included \"%s\"",d.cFileName); +#endif // NSIS_CONFIG_PLUGIN_SUPPORT else SCRIPT_MSG("File: \"%s\"",d.cFileName); if (!build_compress_whole) if (build_compress) SCRIPT_MSG(" [compress]"); fflush(stdout); - char buf[1024]; + char buf[1024]; int last_build_datablock_used=getcurdbsize(); entry ent={0,}; ent.which=EW_EXTRACTFILE; @@ -3379,11 +3460,24 @@ int CEXEBuild::do_add_file(const char *lgss, int attrib, int recurse, int linecn else m_inst_fileused++; CloseHandle(hFile); - int a=add_entry(&ent); - if (a != PS_OK) + + int a; + // Only insert a EW_EXTRACTFILE command into the installer for this + // file if linecnt is NOT -1. This has nothing to do with line counts + // - linecnt was just a handy value to use since this function doesn't + // appear to be using it anywhere else for anything :-) +#ifdef NSIS_CONFIG_PLUGIN_SUPPORT + if (-1 == linecnt) + *total_files = ent.offsets[2]; + else +#endif //NSIS_CONFIG_PLUGIN_SUPPORT { - FindClose(h); - return a; + a=add_entry(&ent); + if (a != PS_OK) + { + FindClose(h); + return a; + } } if (attrib) { @@ -3413,4 +3507,3 @@ int CEXEBuild::do_add_file(const char *lgss, int attrib, int recurse, int linecn } return PS_OK; } - diff --git a/Source/tokens.h b/Source/tokens.h index 2ec359ea..7aa5043f 100644 --- a/Source/tokens.h +++ b/Source/tokens.h @@ -187,7 +187,8 @@ enum TOK_SETSHELLVARCONTEXT, - TOK__LAST + TOK__LAST, + TOK__EXTERNALCOMMAND }; #endif//_TOKENS_H_ \ No newline at end of file