Subversion Repositories filter_foundry

Rev

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