Subversion Repositories filter_foundry

Rev

Rev 274 | Rev 277 | 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
 
23
#include "file_compat.h"
24
#include "compat_string.h"
25
#include "versioninfo_modify_win.h"
26
#include "version.h"
27
 
28
extern HINSTANCE hDllInstance;
29
 
274 daniel-mar 30
Boolean doresources(HMODULE srcmod,char *dstname, int bits);
258 daniel-mar 31
 
32
void dbglasterror(char *func){
33
        char s[0x100];
34
 
35
        strcpy(s,func);
36
        strcat(s," failed: ");
37
        FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),0,s+strlen(s),0x100,NULL );
38
        dbg(s);
39
}
40
 
41
/*
42
BOOL CALLBACK enumfunc(HMODULE hModule,LPCTSTR lpszType,LPCTSTR lpszName,WORD wIDLanguage,LONG lParam){
43
        char s[0x100];
44
        sprintf(s,"EnumResourceLanguages callback: module=%#x type=%s name=%s lang=%d",
45
                hModule,lpszType,lpszName,wIDLanguage);
46
        dbg(s);
47
        return TRUE;
48
}
49
*/
50
 
274 daniel-mar 51
int domanifest(char *newmanifest, const char *manifestp, PARM_T* pparm, int bits) {
258 daniel-mar 52
        char name[1024];
53
        char description[1024];
54
        size_t i;
276 daniel-mar 55
        size_t iname = 0;
258 daniel-mar 56
        int idescription = 0;
57
 
58
        // Description
59
        for (i = 0; i < strlen((char*)pparm->category); i++) {
60
                char c = pparm->category[i];
61
                if ((c != '<') && (c != '>')) {
62
                        description[idescription++] = c;
63
                }
64
        }
65
        description[idescription++] = ' ';
66
        description[idescription++] = '-';
67
        description[idescription++] = ' ';
68
        for (i = 0; i < strlen((char*)pparm->title); i++) {
69
                char c = pparm->title[i];
70
                if ((c != '<') && (c != '>')) {
71
                        description[idescription++] = c;
72
                }
73
        }
74
        description[idescription++] = '\0';
75
 
76
        // Name
77
        strcpy(name, "Telegraphics.FilterFoundry.");
78
        iname = strlen("Telegraphics.FilterFoundry.");
79
        for (i = 0; i < strlen((char*)pparm->category); i++) {
80
                char c = pparm->category[i];
81
                if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) {
82
                        name[iname++] = c;
83
                }
84
        }
85
        name[iname++] = '.';
86
        for (i = 0; i < strlen((char*)pparm->title); i++) {
87
                char c = pparm->title[i];
88
                if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) {
89
                        name[iname++] = c;
90
                }
91
        }
92
        name[iname++] = '\0';
93
 
274 daniel-mar 94
        if (bits == 64) {
95
                return sprintf(newmanifest, manifestp, (char*)name, "amd64", VERSION_STR, (char*)description);
96
        }
97
        else {
98
                return sprintf(newmanifest, manifestp, (char*)name, "x86", VERSION_STR, (char*)description);
99
        }
258 daniel-mar 100
}
101
 
