Subversion Repositories filter_foundry

Rev

Rev 271 | Rev 276 | 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;
55
        int iname = 0;
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
 
274 daniel-mar 175
Boolean doresources(HMODULE srcmod,char *dstname, int bits){
258 daniel-mar 176
        HRSRC datarsrc,aetersrc,manifestsrc;
177
        HGLOBAL datah,aeteh,hupdate,manifesth;
178
        Ptr newpipl = NULL, newaete = NULL;
179
        LPVOID datap, aetep, manifestp;
180
        PARM_T *pparm = NULL;
181
        size_t piplsize,aetesize,origsize,manifestsize;
182
        Str255 title;
183
        LPCTSTR parm_type;
184
        int i,parm_id;
185
        Boolean discard = true;
268 daniel-mar 186
 
258 daniel-mar 187
        long event_id;
188
 
189
//      if(!EnumResourceLanguages(srcmod,"PiPL",MAKEINTRESOURCE(16000),enumfunc,0))
190
//            dbglasterror("EnumResourceLanguages");
191
 
192
        if( (hupdate = _BeginUpdateResource(dstname,false)) ){
193
                DBG("BeginUpdateResource OK");
194
                if( (datarsrc = FindResource(srcmod,MAKEINTRESOURCE(16000),"TPLT"))
195
                        && (datah = LoadResource(srcmod,datarsrc))
196
                        && (datap = (Ptr)LockResource(datah))
197
                        && (aetersrc = FindResource(srcmod, MAKEINTRESOURCE(16000), "AETE"))
198
                        && (aeteh = LoadResource(srcmod, aetersrc))
199
                        && (aetep = (Ptr)LockResource(aeteh))
200
                        && (manifestsrc = FindResource(srcmod, MAKEINTRESOURCE(50), "TPLT"))
201
                        && (manifesth = LoadResource(srcmod, manifestsrc))
202
                        && (manifestp = (Ptr)LockResource(manifesth)) )
203
                {
204
                        char newmanifest[5000];
205
 
206
                        DBG("loaded DATA, PiPL");
207
 
208
                        PLstrcpy(title,gdata->parm.title);
209
                        if(gdata->parm.popDialog)
210
                                PLstrcat(title,(StringPtr)"\003...");
211
 
212
                        origsize = SizeofResource(srcmod,datarsrc);
213
 
214
                        if( (newpipl = (Ptr)malloc(origsize+0x300))
215
                         && (newaete = (Ptr)malloc(4096))
216
                         && (pparm = (PARM_T*)malloc(sizeof(PARM_T))) )
217
                        {
218
                                // ====== Generate AETE and PIPL
219
 
220
                                /* add user-specified title and category to new PiPL */
221
                                memcpy(newpipl,datap,origsize);
222
                                /* note that Windows PiPLs have 2 byte version datum in front
223
                                   that isn't reflected in struct definition or Mac resource template: */
224
                                piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,title, &event_id) + 2;
225
 
226
                                /* set up the PARM resource with saved parameters */
227
                                memcpy(pparm,&gdata->parm,sizeof(PARM_T));
228
 
229
                                /* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
230
                                aetesize = aete_generate(newaete, pparm, event_id);
231
 
232
                                // ====== Change Pascal strings to C-Strings
233
 
234
                                /* convert to C strings for Windows PARM resource */
235
                                // Don't do it before aete_generate, because they need Pascal strings
236
                                myp2cstr(pparm->category);
237
                                myp2cstr(pparm->title);
238
                                myp2cstr(pparm->copyright);
239
                                myp2cstr(pparm->author);
240
                                for (i = 0; i < 4; ++i)
241
                                        myp2cstr(pparm->map[i]);
242
                                for (i = 0; i < 8; ++i)
243
                                        myp2cstr(pparm->ctl[i]);
244
 
274 daniel-mar 245
                                manifestsize = domanifest(newmanifest, (const char*)manifestp, pparm, bits);
258 daniel-mar 246
 
247
                                // ====== Change version attributes
248
 
249
                                changeVersionInfo(dstname, pparm, hupdate);
250
 
251
                                // ====== Obfuscate pparm!
252
 
253
                                if(gdata->obfusc){
254
                                        parm_type = RT_RCDATA;
255
                                        parm_id = OBFUSCDATA_ID;
271 daniel-mar 256
                                        obfusc(pparm);
258 daniel-mar 257
                                }else{
258
                                        parm_type = "PARM";
259
                                        parm_id = PARM_ID;
260
                                }
261
 
262
                                // ====== Save AETE, PIPL, Manifest and PARM/RCDATA
263
 
264
                                /* Attention: The resource we have found using FindResource() might have a different
265
                                   language than the resource we are saving (Neutral), so we might end up having
266
                                   multiple languages for the same resource. Therefore, the language "Neutral" was
267
                                   set in the Scripting.rc file for the resource AETE and PIPL.rc for the resources PIPL. */
274 daniel-mar 268
 
269
                                if(_UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(50), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)
270
                                        && _UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)
271
                                        && _UpdateResource(hupdate, RT_DIALOG, MAKEINTRESOURCE(ID_BUILDDLG), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), NULL, 0)
272
                                        && _UpdateResource(hupdate,"PIPL" /* note: caps!! */,MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
258 daniel-mar 273
                                        && _UpdateResource(hupdate, "AETE" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
274
                                        && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
275
                                        && _UpdateResource(hupdate,parm_type,MAKEINTRESOURCE(parm_id), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
276
                                {
277
                                        discard = false;
278
                                } else {
279
                                        dbglasterror(_strdup("UpdateResource"));
280
                                }
281
                        }
282
 
283
                }else dbglasterror(_strdup("Find-, Load- or LockResource"));
284
 
285
                if(!_EndUpdateResource(hupdate,discard))
286
                        dbglasterror(_strdup("EndUpdateResource"));
287
 
288
                if(pparm) free(pparm);
289
                if(newpipl) free(newpipl);
290
                if(newaete) free(newaete);
291
        }else
292
                dbglasterror(_strdup("BeginUpdateResource"));
293
        return !discard;
294
}
295
 
