Subversion Repositories filter_foundry

Rev

Rev 508 | Rev 510 | 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
        {
508 daniel-mar 288
                if (cnt != sizeof(srecord)) break; // EOF reached
276 daniel-mar 289
                if (srecord == search) {
290
                        srecord = replace;
444 daniel-mar 291
                        SetFPos(fptr, fsFromMark, -1 * (long)sizeof(srecord));
292
                        cnt = (int)sizeof(srecord);
293
                        FSWrite(fptr, &cnt, &srecord);
294
                        SetFPos(fptr, fsFromStart, 0); // important for fseek
276 daniel-mar 295
                        found++;
347 daniel-mar 296
                        if (found == maxamount) break;
276 daniel-mar 297
                }
298
                else {
347 daniel-mar 299
                        if (!align) {
444 daniel-mar 300
                                SetFPos(fptr, fsFromMark, -1 * (long)(sizeof(srecord) - 1));
347 daniel-mar 301
                        }
276 daniel-mar 302
                }
303
        }
444 daniel-mar 304
        FSClose(fptr);
276 daniel-mar 305
 
306
        return found;
307
}
308
 
444 daniel-mar 309
uint32_t calculate_checksum(FSSpec* dst) {
281 daniel-mar 310
        //Calculate checksum of image
311
        // Taken from "PE Bliss" Cross-Platform Portable Executable C++ Library
312
        // https://github.com/mrexodia/portable-executable-library/blob/master/pe_lib/pe_checksum.cpp
313
        // Converted from C++ to C by Daniel Marschall
314
 
444 daniel-mar 315
        FILEREF fptr;
281 daniel-mar 316
        unsigned long long checksum = 0;
456 daniel-mar 317
        IMAGE_DOS_HEADER header;
444 daniel-mar 318
        FILEPOS filesize, i;
281 daniel-mar 319
        unsigned long long top;
320
        unsigned long pe_checksum_pos;
321
        static const unsigned long checksum_pos_in_optional_headers = 64;
444 daniel-mar 322
        FILECOUNT cnt;
281 daniel-mar 323
 
444 daniel-mar 324
        if (FSpOpenDF(dst, fsRdWrPerm, &fptr) != noErr) return 0x00000000;
281 daniel-mar 325
 
326
        //Read DOS header
444 daniel-mar 327
        SetFPos(fptr, fsFromStart, 0);
456 daniel-mar 328
        cnt = sizeof(IMAGE_DOS_HEADER);
444 daniel-mar 329
        FSRead(fptr, &cnt, &header);
281 daniel-mar 330
 
331
        //Calculate PE checksum
444 daniel-mar 332
        SetFPos(fptr, fsFromStart, 0);
281 daniel-mar 333
        top = 0xFFFFFFFF;
334
        top++;
335
 
336
        //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+
337
        //Calculate real PE headers "CheckSum" field position
338
        //Sum is safe here
456 daniel-mar 339
        pe_checksum_pos = header.e_lfanew + sizeof(IMAGE_FILE_HEADER) + sizeof(uint32_t) + checksum_pos_in_optional_headers;
281 daniel-mar 340
 
341
        //Calculate checksum for each byte of file
444 daniel-mar 342
        filesize = 0;
343
        GetEOF(fptr, &filesize);
344
        SetFPos(fptr, fsFromStart, 0);
281 daniel-mar 345
        for (i = 0; i < filesize; i += 4)
346
        {
347
                unsigned long dw = 0;
348
 
349
                //Read DWORD from file
444 daniel-mar 350
                cnt = sizeof(dw);
351
                FSRead(fptr, &cnt, &dw);
281 daniel-mar 352
                //Skip "CheckSum" DWORD
353
                if (i == pe_checksum_pos)
354
                        continue;
355
 
356
                //Calculate checksum
357
                checksum = (checksum & 0xffffffff) + dw + (checksum >> 32);
358
                if (checksum > top)
359
                        checksum = (checksum & 0xffffffff) + (checksum >> 32);
360
        }
361
 
362
        //Finish checksum
363
        checksum = (checksum & 0xffff) + (checksum >> 16);
364
        checksum = (checksum)+(checksum >> 16);
365
        checksum = checksum & 0xffff;
366
 
367
        checksum += (unsigned long)(filesize);
368
 
444 daniel-mar 369
        FSClose(fptr);
281 daniel-mar 370
 
371
        //Return checksum
372
        return (uint32_t)checksum;
373
}
374
 