102
void changeVersionInfo(char* dstname, PARM_T* pparm, HGLOBAL hupdate) {
103
        char* soleFilename;
104
        LPWSTR changeRequestStr, tmp;
105
 
106
        if (soleFilename = strrchr(dstname, '\\')) {
107
                ++soleFilename;
108
        }
109
        else {
110
                soleFilename = dstname;
111
        }
112
 
113
        // Format of argument "PCWSTR changes" is "<name>\0<value>\0<name>\0<value>\0....."
114
        // You can CHANGE values for any given name
115
        // You can DELETE entries by setting the value to "\b" (0x08 backspace character)
116
        // You cannot (yet) ADD entries.
117
        changeRequestStr = (LPWSTR)malloc(6 * 2 * 100 + 1);
118
 
119
        tmp = changeRequestStr;
120
 
121
        tmp += mbstowcs(tmp, "Comments", 100);
122
        tmp++;
123
        tmp += mbstowcs(tmp, "Built using Filter Foundry " VERSION_STR, 100);
124
        tmp++;
125
 
126
        tmp += mbstowcs(tmp, "CompanyName", 100);
127
        tmp++;
128
        if (strlen((char*)pparm->author) > 0) {
129
                tmp += mbstowcs(tmp, (char*)pparm->author, 100);
130
        }
131
        else {
132
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
133
        }
134
        tmp++;
135
 
136
        tmp += mbstowcs(tmp, "LegalCopyright", 100);
137
        tmp++;
138
        if (strlen((char*)pparm->copyright) > 0) {
139
                tmp += mbstowcs(tmp, (char*)pparm->copyright, 100);
140
        }
141
        else {
142
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
143
        }
144
        tmp++;
145
 
146
        tmp += mbstowcs(tmp, "FileDescription", 100);
147
        tmp++;
148
        if (strlen((char*)pparm->title) > 0) {
149
                tmp += mbstowcs(tmp, (char*)pparm->title, 100);
150
        }
151
        else {
152
                tmp += mbstowcs(tmp, "Untitled filter", 100);
153
        }
154
        tmp++;
155
 
156
        tmp += mbstowcs(tmp, "OriginalFilename", 100);
157
        tmp++;
158
        tmp += mbstowcs(tmp, soleFilename, 100);
159
        tmp++;
160
 
161
        tmp += mbstowcs(tmp, "License", 100);
162
        tmp++;
163
        tmp += mbstowcs(tmp, "\b", 100); // \b = remove, since filter is standalone and might have its own license
164
        tmp++;
165
 
166
        tmp += mbstowcs(tmp, "", 1);
167
 
168
        if (UpdateVersionInfoWithHandle(dstname, hupdate, changeRequestStr) != NOERROR) {
169
                alertuser(_strdup("UpdateVersionInfoWithHandle failed"), _strdup(""));
170
        }
171
 
172
        free(changeRequestStr);
173
}
174
 
276 daniel-mar 175
int binary_replace_file(const char* filename, unsigned int search, unsigned int replace) {
176
        unsigned int srecord = 0;
177
        int found = 0;
178
 
179
        FILE* fptr = fopen(filename, "rb+");
180
        if (fptr == NULL) return -1;
181
 
182
        while ((fread(&srecord, sizeof(srecord), 1, fptr) == 1))
183
        {
184
                if (srecord == search) {
185
                        srecord = replace;
186
                        fseek(fptr, -1*(long)sizeof(srecord), SEEK_CUR);
187
                        fwrite(&srecord, (int)sizeof(srecord), 1, fptr);
188
                        fseek(fptr, 0, SEEK_CUR); // important!
189
                        found++;
190
                }
191
                else {
192
                        fseek(fptr, -1*(long)(sizeof(srecord) - 1), SEEK_CUR);
193
                }
194
        }
195
        fclose(fptr);
196
 
197
        return found;
198
}
199
 