274 daniel-mar 296
BOOL remove_64_filename_prefix(char* dstname) {
297
        // foobar.8bf => foobar.8bf
298
        // foobar64.8bf => foobar.8bf
299
        int i;
300
        for (i = strlen(dstname); i > 2; i--) {
301
                if (dstname[i] == '.') {
302
                        if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
303
                                int tmp = strlen(dstname);
304
                                memcpy(&dstname[i - 2], &dstname[i], strlen(dstname) - i + 1);
305
                                dstname[tmp - 2] = 0;
306
                                return true;
307
                        }
308
                }
309
        }
310
        return false;
311
}
312
 
313
BOOL add_64_filename_prefix(char* dstname) {
314
        // foobar.8bf => foobar64.8bf
315
        int i;
316
        for (i = strlen(dstname); i > 2; i--) {
317
                if (dstname[i] == '.') {
318
                        int tmp = strlen(dstname);
319
                        memcpy(&dstname[i + 2], &dstname[i], strlen(dstname) - i + 1);
320
                        dstname[i] = '6';
321
                        dstname[i + 1] = '4';
322
                        dstname[tmp + 2] = 0;
323
                        return true;
324
                }
325
        }
326
        return false;
327
}
328
 
329
BOOL FileExists(LPCTSTR szPath) {
330
        DWORD dwAttrib = GetFileAttributes(szPath);
331
        return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
332
                !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
333
}
334
 
335
BOOL Is32BitOperatingSystem() {
336
#ifdef _WIN64
337
        return false;
338
#else
339
        SYSTEM_INFO info;
340
        _GetNativeSystemInfo(&info);
341
        return info.wProcessorArchitecture == PROCESSOR_ARCHITECTURE_INTEL;
342
#endif
343
}
344
 
345
OSErr do_make_standalone(char* srcname, char* dstname, int bits) {
346
        Boolean res;
347
 
348
        //DeleteFile(dstname);
349
        if (CopyFile(srcname, dstname, false)) {
350
                HMODULE hSrcmod;
351
                hSrcmod = LoadLibraryEx(srcname, NULL, LOAD_LIBRARY_AS_DATAFILE);
352
                if (hSrcmod) {
353
                        res = doresources(hSrcmod, dstname, bits);
354
                        if (!res) {
355
                                DeleteFile(dstname);
356
                        }
357
                        FreeLibrary(hSrcmod);
358
                }
359
                else {
360
                        res = false;
361
                }
362
        }
363
        else {
364
                res = false;
365
        }
366
 
367
        if (!res) {
368
                char err[MAX_PATH + 200];
369
                sprintf(err, "Could not create %d bit standalone plugin.", bits);
370
                alertuser(_strdup(&err[0]), _strdup(""));
371
        }
372
 
373
        return res ? noErr : ioErr;
374
}
375
 
