Subversion Repositories filter_foundry

Rev

Rev 508 | Rev 510 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.     This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
  3.     Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
  4.     Copyright (C) 2018-2022 Daniel Marschall, ViaThinkSoft
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19. */
  20.  
  21. #include "ff.h"
  22.  
  23. #include <time.h>
  24.  
  25. #include "file_compat.h"
  26. #include "compat_string.h"
  27. #include "compat_win.h"
  28. #include "versioninfo_modify_win.h"
  29. #include "version.h"
  30.  
  31. extern HINSTANCE hDllInstance;
  32.  
  33. typedef struct _PE32 {
  34.         uint32_t magic; // 0x50450000
  35.         IMAGE_FILE_HEADER fileHeader; // COFF Header without Signature
  36.         IMAGE_OPTIONAL_HEADER32 optHeader; // Standard COFF fields, Windows Specific Fields, Data Directories
  37. } PE32;
  38.  
  39. Boolean doresources(FSSpec* dst, int bits);
  40.  
  41. void showLastError(TCHAR *func){
  42.         TCHAR s[0x300] = {0};
  43.  
  44.         xstrcpy(&s[0],func);
  45.         xstrcat(&s[0],TEXT(" failed: ")); // TODO (Not so important): TRANSLATE
  46.         FormatMessage(FORMAT_MESSAGE_FROM_SYSTEM, NULL, GetLastError(), 0, s + xstrlen(s), 0x300 - (DWORD)xstrlen(s), NULL);
  47.         simplealert(&s[0]);
  48. }
  49.  
  50. /*
  51. BOOL CALLBACK enumfunc(HMODULE hModule,LPCTSTR lpszType,LPCTSTR lpszName,WORD wIDLanguage,LONG lParam){
  52.         #ifdef DEBUG
  53.         char s[0x100];
  54.         sprintf(s,"EnumResourceLanguages callback: module=%#x type=%s name=%s lang=%d",
  55.                 hModule,lpszType,lpszName,wIDLanguage);
  56.         dbg(s);
  57.         #endif
  58.         return TRUE;
  59. }
  60. */
  61.  
  62. int WriteXmlEscaped(char* description, char c) {
  63.         int idescription = 0;
  64.         if (c == '&') {
  65.                 description[idescription++] = '&';
  66.                 description[idescription++] = 'a';
  67.                 description[idescription++] = 'm';
  68.                 description[idescription++] = 'p';
  69.                 description[idescription++] = ';';
  70.         }
  71.         else if (c == '<') {
  72.                 description[idescription++] = '&';
  73.                 description[idescription++] = 'l';
  74.                 description[idescription++] = 't';
  75.                 description[idescription++] = ';';
  76.         }
  77.         else if (c == '>') {
  78.                 description[idescription++] = '&';
  79.                 description[idescription++] = 'g';
  80.                 description[idescription++] = 't';
  81.                 description[idescription++] = ';';
  82.         }
  83.         else {
  84.                 description[idescription++] = c;
  85.         }
  86.         return idescription;
  87. }
  88.  
  89. int domanifest(char *newmanifest, char *manifestp, PARM_T* pparm, int bits) {
  90.         char* name;
  91.         char* description, *tmpDescription;
  92.         int res;
  93.         size_t i;
  94.         size_t iname;
  95.  
  96.         name = (char*)malloc(40 + (2 * 256) * 5);
  97.         description = (char*)malloc(10 + (2 * 256)); // x4 because & becomes &amp;
  98.         if (name == NULL || description == NULL) return 0;
  99.        
  100.         // Description
  101.         tmpDescription = description;
  102.         for (i = 0; i < strlen(pparm->szCategory); i++) {
  103.                 char c = pparm->szCategory[i];
  104.                 tmpDescription += WriteXmlEscaped(tmpDescription, c);
  105.         }
  106.         tmpDescription += WriteXmlEscaped(tmpDescription, ' ');
  107.         tmpDescription += WriteXmlEscaped(tmpDescription, '-');
  108.         tmpDescription += WriteXmlEscaped(tmpDescription, ' ');
  109.         for (i = 0; i < strlen(pparm->szTitle); i++) {
  110.                 char c = pparm->szTitle[i];
  111.                 tmpDescription += WriteXmlEscaped(tmpDescription, c);
  112.         }
  113.         tmpDescription[0] = '\0';
  114.  
  115.         // Name
  116.         strcpy(name, "Telegraphics.FilterFoundry.");
  117.         iname = strlen("Telegraphics.FilterFoundry.");
  118.         for (i = 0; i < strlen(pparm->szCategory); i++) {
  119.                 char c = pparm->szCategory[i];
  120.                 if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9'))) {
  121.                         name[iname++] = c;
  122.                 }
  123.         }
  124.         name[iname++] = '.';
  125.         for (i = 0; i < strlen(pparm->szTitle); i++) {
  126.                 char c = pparm->szTitle[i];
  127.                 if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z')) || ((c >= '0') && (c <= '9'))) {
  128.                         name[iname++] = c;
  129.                 }
  130.         }
  131.         name[iname++] = '\0';
  132.  
  133.         if (bits == 64) {
  134.                 res = sprintf(newmanifest, manifestp, (char*)name, "amd64", VERSION_STR, (char*)description);
  135.         }
  136.         else {
  137.                 res = sprintf(newmanifest, manifestp, (char*)name, "x86", VERSION_STR, (char*)description);
  138.         }
  139.  
  140.         free(name);
  141.         free(description);
  142.  
  143.         return res;
  144. }
  145.  
  146. ULONG changeVersionInfo(FSSpec* dst, HANDLE hUpdate, PARM_T* pparm, int bits) {
  147.         LPTSTR soleFilename;
  148.         LPWSTR changeRequestStrW, tmp;
  149.         ULONG dwError = NOERROR;
  150.         HRSRC hResInfo;
  151.         HGLOBAL hg;
  152.         ULONG size;
  153.         PVOID pv;
  154.         //BOOL fDiscard = TRUE;
  155.  
  156.         if (soleFilename = xstrrchr(&dst->szName[0], '\\')) {
  157.                 ++soleFilename;
  158.         }
  159.         else {
  160.                 soleFilename = &dst->szName[0];
  161.         }
  162.  
  163.         // Format of argument "PCWSTR changes" is "<name>\0<value>\0<name>\0<value>\0....."
  164.         // You can CHANGE values for any given name
  165.         // You can DELETE entries by setting the value to "\b" (0x08 backspace character)
  166.         // You cannot (yet) ADD entries.
  167.         changeRequestStrW = (LPWSTR)malloc((6 * 2 * 100 + 1) * sizeof(WCHAR));
  168.         if (changeRequestStrW == 0) return E_OUTOFMEMORY;
  169.         memset((char*)changeRequestStrW, 0, sizeof(changeRequestStrW));
  170.  
  171.         tmp = changeRequestStrW;
  172.  
  173.         tmp += mbstowcs(tmp, "Comments", 100);
  174.         tmp++;
  175.         tmp += mbstowcs(tmp, "Built using Filter Foundry " VERSION_STR, 100);
  176.         tmp++;
  177.  
  178.         tmp += mbstowcs(tmp, "CompanyName", 100);
  179.         tmp++;
  180.         if (strlen(pparm->szAuthor) > 0) {
  181.                 tmp += mbstowcs(tmp, pparm->szAuthor, 100);
  182.         }
  183.         else {
  184.                 tmp += mbstowcs(tmp, "\b", 100); // \b = remove
  185.         }
  186.         tmp++;
  187.  
  188.         tmp += mbstowcs(tmp, "LegalCopyright", 100);
  189.         tmp++;
  190.         if (strlen(pparm->szCopyright) > 0) {
  191.                 tmp += mbstowcs(tmp, pparm->szCopyright, 100);
  192.         }
  193.         else {
  194.                 tmp += mbstowcs(tmp, "\b", 100); // \b = remove
  195.         }
  196.         tmp++;
  197.  
  198.         tmp += mbstowcs(tmp, "FileDescription", 100);
  199.         tmp++;
  200.         if (strlen(pparm->szTitle) > 0) {
  201.                 tmp += mbstowcs(tmp, pparm->szTitle, 100);
  202.         }
  203.         else {
  204.                 tmp += mbstowcs(tmp, "Untitled filter", 100);
  205.         }
  206.         tmp++;
  207.  
  208.         tmp += mbstowcs(tmp, "OriginalFilename", 100);
  209.         tmp++;
  210.         #ifdef UNICODE
  211.         xstrcpy(tmp, soleFilename);
  212.         tmp += xstrlen(soleFilename);
  213.         #else
  214.         tmp += mbstowcs(tmp, soleFilename, 100);
  215.         #endif
  216.         tmp++;
  217.  
  218.         tmp += mbstowcs(tmp, "License", 100);
  219.         tmp++;
  220.         tmp += mbstowcs(tmp, "\b", 100); // \b = remove, since filter is standalone and might have its own license
  221.         tmp++;
  222.  
  223.         tmp += mbstowcs(tmp, "", 1);
  224.  
  225.         if (hResInfo = FindResourceEx(hDllInstance, TEXT("TPLT"), MAKEINTRESOURCE(3000 + bits), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US)))
  226.         {
  227.                 if (hg = LoadResource(hDllInstance, hResInfo))
  228.                 {
  229.                         if (size = SizeofResource(hDllInstance, hResInfo))
  230.                         {
  231.                                 if (pv = LockResource(hg))
  232.                                 {
  233.                                         if (UpdateVersionRaw(pv, size, &pv, &size, changeRequestStrW))
  234.                                         {
  235.                                                 if (_UpdateResource(hUpdate, RT_VERSION, MAKEINTRESOURCE(1), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), pv, size))
  236.                                                 {
  237.                                                         //fDiscard = FALSE;
  238.                                                 }
  239.                                                 else {
  240.                                                         //dwError = GetLastError();
  241.                                                 }
  242.                                         }
  243.                                         LocalFree(pv);
  244.                                 }
  245.                         }
  246.                 }
  247.         }
  248.  
  249.         free(changeRequestStrW);
  250.  
  251.         return dwError;
  252. }
  253.  
  254. typedef long                          __time32_t;
  255.  
  256. Boolean update_pe_timestamp(const FSSpec* dst, __time32_t timestamp) {
  257.         size_t peoffset;
  258.         FILEREF fptr;
  259.         Boolean res;
  260.         FILECOUNT cnt;
  261.  
  262.         if (FSpOpenDF(dst, fsRdWrPerm, &fptr) != noErr) return false;
  263.  
  264.         res =
  265.                 SetFPos(fptr, fsFromStart, 0x3C) ||
  266.                 (cnt = sizeof(peoffset), noErr) ||
  267.                 FSRead(fptr, &cnt, &peoffset) ||
  268.                 SetFPos(fptr, fsFromStart, (long)peoffset + /*0x0008*/offsetof(PE32, fileHeader.TimeDateStamp)) ||
  269.                 (cnt = sizeof(__time32_t), noErr) ||
  270.                 FSWrite(fptr, &cnt, &timestamp);
  271.  
  272.         FSClose(fptr);
  273.  
  274.         return res == noErr; // res=0 means everything was noErr, res=1 means something was !=noErr
  275. }
  276.  
  277. int binary_replace_file(FSSpec* dst, uint64_t search, uint64_t replace, Boolean align, int maxamount) {
  278.         uint64_t srecord = 0;
  279.         int found = 0;
  280.         FILEREF fptr;
  281.         FILECOUNT cnt;
  282.  
  283.         if (FSpOpenDF(dst, fsRdWrPerm, &fptr) != noErr) return -1;
  284.  
  285.         cnt = sizeof(srecord);
  286.         while (FSRead(fptr, &cnt, &srecord) == noErr)
  287.         {
  288.                 if (cnt != sizeof(srecord)) break; // EOF reached
  289.                 if (srecord == search) {
  290.                         srecord = replace;
  291.                         SetFPos(fptr, fsFromMark, -1 * (long)sizeof(srecord));
  292.                         cnt = (int)sizeof(srecord);
  293.                         FSWrite(fptr, &cnt, &srecord);
  294.                         SetFPos(fptr, fsFromStart, 0); // important for fseek
  295.                         found++;
  296.                         if (found == maxamount) break;
  297.                 }
  298.                 else {
  299.                         if (!align) {
  300.                                 SetFPos(fptr, fsFromMark, -1 * (long)(sizeof(srecord) - 1));
  301.                         }
  302.                 }
  303.         }
  304.         FSClose(fptr);
  305.  
  306.         return found;
  307. }
  308.  
  309. uint32_t calculate_checksum(FSSpec* dst) {
  310.         //Calculate checksum of image
  311.         // Taken from "PE Bliss" Cross-Platform Portable Executable C++ Library
  312.         // https://github.com/mrexodia/portable-executable-library/blob/master/pe_lib/pe_checksum.cpp
  313.         // Converted from C++ to C by Daniel Marschall
  314.  
  315.         FILEREF fptr;
  316.         unsigned long long checksum = 0;
  317.         IMAGE_DOS_HEADER header;
  318.         FILEPOS filesize, i;
  319.         unsigned long long top;
  320.         unsigned long pe_checksum_pos;
  321.         static const unsigned long checksum_pos_in_optional_headers = 64;
  322.         FILECOUNT cnt;
  323.  
  324.         if (FSpOpenDF(dst, fsRdWrPerm, &fptr) != noErr) return 0x00000000;
  325.  
  326.         //Read DOS header
  327.         SetFPos(fptr, fsFromStart, 0);
  328.         cnt = sizeof(IMAGE_DOS_HEADER);
  329.         FSRead(fptr, &cnt, &header);
  330.  
  331.         //Calculate PE checksum
  332.         SetFPos(fptr, fsFromStart, 0);
  333.         top = 0xFFFFFFFF;
  334.         top++;
  335.  
  336.         //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+
  337.         //Calculate real PE headers "CheckSum" field position
  338.         //Sum is safe here
  339.         pe_checksum_pos = header.e_lfanew + sizeof(IMAGE_FILE_HEADER) + sizeof(uint32_t) + checksum_pos_in_optional_headers;
  340.  
  341.         //Calculate checksum for each byte of file
  342.         filesize = 0;
  343.         GetEOF(fptr, &filesize);
  344.         SetFPos(fptr, fsFromStart, 0);
  345.         for (i = 0; i < filesize; i += 4)
  346.         {
  347.                 unsigned long dw = 0;
  348.  
  349.                 //Read DWORD from file
  350.                 cnt = sizeof(dw);
  351.                 FSRead(fptr, &cnt, &dw);
  352.                 //Skip "CheckSum" DWORD
  353.                 if (i == pe_checksum_pos)
  354.                         continue;
  355.  
  356.                 //Calculate checksum
  357.                 checksum = (checksum & 0xffffffff) + dw + (checksum >> 32);
  358.                 if (checksum > top)
  359.                         checksum = (checksum & 0xffffffff) + (checksum >> 32);
  360.         }
  361.  
  362.         //Finish checksum
  363.         checksum = (checksum & 0xffff) + (checksum >> 16);
  364.         checksum = (checksum)+(checksum >> 16);
  365.         checksum = checksum & 0xffff;
  366.  
  367.         checksum += (unsigned long)(filesize);
  368.  
  369.         FSClose(fptr);
  370.  
  371.         //Return checksum
  372.         return (uint32_t)checksum;
  373. }
  374.  
  375. Boolean repair_pe_checksum(FSSpec* dst) {
  376.         size_t peoffset;
  377.         FILEREF fptr;
  378.         FILECOUNT cnt;
  379.         Boolean res;
  380.  
  381.         uint32_t checksum = calculate_checksum(dst);
  382.         //if (checksum == 0x00000000) return false;
  383.  
  384.         if (FSpOpenDF(dst, fsRdWrPerm, &fptr) != noErr) return false;
  385.  
  386.         res =
  387.                 SetFPos(fptr, fsFromStart, 0x3C) ||
  388.                 (cnt = sizeof(peoffset), noErr) ||
  389.                 FSRead(fptr, &cnt, &peoffset) ||
  390.                 SetFPos(fptr, fsFromStart, (long)peoffset + /*0x0058*/offsetof(PE32, optHeader.CheckSum)) ||
  391.                 (cnt = sizeof(uint32_t), noErr) ||
  392.                 FSWrite(fptr, &cnt, &checksum);
  393.  
  394.         FSClose(fptr);
  395.  
  396.         return res == noErr; // res=0 means everything was noErr, res=1 means something was !=noErr
  397. }
  398.  
  399. typedef struct {
  400.         char funcname[8];
  401.         uint16_t codelen;
  402. } operdef_t;
  403.  
  404. typedef struct {
  405.         char funcname[8];
  406.         uint16_t numparams;
  407. } funcdef_t;
  408.  
  409. typedef struct {
  410.         char funcname[8];
  411.         char referencename[8];
  412. } symndef_t;
  413.  
  414. Boolean doresources(FSSpec* dst, int bits){
  415.         HRSRC datarsrc,aetersrc,manifestsrc;
  416.         HGLOBAL datah,aeteh,hupdate,manifesth;
  417.  
  418.         operdef_t dummy_oper;
  419.         funcdef_t dummy_func;
  420.         symndef_t dummy_symn;
  421.  
  422.         Ptr newpipl = NULL, newaete = NULL;
  423.         LPVOID datap, aetep, manifestp;
  424.         char* manifestp_copy;
  425.         PARM_T *pparm = NULL;
  426.         size_t piplsize,aetesize,origsize;
  427.         char title[256];
  428.         LPCTSTR parm_type;
  429.         LPCTSTR parm_id;
  430.         Boolean discard = true;
  431.         uint64_t obfuscseed = 0, obfuscseed2 = 0;
  432.         long event_id;
  433.  
  434.         memset(&dummy_oper, 0, sizeof(operdef_t));
  435.         memset(&dummy_func, 0, sizeof(funcdef_t));
  436.         memset(&dummy_symn, 0, sizeof(symndef_t));
  437.  
  438.         if( (hupdate = _BeginUpdateResource(&dst->szName[0],false)) ){
  439.                 if( (datarsrc = FindResource(hDllInstance,MAKEINTRESOURCE(16000 + bits), TEXT("TPLT")))
  440.                         && (datah = LoadResource(hDllInstance,datarsrc))
  441.                         && (datap = (Ptr)LockResource(datah))
  442.                         && (aetersrc = FindResource(hDllInstance, MAKEINTRESOURCE(16000), TEXT("AETE")))
  443.                         && (aeteh = LoadResource(hDllInstance, aetersrc))
  444.                         && (aetep = (Ptr)LockResource(aeteh))
  445.                         && (manifestsrc = FindResource(hDllInstance, MAKEINTRESOURCE(1), TEXT("TPLT")))
  446.                         && (manifesth = LoadResource(hDllInstance, manifestsrc))
  447.                         && (manifestp = (Ptr)LockResource(manifesth)) )
  448.                 {
  449.                         char* newmanifest;
  450.                         int manifestsize = SizeofResource(hDllInstance, manifestsrc);
  451.  
  452.                         newmanifest = (char*)malloc((size_t)manifestsize + 4096/*+4KiB for name,description,etc.*/);
  453.  
  454.                         strcpy(title,gdata->parm.szTitle);
  455.                         if(gdata->parm.popDialog)
  456.                                 strcat(title,"...");
  457.  
  458.                         origsize = SizeofResource(hDllInstance,datarsrc);
  459.  
  460.                         if( (newpipl = (Ptr)malloc(origsize+0x300))
  461.                          && (newaete = (Ptr)malloc(4096))
  462.                          && (pparm = (PARM_T*)malloc(sizeof(PARM_T))) )
  463.                         {
  464.                                 // ====== Generate AETE and PIPL
  465.  
  466.                                 /* add user-specified title and category to new PiPL */
  467.                                 memcpy(newpipl,datap,origsize);
  468.                                 /* note that Windows PiPLs have 2 byte version datum in front
  469.                                    that isn't reflected in struct definition or Mac resource template: */
  470.                                 piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,&title[0], &event_id) + 2;
  471.  
  472.                                 /* set up the PARM resource with saved parameters */
  473.                                 memcpy(pparm,&gdata->parm,sizeof(PARM_T));
  474.  
  475.                                 /* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
  476.                                 aetesize = aete_generate(newaete, pparm, event_id);
  477.  
  478.                                 // ====== Create fitting manifest for the activation context
  479.  
  480.                                 manifestp_copy = (char*)malloc((size_t)manifestsize + 1/*sz*/);
  481.                                 if (manifestp_copy != 0) {
  482.                                         memcpy(manifestp_copy, manifestp, manifestsize); // copy manifestp to manifestp_copy, because manifestp is readonly
  483.                                         manifestp_copy[manifestsize] = '\0'; // and add the null-terminating char, because domanifest() uses sprintf() on it
  484.                                         manifestsize = domanifest(newmanifest, manifestp_copy, pparm, bits);
  485.                                         free(manifestp_copy);
  486.                                 }
  487.  
  488.                                 // ====== Change version attributes
  489.  
  490.                                 if (changeVersionInfo(dst, hupdate, pparm, bits) != NOERROR) {
  491.                                         simplewarning((TCHAR*)TEXT("changeVersionInfo failed")); // TODO (Not so important): TRANSLATE
  492.                                 }
  493.  
  494.                                 // ====== Obfuscate pparm!
  495.  
  496.                                 if (gdata->obfusc) {
  497.                                         parm_type = OBFUSCDATA_TYPE_NEW;
  498.                                         parm_id = OBFUSCDATA_ID_NEW;
  499.  
  500.                                         // Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
  501.                                         obfusc(pparm, &obfuscseed, &obfuscseed2);
  502.                                 }else{
  503.                                         parm_type = PARM_TYPE;
  504.                                         parm_id = PARM_ID_NEW;
  505.                                 }
  506.  
  507.                                 // ====== Save AETE, PIPL, Manifest and PARM/RCDATA
  508.  
  509.                                 /* Attention: The resource we have found using FindResource() might have a different
  510.                                    language than the resource we are saving (Neutral), so we might end up having
  511.                                    multiple languages for the same resource. Therefore, the language "Neutral" was
  512.                                    set in the Scripting.rc file for the resource AETE and PIPL.rc for the resources PIPL. */
  513.  
  514.                                 if(
  515.                                            _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_BUILDDLG), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL, 0) // clean up things we don't need in the standalone plugin
  516.                                         && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_BUILDDLG), MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), NULL, 0) // clean up things we don't need in the standalone plugin
  517.                                         && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_MAINDLG), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL, 0) // clean up things we don't need in the standalone plugin
  518.                                         && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_MAINDLG), MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), NULL, 0) // clean up things we don't need in the standalone plugin
  519.                                         && _UpdateResource(hupdate, RT_GROUP_ICON, TEXT("CAUTION_ICO"), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
  520. //                                      && _UpdateResource(hupdate, RT_ICON, MAKEINTRESOURCE(1)/*Caution*/, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
  521.                                         && _UpdateResource(hupdate, RT_GROUP_CURSOR, TEXT("HAND_QUESTION"), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
  522.                                         // TODO: Removing the single resources don't work correctly. Sometimes the cursors are numbered 4,5,6 and sometimes 1,2,3 . Probably conflicts with icons
  523. //                                      && _UpdateResource(hupdate, RT_CURSOR, MAKEINTRESOURCE(3)/*QuestionHand*/, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
  524.                                         && _UpdateResource(hupdate, TEXT("PIPL") /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
  525.                                         && _UpdateResource(hupdate, TEXT("AETE") /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
  526.                                         // OPER and FUNC are written so that "Plugin Manager 2.1" thinks that this plugin is a Filter Factory plugin! SYNM is not important, though.
  527.                                         && (gdata->obfusc || _UpdateResource(hupdate, TEXT("OPER"), MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_oper, sizeof(dummy_oper)))
  528.                                         && (gdata->obfusc || _UpdateResource(hupdate, TEXT("FUNC"), MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_func, sizeof(dummy_func)))
  529.                                         && (gdata->obfusc || _UpdateResource(hupdate, TEXT("SYNM"), MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_symn, sizeof(dummy_symn)))
  530.                                         && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
  531.                                         && _UpdateResource(hupdate, parm_type,parm_id, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
  532.                                 {
  533.                                         discard = false;
  534.                                 } else {
  535.                                         showLastError((TCHAR*)TEXT("UpdateResource"));
  536.                                 }
  537.                         }
  538.  
  539.                         free(newmanifest);
  540.  
  541.                         // Here, the file will be saved
  542.                         if (_EndUpdateResource(hupdate, discard)) {
  543.                                 if (gdata->obfusc) {
  544.                                         // We modify the binary code to replace the deobfuscate-seed from <cObfuscSeed> to <obfuscseed>
  545.  
  546.                                         // First try with alignment "4" (this should be the usual case),
  547.                                         // and if that failed, try without alignment ("1").
  548.                                         // We only need to set maxamount to "1", because "const volatile" makes sure that
  549.                                         // the compiler won't place (inline) it at several locations in the code.
  550.                                         // TODO: This is very slow
  551.                                         if ((binary_replace_file(dst, GetObfuscSeed(), obfuscseed, /*0 means "align to 1"*/0, /*maxamount=*/1) == 0) ||
  552.                                                 (binary_replace_file(dst, GetObfuscSeed2(), obfuscseed2, /*0 means "align to 1"*/0, /*maxamount=*/1) == 0))
  553.                                         {
  554.                                                 simplewarning((TCHAR*)TEXT("binary_replace_file failed")); // TODO (Not so important): TRANSLATE
  555.                                                 discard = true;
  556.                                         }
  557.                                 }
  558.  
  559.                                 if (!update_pe_timestamp(dst, (__time32_t)time(0))) {
  560.                                         simplewarning((TCHAR*)TEXT("update_pe_timestamp failed")); // TODO (Not so important): TRANSLATE
  561.                                 }
  562.  
  563.                                 if (!repair_pe_checksum(dst)) {
  564.                                         simplewarning((TCHAR*)TEXT("repair_pe_checksum failed")); // TODO (Not so important): TRANSLATE
  565.                                 }
  566.                         }else showLastError((TCHAR*)TEXT("EndUpdateResource"));
  567.  
  568.                 }else showLastError((TCHAR*)TEXT("Find-, Load- or LockResource"));
  569.  
  570.                 if(pparm) free(pparm);
  571.                 if(newpipl) free(newpipl);
  572.                 if(newaete) free(newaete);
  573.         }else
  574.         showLastError((TCHAR*)TEXT("BeginUpdateResource"));
  575.         return !discard;
  576. }
  577.  
  578. Boolean remove_64_filename_prefix(LPTSTR dstname) {
  579.         // foobar.8bf => foobar.8bf
  580.         // foobar64.8bf => foobar.8bf
  581.         size_t i;
  582.         for (i = xstrlen(dstname); i > 2; i--) {
  583.                 if (dstname[i] == '.') {
  584.                         if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
  585.                                 size_t tmp = xstrlen(dstname);
  586.                                 memcpy(&dstname[i - 2], &dstname[i], (xstrlen(dstname) - i + 1) * sizeof(TCHAR));
  587.                                 dstname[tmp - 2] = 0;
  588.                                 return true;
  589.                         }
  590.                 }
  591.         }
  592.         return false;
  593. }
  594.  
  595. Boolean add_64_filename_prefix(LPTSTR dstname) {
  596.         // foobar.8bf => foobar64.8bf
  597.         size_t i;
  598.         for (i = xstrlen(dstname); i > 2; i--) {
  599.                 if (dstname[i] == '.') {
  600.                         size_t tmp = xstrlen(dstname);
  601.                         memcpy(&dstname[i + 2], &dstname[i], (xstrlen(dstname) - i + 1) * sizeof(TCHAR));
  602.                         dstname[i] = '6';
  603.                         dstname[i + 1] = '4';
  604.                         dstname[tmp + 2] = 0;
  605.                         return true;
  606.                 }
  607.         }
  608.         return false;
  609. }
  610.  
  611. BOOL FileExists(LPCTSTR szPath) {
  612.         DWORD dwAttrib = GetFileAttributes(szPath);
  613.         return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
  614.                 !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
  615. }
  616.  
  617. Boolean extract_file(LPCTSTR lpType, LPCTSTR lpName, FSSpec* dst) {
  618.         HGLOBAL datah;
  619.         LPVOID datap;
  620.         HRSRC datarsrc;
  621.         FILECOUNT datalen;
  622.         FILEREF fptr;
  623.         OSErr res;
  624.  
  625.         if ((datarsrc = FindResource((HMODULE)hDllInstance, lpName, lpType))
  626.                 && (datah = LoadResource((HMODULE)hDllInstance, datarsrc))
  627.                 && (datalen = (FILECOUNT)SizeofResource((HMODULE)hDllInstance, datarsrc))
  628.                 && (datap = (Ptr)LockResource(datah))) {
  629.  
  630.                 FSpDelete(dst);
  631.                 if (FSpCreate(dst, kPhotoshopSignature, PS_FILTER_FILETYPE, 0/*sfr->sfScript*/) != noErr) return false;
  632.  
  633.                 if (FSpOpenDF(dst, fsRdWrPerm, &fptr) != noErr) return false;
  634.  
  635.                 res = FSWrite(fptr, &datalen, datap);
  636.  
  637.                 FSClose(fptr);
  638.  
  639.                 return res == noErr;
  640.         }
  641.         else {
  642.                 return false;
  643.         }
  644. }
  645.  
  646. BOOL StripAuthenticode(FSSpec* dst) {
  647.         HANDLE hFile = CreateFile(&dst->szName[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
  648.         if (hFile == INVALID_HANDLE_VALUE) {
  649.                 CloseHandle(hFile);
  650.                 return FALSE;
  651.         }
  652.         if (!_ImageRemoveCertificate(hFile, 0)) {
  653.                 CloseHandle(hFile);
  654.                 return FALSE;
  655.         }
  656.         CloseHandle(hFile);
  657.         return TRUE;
  658. }
  659.  
  660. OSErr do_make_standalone(FSSpec* dst, int bits) {
  661.         Boolean res;
  662.  
  663.         //DeleteFile(dstname);
  664.         if (extract_file(TEXT("TPLT"), MAKEINTRESOURCE(1000 + bits), dst)) {
  665.                 // In case we did digitally sign the FilterFoundry plugin (which is currently not the case though),
  666.                 // we must now remove the signature, because the embedding of parameter data has invalidated it.
  667.                 // Do it before we manipulate anything, in order to avoid that there is an invalid binary (which might annoy AntiVirus software)
  668.                 StripAuthenticode(dst);
  669.  
  670.                 // Now do the resources
  671.                 res = doresources(dst, bits);
  672.                 if (!res) {
  673.                         DeleteFile(&dst->szName[0]);
  674.                         alertuser_id(bits == 32 ? MSG_CANNOT_CREATE_32BIT_FILTER_ID : MSG_CANNOT_CREATE_64BIT_FILTER_ID, (TCHAR*)TEXT("doresources failed"));
  675.                 }
  676.         }
  677.         else {
  678.                 // If you see this error, please make sure that you have called foundry_3264_mixer to include the 32/64 plugins as resource!
  679.                 res = false;
  680.                 //DeleteFile(dstname);
  681.  
  682.                 alertuser_id(bits == 32 ? MSG_CANNOT_CREATE_32BIT_FILTER_ID : MSG_CANNOT_CREATE_64BIT_FILTER_ID, (TCHAR*)TEXT("extract_file failed"));
  683.         }
  684.  
  685.         return res ? noErr : ioErr;
  686. }
  687.  
  688. OSErr make_standalone(StandardFileReply *sfr){
  689.         OSErr tmpErr, outErr;
  690.         FSSpec dst = { 0 };
  691.  
  692.         outErr = noErr;
  693.  
  694.         // Make 32 bit:
  695.         // Destfile = no64_or_32(chosenname)
  696.         xstrcpy(dst.szName, sfr->sfFile.szName);
  697.         remove_64_filename_prefix(&dst.szName[0]);
  698.         tmpErr = do_make_standalone(&dst, 32);
  699.         if (tmpErr != noErr)
  700.                 outErr = tmpErr;
  701.         else
  702.                 showmessage_id(MSG_BUILT32_ID);
  703.  
  704.         // Make 64 bit:
  705.         // Destfile = no64_or_32(chosenname) + 64
  706.         xstrcpy(dst.szName, sfr->sfFile.szName);
  707.         remove_64_filename_prefix(&dst.szName[0]);
  708.         add_64_filename_prefix(&dst.szName[0]);
  709.         tmpErr = do_make_standalone(&dst, 64);
  710.         if (tmpErr != noErr)
  711.                 outErr = tmpErr;
  712.         else
  713.                 showmessage_id(MSG_BUILT64_ID);
  714.  
  715.         return outErr;
  716. }
  717.  
  718.