274 daniel-mar 200
Boolean doresources(HMODULE srcmod,char *dstname, int bits){
258 daniel-mar 201
        HRSRC datarsrc,aetersrc,manifestsrc;
202
        HGLOBAL datah,aeteh,hupdate,manifesth;
203
        Ptr newpipl = NULL, newaete = NULL;
204
        LPVOID datap, aetep, manifestp;
205
        PARM_T *pparm = NULL;
206
        size_t piplsize,aetesize,origsize,manifestsize;
207
        Str255 title;
208
        LPCTSTR parm_type;
209
        int i,parm_id;
210
        Boolean discard = true;
276 daniel-mar 211
        unsigned int obfuscseed = 0;
258 daniel-mar 212
        long event_id;
213
 
214
        if( (hupdate = _BeginUpdateResource(dstname,false)) ){
215
                DBG("BeginUpdateResource OK");
216
                if( (datarsrc = FindResource(srcmod,MAKEINTRESOURCE(16000),"TPLT"))
217
                        && (datah = LoadResource(srcmod,datarsrc))
218
                        && (datap = (Ptr)LockResource(datah))
219
                        && (aetersrc = FindResource(srcmod, MAKEINTRESOURCE(16000), "AETE"))
220
                        && (aeteh = LoadResource(srcmod, aetersrc))
221
                        && (aetep = (Ptr)LockResource(aeteh))
222
                        && (manifestsrc = FindResource(srcmod, MAKEINTRESOURCE(50), "TPLT"))
223
                        && (manifesth = LoadResource(srcmod, manifestsrc))
224
                        && (manifestp = (Ptr)LockResource(manifesth)) )
225
                {
226
                        char newmanifest[5000];
227
 
228
                        DBG("loaded DATA, PiPL");
229
 
230
                        PLstrcpy(title,gdata->parm.title);
231
                        if(gdata->parm.popDialog)
232
                                PLstrcat(title,(StringPtr)"\003...");
233
 
234
                        origsize = SizeofResource(srcmod,datarsrc);
235
 
236
                        if( (newpipl = (Ptr)malloc(origsize+0x300))
237
                         && (newaete = (Ptr)malloc(4096))
238
                         && (pparm = (PARM_T*)malloc(sizeof(PARM_T))) )
239
                        {
240
                                // ====== Generate AETE and PIPL
241
 
242
                                /* add user-specified title and category to new PiPL */
243
                                memcpy(newpipl,datap,origsize);
244
                                /* note that Windows PiPLs have 2 byte version datum in front
245
                                   that isn't reflected in struct definition or Mac resource template: */
246
                                piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,title, &event_id) + 2;
247
 
248
                                /* set up the PARM resource with saved parameters */
249
                                memcpy(pparm,&gdata->parm,sizeof(PARM_T));
250
 
251
                                /* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
252
                                aetesize = aete_generate(newaete, pparm, event_id);
253
 
276 daniel-mar 254
                                if (gdata->obfusc) {
255
                                        // Avoid that the same filter can generate with two seeds,
256
                                        // otherwise the comparison would be much easier
257
                                        obfuscseed = (unsigned int)get_parm_hash(pparm);
258
                                }
259
 
258 daniel-mar 260
                                // ====== Change Pascal strings to C-Strings
261
 
262
                                /* convert to C strings for Windows PARM resource */
263
                                // Don't do it before aete_generate, because they need Pascal strings
264
                                myp2cstr(pparm->category);
265
                                myp2cstr(pparm->title);
266
                                myp2cstr(pparm->copyright);
267
                                myp2cstr(pparm->author);
268
                                for (i = 0; i < 4; ++i)
269
                                        myp2cstr(pparm->map[i]);
270
                                for (i = 0; i < 8; ++i)
271
                                        myp2cstr(pparm->ctl[i]);
272
 
274 daniel-mar 273
                                manifestsize = domanifest(newmanifest, (const char*)manifestp, pparm, bits);
258 daniel-mar 274
 
275
                                // ====== Change version attributes
276
 
277
                                changeVersionInfo(dstname, pparm, hupdate);
278
 
279
                                // ====== Obfuscate pparm!
280
 
281
                                if(gdata->obfusc){
282
                                        parm_type = RT_RCDATA;
283
                                        parm_id = OBFUSCDATA_ID;
276 daniel-mar 284
 
285
                                        // Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
286
                                        obfusc(pparm, obfuscseed);
258 daniel-mar 287
                                }else{
288
                                        parm_type = "PARM";
289
                                        parm_id = PARM_ID;
290
                                }
291
 
292
                                // ====== Save AETE, PIPL, Manifest and PARM/RCDATA
293
 
294
                                /* Attention: The resource we have found using FindResource() might have a different
295
                                   language than the resource we are saving (Neutral), so we might end up having
296
                                   multiple languages for the same resource. Therefore, the language "Neutral" was
297
                                   set in the Scripting.rc file for the resource AETE and PIPL.rc for the resources PIPL. */
274 daniel-mar 298
 
299
                                if(_UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(50), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)
300
                                        && _UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)
301
                                        && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_BUILDDLG), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL, 0)
302
                                        && _UpdateResource(hupdate,"PIPL" /* note: caps!! */,MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
258 daniel-mar 303
                                        && _UpdateResource(hupdate, "AETE" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
304
                                        && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
305
                                        && _UpdateResource(hupdate,parm_type,MAKEINTRESOURCE(parm_id), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
306
                                {
307
                                        discard = false;
308
                                } else {
309
                                        dbglasterror(_strdup("UpdateResource"));
310
                                }
311
                        }
312
 
313
                }else dbglasterror(_strdup("Find-, Load- or LockResource"));
314
 
276 daniel-mar 315
                // Here, the file will be saved
258 daniel-mar 316
                if(!_EndUpdateResource(hupdate,discard))
317
                        dbglasterror(_strdup("EndUpdateResource"));
318
 
276 daniel-mar 319
                if (gdata->obfusc) {
320
                        // We modify the binary code to replace the deobfuscate-seed from OBFUSC_V4_DEFAULT_SEED to obfuscseed
321
                        if (binary_replace_file(dstname, OBFUSC_V4_DEFAULT_SEED, obfuscseed) <= 0) {
322
                                dbg("binary_replace_file failed");
323
                                discard = true;
324
                        }
325
                }
326
 
258 daniel-mar 327
                if(pparm) free(pparm);
328
                if(newpipl) free(newpipl);
329
                if(newaete) free(newaete);
330
        }else
