Subversion Repositories filter_foundry

Rev

Rev 497 | Rev 504 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

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