444 daniel-mar 375
Boolean repair_pe_checksum(FSSpec* dst) {
281 daniel-mar 376
        size_t peoffset;
444 daniel-mar 377
        FILEREF fptr;
378
        FILECOUNT cnt;
379
        Boolean res;
281 daniel-mar 380
 
444 daniel-mar 381
        uint32_t checksum = calculate_checksum(dst);
281 daniel-mar 382
        //if (checksum == 0x00000000) return false;
383
 
444 daniel-mar 384
        if (FSpOpenDF(dst, fsRdWrPerm, &fptr) != noErr) return false;
281 daniel-mar 385
 
503 daniel-mar 386
        res =
444 daniel-mar 387
                SetFPos(fptr, fsFromStart, 0x3C) ||
388
                (cnt = sizeof(peoffset), noErr) ||
389
                FSRead(fptr, &cnt, &peoffset) ||
456 daniel-mar 390
                SetFPos(fptr, fsFromStart, (long)peoffset + /*0x0058*/offsetof(PE32, optHeader.CheckSum)) ||
444 daniel-mar 391
                (cnt = sizeof(uint32_t), noErr) ||
392
                FSWrite(fptr, &cnt, &checksum);
281 daniel-mar 393
 
444 daniel-mar 394
        FSClose(fptr);
281 daniel-mar 395
 
444 daniel-mar 396
        return res == noErr; // res=0 means everything was noErr, res=1 means something was !=noErr
281 daniel-mar 397
}
398
 
345 daniel-mar 399
typedef struct {
400
        char funcname[8];
401
        uint16_t codelen;
402
} operdef_t;
403
 
404
typedef struct {
405
        char funcname[8];
406
        uint16_t numparams;
407
} funcdef_t;
408
 
409
typedef struct {
410
        char funcname[8];
411
        char referencename[8];
412
} symndef_t;
413
 