331
                dbglasterror(_strdup("BeginUpdateResource"));
332
        return !discard;
333
}
334
 
274 daniel-mar 335
BOOL remove_64_filename_prefix(char* dstname) {
336
        // foobar.8bf => foobar.8bf
337
        // foobar64.8bf => foobar.8bf
276 daniel-mar 338
        size_t i;
274 daniel-mar 339
        for (i = strlen(dstname); i > 2; i--) {
340
                if (dstname[i] == '.') {
341
                        if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
276 daniel-mar 342
                                size_t tmp = strlen(dstname);
274 daniel-mar 343
                                memcpy(&dstname[i - 2], &dstname[i], strlen(dstname) - i + 1);
344
                                dstname[tmp - 2] = 0;
345
                                return true;
346
                        }
347
                }
348
        }
349
        return false;
350
}
351
 
352
BOOL add_64_filename_prefix(char* dstname) {
353
        // foobar.8bf => foobar64.8bf
276 daniel-mar 354
        size_t i;
274 daniel-mar 355
        for (i = strlen(dstname); i > 2; i--) {
356
                if (dstname[i] == '.') {
276 daniel-mar 357
                        size_t tmp = strlen(dstname);
274 daniel-mar 358
                        memcpy(&dstname[i + 2], &dstname[i], strlen(dstname) - i + 1);
359
                        dstname[i] = '6';
360
                        dstname[i + 1] = '4';
361
                        dstname[tmp + 2] = 0;
362
                        return true;
363
                }
364
        }
365
        return false;
366
}
367
 
368
BOOL FileExists(LPCTSTR szPath) {
369
        DWORD dwAttrib = GetFileAttributes(szPath);
370
        return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
371
                !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
372
}
373
 
374
BOOL Is32BitOperatingSystem() {
375
#ifdef _WIN64
376
        return false;
377
#else
378
        SYSTEM_INFO info;
379
        _GetNativeSystemInfo(&info);
380
        return info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
381
#endif
382
}
383
 
384
OSErr do_make_standalone(char* srcname, char* dstname, int bits) {
385
        Boolean res;
386
 
387
        //DeleteFile(dstname);
388
        if (CopyFile(srcname, dstname, false)) {
389
                HMODULE hSrcmod;
390
                hSrcmod = LoadLibraryEx(srcname, NULL, LOAD_LIBRARY_AS_DATAFILE);
391
                if (hSrcmod) {
392
                        res = doresources(hSrcmod, dstname, bits);
393
                        if (!res) {
394
                                DeleteFile(dstname);
395
                        }
396
                        FreeLibrary(hSrcmod);
397
                }
398
                else {
399
                        res = false;
400
                }
401
        }
402
        else {
403
                res = false;
404
        }
405
 
406
        if (!res) {
407
                char err[MAX_PATH + 200];
408
                sprintf(err, "Could not create %d bit standalone plugin.", bits);
409
                alertuser(_strdup(&err[0]), _strdup(""));
410
        }
411
 
412
        return res ? noErr : ioErr;
413
}
414
 