258 daniel-mar 376
OSErr make_standalone(StandardFileReply *sfr){
274 daniel-mar 377
        OSErr tmpErr, outErr;
258 daniel-mar 378
        char dstname[0x100],srcname[MAX_PATH+1];
379
 
380
        if (!isWin32NT()) {
381
                HMODULE hLib;
382
 
383
                hLib = LoadLibraryA("UNICOWS.DLL");
384
                if (!hLib) {
385
                        char* sysdir;
386
 
387
                        sysdir = (char*)malloc(MAX_PATH);
388
                        GetSystemDirectoryA(sysdir, MAX_PATH);
389
                        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);
390
                        free(sysdir);
391
 
392
                        return false;
393
                }
394
                else {
395
                        FreeLibrary(hLib);
396
                }
397
        }
398
 
274 daniel-mar 399
        outErr = noErr;
258 daniel-mar 400
 
274 daniel-mar 401
#ifdef _WIN64
402
 
403
        //64 bit DLL makes 64 bit:
404
        // Source file = module filename
405
        GetModuleFileName(hDllInstance, srcname, MAX_PATH);
406
        // Destfile = no64_or_32(chosenname) + 64
407
        myp2cstrcpy(dstname, sfr->sfFile.name);
408
        remove_64_filename_prefix(dstname);
409
        add_64_filename_prefix(dstname);
410
        tmpErr = do_make_standalone(&srcname[0], &dstname[0], 64);
411
        if (tmpErr != noErr)
412
                outErr = tmpErr;
413
        else
414
                showmessage(_strdup("64 bit standalone filter was successfully created"));
415
 
416
        //64 bit DLL makes 32 bit:
417
        // Source file = no32(modulefilename)
418
        GetModuleFileName(hDllInstance, srcname, MAX_PATH);
419
        if (!remove_64_filename_prefix(srcname)) {
420
                char err[MAX_PATH + 200];
421
                sprintf(err, "Cannot create the %d bit version of this filter, because the 32-bit variant of this plugin could not be found", 32);
422
                alertuser(_strdup(&err[0]), _strdup(""));
258 daniel-mar 423
        }
274 daniel-mar 424
        else if (!FileExists(srcname)) {
425
                char err[MAX_PATH + 200];
426
                sprintf(err, "%s was not found. Therefore, the %d bit version of the standalone filter could not be created!", srcname, 32);
427
                alertuser(_strdup(&err[0]), _strdup(""));
428
        }
429
        else {
430
                // Destfile = no64_or_32(chosenname)
431
                myp2cstrcpy(dstname, sfr->sfFile.name);
432
                remove_64_filename_prefix(dstname);
433
                tmpErr = do_make_standalone(&srcname[0], &dstname[0], 32);
434
                if (tmpErr != noErr)
435
                        outErr = tmpErr;
436
                else
437
                        showmessage(_strdup("32 bit standalone filter was successfully created"));
438
}
258 daniel-mar 439
 
274 daniel-mar 440
#else
441
 
442
        //32 bit DLL makes 32 bit:
443
        // Source file = module filename
444
        GetModuleFileName(hDllInstance, srcname, MAX_PATH);
445
        // Destfile = no64_or_32(chosenname)
446
        myp2cstrcpy(dstname, sfr->sfFile.name);
447
        remove_64_filename_prefix(dstname);
448
        tmpErr = do_make_standalone(&srcname[0], &dstname[0], 32);
449
        if (tmpErr != noErr)
450
                outErr = tmpErr;
451
        else
452
                showmessage(_strdup("32 bit standalone filter was successfully created"));
453
 
454
        if (!Is32BitOperatingSystem()) {
455
                //32 bit DLL makes 64 bit:
456
                // Source file = module filename + 64
457
                GetModuleFileName(hDllInstance, srcname, MAX_PATH);
458
                add_64_filename_prefix(srcname);
459
                if (!FileExists(srcname)) {
460
                        char err[MAX_PATH + 200];
461
                        sprintf(err, "%s was not found. Therefore, the %d bit version of the standalone filter could not be created!", srcname, 64);
462
                        alertuser(_strdup(&err[0]), _strdup(""));
463
                }
464
                else {
465
                        // Destfile = no64_or_32(chosenname) + 64
466
                        myp2cstrcpy(dstname, sfr->sfFile.name);
467
                        remove_64_filename_prefix(dstname);
468
                        add_64_filename_prefix(dstname);
469
                        tmpErr = do_make_standalone(&srcname[0], &dstname[0], 64);
470
                        if (tmpErr != noErr)
471
                                outErr = tmpErr;
472
                        else
473
                                showmessage(_strdup("64 bit standalone filter was successfully created"));
474
                }
475
        }
476
#endif
477
 
478
        return outErr;
258 daniel-mar 479
}