444 daniel-mar 414
Boolean doresources(FSSpec* dst, int bits){
258 daniel-mar 415
        HRSRC datarsrc,aetersrc,manifestsrc;
416
        HGLOBAL datah,aeteh,hupdate,manifesth;
345 daniel-mar 417
 
418
        operdef_t dummy_oper;
419
        funcdef_t dummy_func;
420
        symndef_t dummy_symn;
421
 
258 daniel-mar 422
        Ptr newpipl = NULL, newaete = NULL;
423
        LPVOID datap, aetep, manifestp;
324 daniel-mar 424
        char* manifestp_copy;
258 daniel-mar 425
        PARM_T *pparm = NULL;
324 daniel-mar 426
        size_t piplsize,aetesize,origsize;
393 daniel-mar 427
        char title[256];
258 daniel-mar 428
        LPCTSTR parm_type;
425 daniel-mar 429
        LPCTSTR parm_id;
258 daniel-mar 430
        Boolean discard = true;
508 daniel-mar 431
        uint64_t obfuscseed = 0, obfuscseed2 = 0;
258 daniel-mar 432
        long event_id;
433
 
345 daniel-mar 434
        memset(&dummy_oper, 0, sizeof(operdef_t));
435
        memset(&dummy_func, 0, sizeof(funcdef_t));
436
        memset(&dummy_symn, 0, sizeof(symndef_t));
437
 
444 daniel-mar 438
        if( (hupdate = _BeginUpdateResource(&dst->szName[0],false)) ){
439
                if( (datarsrc = FindResource(hDllInstance,MAKEINTRESOURCE(16000 + bits), TEXT("TPLT")))
402 daniel-mar 440
                        && (datah = LoadResource(hDllInstance,datarsrc))
258 daniel-mar 441
                        && (datap = (Ptr)LockResource(datah))
444 daniel-mar 442
                        && (aetersrc = FindResource(hDllInstance, MAKEINTRESOURCE(16000), TEXT("AETE")))
402 daniel-mar 443
                        && (aeteh = LoadResource(hDllInstance, aetersrc))
258 daniel-mar 444
                        && (aetep = (Ptr)LockResource(aeteh))
444 daniel-mar 445
                        && (manifestsrc = FindResource(hDllInstance, MAKEINTRESOURCE(1), TEXT("TPLT")))
402 daniel-mar 446
                        && (manifesth = LoadResource(hDllInstance, manifestsrc))
258 daniel-mar 447
                        && (manifestp = (Ptr)LockResource(manifesth)) )
448
                {
324 daniel-mar 449
                        char* newmanifest;
402 daniel-mar 450
                        int manifestsize = SizeofResource(hDllInstance, manifestsrc);
258 daniel-mar 451
 
454 daniel-mar 452
                        newmanifest = (char*)malloc((size_t)manifestsize + 4096/*+4KiB for name,description,etc.*/);
324 daniel-mar 453
 
393 daniel-mar 454
                        strcpy(title,gdata->parm.szTitle);
258 daniel-mar 455
                        if(gdata->parm.popDialog)
393 daniel-mar 456
                                strcat(title,"...");
258 daniel-mar 457
 
402 daniel-mar 458
                        origsize = SizeofResource(hDllInstance,datarsrc);
258 daniel-mar 459
 
460
                        if( (newpipl = (Ptr)malloc(origsize+0x300))
461
                         && (newaete = (Ptr)malloc(4096))
462
                         && (pparm = (PARM_T*)malloc(sizeof(PARM_T))) )
463
                        {
464
                                // ====== Generate AETE and PIPL
465
 
466
                                /* add user-specified title and category to new PiPL */
467
                                memcpy(newpipl,datap,origsize);
468
                                /* note that Windows PiPLs have 2 byte version datum in front
469
                                   that isn't reflected in struct definition or Mac resource template: */
393 daniel-mar 470
                                piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,&title[0], &event_id) + 2;
258 daniel-mar 471
 
472
                                /* set up the PARM resource with saved parameters */
473
                                memcpy(pparm,&gdata->parm,sizeof(PARM_T));
474
 
475
                                /* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
476
                                aetesize = aete_generate(newaete, pparm, event_id);
477
 
324 daniel-mar 478
                                // ====== Create fitting manifest for the activation context
258 daniel-mar 479
 
454 daniel-mar 480
                                manifestp_copy = (char*)malloc((size_t)manifestsize + 1/*sz*/);
324 daniel-mar 481
                                if (manifestp_copy != 0) {
482
                                        memcpy(manifestp_copy, manifestp, manifestsize); // copy manifestp to manifestp_copy, because manifestp is readonly
483
                                        manifestp_copy[manifestsize] = '\0'; // and add the null-terminating char, because domanifest() uses sprintf() on it
484
                                        manifestsize = domanifest(newmanifest, manifestp_copy, pparm, bits);
485
                                        free(manifestp_copy);
486
                                }
487
 
258 daniel-mar 488
                                // ====== Change version attributes
489
 
444 daniel-mar 490
                                if (changeVersionInfo(dst, hupdate, pparm, bits) != NOERROR) {
492 daniel-mar 491
                                        simplewarning((TCHAR*)TEXT("changeVersionInfo failed")); // TODO (Not so important): TRANSLATE
416 daniel-mar 492
                                }
258 daniel-mar 493
 
494
                                // ====== Obfuscate pparm!
495
 
292 daniel-mar 496
                                if (gdata->obfusc) {
375 daniel-mar 497
                                        parm_type = OBFUSCDATA_TYPE_NEW;
498
                                        parm_id = OBFUSCDATA_ID_NEW;
276 daniel-mar 499
 
500
                                        // Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
508 daniel-mar 501
                                        obfusc(pparm, &obfuscseed, &obfuscseed2);
258 daniel-mar 502
                                }else{
375 daniel-mar 503
                                        parm_type = PARM_TYPE;
504
                                        parm_id = PARM_ID_NEW;
258 daniel-mar 505
                                }
506
 
507
                                // ====== Save AETE, PIPL, Manifest and PARM/RCDATA
508
 
509
                                /* Attention: The resource we have found using FindResource() might have a different
510
                                   language than the resource we are saving (Neutral), so we might end up having
511
                                   multiple languages for the same resource. Therefore, the language "Neutral" was
512
                                   set in the Scripting.rc file for the resource AETE and PIPL.rc for the resources PIPL. */
274 daniel-mar 513
 
416 daniel-mar 514
                                if(
515
                                           _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_BUILDDLG), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL, 0) // clean up things we don't need in the standalone plugin
497 daniel-mar 516
                                        && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_BUILDDLG), MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), NULL, 0) // clean up things we don't need in the standalone plugin