258 daniel-mar 415
OSErr make_standalone(StandardFileReply *sfr){
274 daniel-mar 416
        OSErr tmpErr, outErr;
258 daniel-mar 417
        char dstname[0x100],srcname[MAX_PATH+1];
418
 
419
        if (!isWin32NT()) {
420
                HMODULE hLib;
421
 
422
                hLib = LoadLibraryA("UNICOWS.DLL");
423
                if (!hLib) {
424
                        char* sysdir;
425
 
426
                        sysdir = (char*)malloc(MAX_PATH);
427
                        GetSystemDirectoryA(sysdir, MAX_PATH);
428
                        alertuser(_strdup("To build standalone plugins using this version of\nWindows, you need to install UNICOWS.DLL\n\nPlease download it from the Internet\nand place it into following directory:"), sysdir);
429
                        free(sysdir);
430
 
431
                        return false;
432
                }
433
                else {
434
                        FreeLibrary(hLib);
435
                }
436
        }
437
 
274 daniel-mar 438
        outErr = noErr;
258 daniel-mar 439
 
274 daniel-mar 440
#ifdef _WIN64
441
 
442
        //64 bit DLL makes 64 bit:
443
        // Source file = module filename
444
        GetModuleFileName(hDllInstance, srcname, MAX_PATH);
445
        // Destfile = no64_or_32(chosenname) + 64
446
        myp2cstrcpy(dstname, sfr->sfFile.name);
447
        remove_64_filename_prefix(dstname);
448
        add_64_filename_prefix(dstname);
449
        tmpErr = do_make_standalone(&srcname[0], &dstname[0], 64);
450
        if (tmpErr != noErr)
451
                outErr = tmpErr;
452
        else
453
                showmessage(_strdup("64 bit standalone filter was successfully created"));
454
 
455
        //64 bit DLL makes 32 bit:
456
        // Source file = no32(modulefilename)
457
        GetModuleFileName(hDllInstance, srcname, MAX_PATH);
458
        if (!remove_64_filename_prefix(srcname)) {
459
                char err[MAX_PATH + 200];
460
                sprintf(err, "Cannot create the %d bit version of this filter, because the 32-bit variant of this plugin could not be found", 32);
461
                alertuser(_strdup(&err[0]), _strdup(""));
258 daniel-mar 462
        }
274 daniel-mar 463
        else if (!FileExists(srcname)) {
464
                char err[MAX_PATH + 200];
465
                sprintf(err, "%s was not found. Therefore, the %d bit version of the standalone filter could not be created!", srcname, 32);
466
                alertuser(_strdup(&err[0]), _strdup(""));
467
        }
468
        else {
469
                // Destfile = no64_or_32(chosenname)
470
                myp2cstrcpy(dstname, sfr->sfFile.name);
471
                remove_64_filename_prefix(dstname);
472
                tmpErr = do_make_standalone(&srcname[0], &dstname[0], 32);
473
                if (tmpErr != noErr)
474
                        outErr = tmpErr;
475
                else
476
                        showmessage(_strdup("32 bit standalone filter was successfully created"));
477
}
258 daniel-mar 478
 
274 daniel-mar 479
#else
480
 
481
        //32 bit DLL makes 32 bit:
482
        // Source file = module filename
483
        GetModuleFileName(hDllInstance, srcname, MAX_PATH);
484
        // Destfile = no64_or_32(chosenname)
485
        myp2cstrcpy(dstname, sfr->sfFile.name);
486
        remove_64_filename_prefix(dstname);
487
        tmpErr = do_make_standalone(&srcname[0], &dstname[0], 32);
488
        if (tmpErr != noErr)
489
                outErr = tmpErr;
490
        else
491
                showmessage(_strdup("32 bit standalone filter was successfully created"));
492
 
493
        if (!Is32BitOperatingSystem()) {
494
                //32 bit DLL makes 64 bit:
495
                // Source file = module filename + 64
496
                GetModuleFileName(hDllInstance, srcname, MAX_PATH);
497
                add_64_filename_prefix(srcname);
498
                if (!FileExists(srcname)) {
499
                        char err[MAX_PATH + 200];
500
                        sprintf(err, "%s was not found. Therefore, the %d bit version of the standalone filter could not be created!", srcname, 64);
501
                        alertuser(_strdup(&err[0]), _strdup(""));
502
                }
503
                else {
504
                        // Destfile = no64_or_32(chosenname) + 64
505
                        myp2cstrcpy(dstname, sfr->sfFile.name);
506
                        remove_64_filename_prefix(dstname);
507
                        add_64_filename_prefix(dstname);
508
                        tmpErr = do_make_standalone(&srcname[0], &dstname[0], 64);
509
                        if (tmpErr != noErr)
510
                                outErr = tmpErr;
511
                        else
512
                                showmessage(_strdup("64 bit standalone filter was successfully created"));
513
                }
514
        }
515
#endif
516
 
517
        return outErr;
258 daniel-mar 518
}