Subversion Repositories filter_foundry

Rev

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