308 daniel-mar 517
                                        && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_MAINDLG), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL, 0) // clean up things we don't need in the standalone plugin
497 daniel-mar 518
                                        && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_MAINDLG), MAKELANGID(LANG_GERMAN, SUBLANG_GERMAN), NULL, 0) // clean up things we don't need in the standalone plugin
444 daniel-mar 519
                                        && _UpdateResource(hupdate, RT_GROUP_ICON, TEXT("CAUTION_ICO"), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
393 daniel-mar 520
//                                      && _UpdateResource(hupdate, RT_ICON, MAKEINTRESOURCE(1)/*Caution*/, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
444 daniel-mar 521
                                        && _UpdateResource(hupdate, RT_GROUP_CURSOR, TEXT("HAND_QUESTION"), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
402 daniel-mar 522
                                        // TODO: Removing the single resources don't work correctly. Sometimes the cursors are numbered 4,5,6 and sometimes 1,2,3 . Probably conflicts with icons
523
//                                      && _UpdateResource(hupdate, RT_CURSOR, MAKEINTRESOURCE(3)/*QuestionHand*/, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
444 daniel-mar 524
                                        && _UpdateResource(hupdate, TEXT("PIPL") /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
525
                                        && _UpdateResource(hupdate, TEXT("AETE") /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
345 daniel-mar 526
                                        // OPER and FUNC are written so that "Plugin Manager 2.1" thinks that this plugin is a Filter Factory plugin! SYNM is not important, though.
444 daniel-mar 527
                                        && (gdata->obfusc || _UpdateResource(hupdate, TEXT("OPER"), MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_oper, sizeof(dummy_oper)))
528
                                        && (gdata->obfusc || _UpdateResource(hupdate, TEXT("FUNC"), MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_func, sizeof(dummy_func)))
529
                                        && (gdata->obfusc || _UpdateResource(hupdate, TEXT("SYNM"), MAKEINTRESOURCE(16000), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), &dummy_symn, sizeof(dummy_symn)))
258 daniel-mar 530
                                        && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
376 daniel-mar 531
                                        && _UpdateResource(hupdate, parm_type,parm_id, MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
258 daniel-mar 532
                                {
533
                                        discard = false;
534
                                } else {
482 daniel-mar 535
                                        showLastError((TCHAR*)TEXT("UpdateResource"));
258 daniel-mar 536
                                }
537
                        }
538
 
425 daniel-mar 539
                        free(newmanifest);
540
 
416 daniel-mar 541
                        // Here, the file will be saved
542
                        if (_EndUpdateResource(hupdate, discard)) {
543
                                if (gdata->obfusc) {
544
                                        // We modify the binary code to replace the deobfuscate-seed from <cObfuscSeed> to <obfuscseed>
258 daniel-mar 545
 
416 daniel-mar 546
                                        // First try with alignment "4" (this should be the usual case),
547
                                        // and if that failed, try without alignment ("1").
548
                                        // We only need to set maxamount to "1", because "const volatile" makes sure that
549
                                        // the compiler won't place (inline) it at several locations in the code.
509 daniel-mar 550
                                        // TODO: This is very slow
551
                                        if ((binary_replace_file(dst, GetObfuscSeed(), obfuscseed, /*0 means "align to 1"*/0, /*maxamount=*/1) == 0) ||
552
                                                (binary_replace_file(dst, GetObfuscSeed2(), obfuscseed2, /*0 means "align to 1"*/0, /*maxamount=*/1) == 0))
416 daniel-mar 553
                                        {
492 daniel-mar 554
                                                simplewarning((TCHAR*)TEXT("binary_replace_file failed")); // TODO (Not so important): TRANSLATE
416 daniel-mar 555
                                                discard = true;
556
                                        }
557
                                }
258 daniel-mar 558
 
456 daniel-mar 559
                                if (!update_pe_timestamp(dst, (__time32_t)time(0))) {
492 daniel-mar 560
                                        simplewarning((TCHAR*)TEXT("update_pe_timestamp failed")); // TODO (Not so important): TRANSLATE
444 daniel-mar 561
                                }
347 daniel-mar 562
 
444 daniel-mar 563
                                if (!repair_pe_checksum(dst)) {
492 daniel-mar 564
                                        simplewarning((TCHAR*)TEXT("repair_pe_checksum failed")); // TODO (Not so important): TRANSLATE
444 daniel-mar 565
                                }
482 daniel-mar 566
                        }else showLastError((TCHAR*)TEXT("EndUpdateResource"));
276 daniel-mar 567
 
482 daniel-mar 568
                }else showLastError((TCHAR*)TEXT("Find-, Load- or LockResource"));
278 daniel-mar 569
 
258 daniel-mar 570
                if(pparm) free(pparm);
571
                if(newpipl) free(newpipl);
572
                if(newaete) free(newaete);
573
        }else
482 daniel-mar 574
        showLastError((TCHAR*)TEXT("BeginUpdateResource"));
258 daniel-mar 575
        return !discard;
576
}
577
 
444 daniel-mar 578
Boolean remove_64_filename_prefix(LPTSTR dstname) {
274 daniel-mar 579
        // foobar.8bf => foobar.8bf
580
        // foobar64.8bf => foobar.8bf
276 daniel-mar 581
        size_t i;
444 daniel-mar 582
        for (i = xstrlen(dstname); i > 2; i--) {
274 daniel-mar 583
                if (dstname[i] == '.') {
584
                        if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
444 daniel-mar 585
                                size_t tmp = xstrlen(dstname);
586
                                memcpy(&dstname[i - 2], &dstname[i], (xstrlen(dstname) - i + 1) * sizeof(TCHAR));
274 daniel-mar 587
                                dstname[tmp - 2] = 0;
588
                                return true;
589
                        }
590
                }
591
        }
592
        return false;
593
}
594
 
444 daniel-mar 595
Boolean add_64_filename_prefix(LPTSTR dstname) {
274 daniel-mar 596
        // foobar.8bf => foobar64.8bf
276 daniel-mar 597
        size_t i;
444 daniel-mar 598
        for (i = xstrlen(dstname); i > 2; i--) {
274 daniel-mar 599
                if (dstname[i] == '.') {
444 daniel-mar 600
                        size_t tmp = xstrlen(dstname);
601
                        memcpy(&dstname[i + 2], &dstname[i], (xstrlen(dstname) - i + 1) * sizeof(TCHAR));
274 daniel-mar 602
                        dstname[i] = '6';
603
                        dstname[i + 1] = '4';
604
                        dstname[tmp + 2] = 0;
605
                        return true;
606
                }
607
        }
608
        return false;
609
}
610
 
611
BOOL FileExists(LPCTSTR szPath) {
612
        DWORD dwAttrib = GetFileAttributes(szPath);
613
        return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
614
                !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
615
}
616
 
444 daniel-mar 617
Boolean extract_file(LPCTSTR lpType, LPCTSTR lpName, FSSpec* dst) {
308 daniel-mar 618
        HGLOBAL datah;
619
        LPVOID datap;
620
        HRSRC datarsrc;
444 daniel-mar 621
        FILECOUNT datalen;
622
        FILEREF fptr;
623
        OSErr res;
308 daniel-mar 624
 
625
        if ((datarsrc = FindResource((HMODULE)hDllInstance, lpName, lpType))
626
                && (datah = LoadResource((HMODULE)hDllInstance, datarsrc))
444 daniel-mar 627
                && (datalen = (FILECOUNT)SizeofResource((HMODULE)hDllInstance, datarsrc))
308 daniel-mar 628
                && (datap = (Ptr)LockResource(datah))) {
629
 
444 daniel-mar 630
                FSpDelete(dst);
631
                if (FSpCreate(dst, kPhotoshopSignature, PS_FILTER_FILETYPE, 0/*sfr->sfScript*/) != noErr) return false;
308 daniel-mar 632
 
444 daniel-mar 633
                if (FSpOpenDF(dst, fsRdWrPerm, &fptr) != noErr) return false;
634
 
635
                res = FSWrite(fptr, &datalen, datap);
636
 
637
                FSClose(fptr);
638
 
639
                return res == noErr;
308 daniel-mar 640
        }
641
        else {
642
                return false;
643
        }
644
}
645
 
444 daniel-mar 646
BOOL StripAuthenticode(FSSpec* dst) {
647
        HANDLE hFile = CreateFile(&dst->szName[0], GENERIC_READ | GENERIC_WRITE, FILE_SHARE_READ | FILE_SHARE_DELETE, NULL, OPEN_EXISTING, 0, NULL);
364 daniel-mar 648
        if (hFile == INVALID_HANDLE_VALUE) {
649
                CloseHandle(hFile);
650
                return FALSE;
651
        }
652
        if (!_ImageRemoveCertificate(hFile, 0)) {
653
                CloseHandle(hFile);
654
                return FALSE;
655
        }
357 daniel-mar 656
        CloseHandle(hFile);
657
        return TRUE;
658
}
659
 
444 daniel-mar 660
OSErr do_make_standalone(FSSpec* dst, int bits) {
274 daniel-mar 661
        Boolean res;
292 daniel-mar 662
 
274 daniel-mar 663
        //DeleteFile(dstname);
444 daniel-mar 664
        if (extract_file(TEXT("TPLT"), MAKEINTRESOURCE(1000 + bits), dst)) {
360 daniel-mar 665
                // In case we did digitally sign the FilterFoundry plugin (which is currently not the case though),
666
                // we must now remove the signature, because the embedding of parameter data has invalidated it.
667
                // Do it before we manipulate anything, in order to avoid that there is an invalid binary (which might annoy AntiVirus software)
444 daniel-mar 668
                StripAuthenticode(dst);
360 daniel-mar 669
 
670
                // Now do the resources
444 daniel-mar 671
                res = doresources(dst, bits);
319 daniel-mar 672
                if (!res) {
444 daniel-mar 673
                        DeleteFile(&dst->szName[0]);
492 daniel-mar 674
                        alertuser_id(bits == 32 ? MSG_CANNOT_CREATE_32BIT_FILTER_ID : MSG_CANNOT_CREATE_64BIT_FILTER_ID, (TCHAR*)TEXT("doresources failed"));
274 daniel-mar 675
                }
676
        }
677
        else {
308 daniel-mar 678
                // 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 679
                res = false;
292 daniel-mar 680
                //DeleteFile(dstname);
444 daniel-mar 681
 
492 daniel-mar 682
                alertuser_id(bits == 32 ? MSG_CANNOT_CREATE_32BIT_FILTER_ID : MSG_CANNOT_CREATE_64BIT_FILTER_ID, (TCHAR*)TEXT("extract_file failed"));
274 daniel-mar 683
        }
684
 
685
        return res ? noErr : ioErr;
686
}
687
 
314 daniel-mar 688
OSErr make_standalone(StandardFileReply *sfr){
689
        OSErr tmpErr, outErr;
454 daniel-mar 690
        FSSpec dst = { 0 };
314 daniel-mar 691
 
274 daniel-mar 692
        outErr = noErr;
314 daniel-mar 693
 
308 daniel-mar 694
        // Make 32 bit:
695
        // Destfile = no64_or_32(chosenname)
444 daniel-mar 696
        xstrcpy(dst.szName, sfr->sfFile.szName);
697
        remove_64_filename_prefix(&dst.szName[0]);
698
        tmpErr = do_make_standalone(&dst, 32);
274 daniel-mar 699
        if (tmpErr != noErr)
700
                outErr = tmpErr;
701
        else
492 daniel-mar 702
                showmessage_id(MSG_BUILT32_ID);
274 daniel-mar 703
 
402 daniel-mar 704
        // Make 64 bit:
705
        // Destfile = no64_or_32(chosenname) + 64
444 daniel-mar 706
        xstrcpy(dst.szName, sfr->sfFile.szName);
707
        remove_64_filename_prefix(&dst.szName[0]);
708
        add_64_filename_prefix(&dst.szName[0]);
709
        tmpErr = do_make_standalone(&dst, 64);
402 daniel-mar 710
        if (tmpErr != noErr)
711
                outErr = tmpErr;
712
        else
492 daniel-mar 713
                showmessage_id(MSG_BUILT64_ID);
274 daniel-mar 714
 
715
        return outErr;
258 daniel-mar 716
}
308 daniel-mar 717