Subversion Repositories filter_foundry

Rev

Rev 318 | Rev 320 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
258 daniel-mar 1
/*
2
    This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
4
    Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
5
 
6
    This program is free software; you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation; either version 2 of the License, or
9
    (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with this program; if not, write to the Free Software
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
*/
20
 
21
#include "ff.h"
22
 
278 daniel-mar 23
#include <time.h>
24
 
258 daniel-mar 25
#include "file_compat.h"
26
#include "compat_string.h"
27
#include "versioninfo_modify_win.h"
28
#include "version.h"
29
 
30
extern HINSTANCE hDllInstance;
31
 
274 daniel-mar 32
Boolean doresources(HMODULE srcmod,char *dstname, int bits);
258 daniel-mar 33
 
34
void dbglasterror(char *func){
35
        char s[0x100];
36
 
37
        strcpy(s,func);
38
        strcat(s," failed: ");
319 daniel-mar 39
        // TODO: Also translate Win32 error to use readable text ( https://docs.microsoft.com/en-us/windows/win32/debug/retrieving-the-last-error-code )
258 daniel-mar 40
        FormatMessage( FORMAT_MESSAGE_FROM_SYSTEM,NULL,GetLastError(),0,s+strlen(s),0x100,NULL );
41
        dbg(s);
42
}
43
 
44
/*
45
BOOL CALLBACK enumfunc(HMODULE hModule,LPCTSTR lpszType,LPCTSTR lpszName,WORD wIDLanguage,LONG lParam){
46
        char s[0x100];
47
        sprintf(s,"EnumResourceLanguages callback: module=%#x type=%s name=%s lang=%d",
48
                hModule,lpszType,lpszName,wIDLanguage);
49
        dbg(s);
50
        return TRUE;
51
}
52
*/
53
 
274 daniel-mar 54
int domanifest(char *newmanifest, const char *manifestp, PARM_T* pparm, int bits) {
258 daniel-mar 55
        char name[1024];
56
        char description[1024];
57
        size_t i;
276 daniel-mar 58
        size_t iname = 0;
258 daniel-mar 59
        int idescription = 0;
60
 
61
        // Description
62
        for (i = 0; i < strlen((char*)pparm->category); i++) {
63
                char c = pparm->category[i];
64
                if ((c != '<') && (c != '>')) {
65
                        description[idescription++] = c;
66
                }
67
        }
68
        description[idescription++] = ' ';
69
        description[idescription++] = '-';
70
        description[idescription++] = ' ';
71
        for (i = 0; i < strlen((char*)pparm->title); i++) {
72
                char c = pparm->title[i];
73
                if ((c != '<') && (c != '>')) {
74
                        description[idescription++] = c;
75
                }
76
        }
77
        description[idescription++] = '\0';
78
 
79
        // Name
80
        strcpy(name, "Telegraphics.FilterFoundry.");
81
        iname = strlen("Telegraphics.FilterFoundry.");
82
        for (i = 0; i < strlen((char*)pparm->category); i++) {
83
                char c = pparm->category[i];
84
                if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) {
85
                        name[iname++] = c;
86
                }
87
        }
88
        name[iname++] = '.';
89
        for (i = 0; i < strlen((char*)pparm->title); i++) {
90
                char c = pparm->title[i];
91
                if (((c >= 'A') && (c <= 'Z')) || ((c >= 'a') && (c <= 'z'))) {
92
                        name[iname++] = c;
93
                }
94
        }
95
        name[iname++] = '\0';
96
 
274 daniel-mar 97
        if (bits == 64) {
98
                return sprintf(newmanifest, manifestp, (char*)name, "amd64", VERSION_STR, (char*)description);
99
        }
100
        else {
101
                return sprintf(newmanifest, manifestp, (char*)name, "x86", VERSION_STR, (char*)description);
102
        }
258 daniel-mar 103
}
104
 
105
void changeVersionInfo(char* dstname, PARM_T* pparm, HGLOBAL hupdate) {
106
        char* soleFilename;
107
        LPWSTR changeRequestStr, tmp;
108
 
109
        if (soleFilename = strrchr(dstname, '\\')) {
110
                ++soleFilename;
111
        }
112
        else {
113
                soleFilename = dstname;
114
        }
115
 
116
        // Format of argument "PCWSTR changes" is "<name>\0<value>\0<name>\0<value>\0....."
117
        // You can CHANGE values for any given name
118
        // You can DELETE entries by setting the value to "\b" (0x08 backspace character)
119
        // You cannot (yet) ADD entries.
120
        changeRequestStr = (LPWSTR)malloc(6 * 2 * 100 + 1);
121
 
122
        tmp = changeRequestStr;
123
 
124
        tmp += mbstowcs(tmp, "Comments", 100);
125
        tmp++;
126
        tmp += mbstowcs(tmp, "Built using Filter Foundry " VERSION_STR, 100);
127
        tmp++;
128
 
129
        tmp += mbstowcs(tmp, "CompanyName", 100);
130
        tmp++;
131
        if (strlen((char*)pparm->author) > 0) {
132
                tmp += mbstowcs(tmp, (char*)pparm->author, 100);
133
        }
134
        else {
135
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
136
        }
137
        tmp++;
138
 
139
        tmp += mbstowcs(tmp, "LegalCopyright", 100);
140
        tmp++;
141
        if (strlen((char*)pparm->copyright) > 0) {
142
                tmp += mbstowcs(tmp, (char*)pparm->copyright, 100);
143
        }
144
        else {
145
                tmp += mbstowcs(tmp, "\b", 100); // \b = remove
146
        }
147
        tmp++;
148
 
149
        tmp += mbstowcs(tmp, "FileDescription", 100);
150
        tmp++;
151
        if (strlen((char*)pparm->title) > 0) {
152
                tmp += mbstowcs(tmp, (char*)pparm->title, 100);
153
        }
154
        else {
155
                tmp += mbstowcs(tmp, "Untitled filter", 100);
156
        }
157
        tmp++;
158
 
159
        tmp += mbstowcs(tmp, "OriginalFilename", 100);
160
        tmp++;
161
        tmp += mbstowcs(tmp, soleFilename, 100);
162
        tmp++;
163
 
164
        tmp += mbstowcs(tmp, "License", 100);
165
        tmp++;
166
        tmp += mbstowcs(tmp, "\b", 100); // \b = remove, since filter is standalone and might have its own license
167
        tmp++;
168
 
169
        tmp += mbstowcs(tmp, "", 1);
170
 
171
        if (UpdateVersionInfoWithHandle(dstname, hupdate, changeRequestStr) != NOERROR) {
315 daniel-mar 172
                simplealert(_strdup("UpdateVersionInfoWithHandle failed"));
258 daniel-mar 173
        }
174
 
175
        free(changeRequestStr);
176
}
177
 
278 daniel-mar 178
Boolean update_pe_timestamp(const char* filename, time_t timestamp) {
280 daniel-mar 179
        size_t peoffset;
180
        FILE* fptr;
181
 
182
        fptr = fopen(filename, "rb+");
278 daniel-mar 183
        if (fptr == NULL) return false;
184
 
185
        fseek(fptr, 0x3C, SEEK_SET);
186
        fread(&peoffset, sizeof(peoffset), 1, fptr);
187
 
280 daniel-mar 188
        fseek(fptr, (long)peoffset + 8, SEEK_SET);
278 daniel-mar 189
        fwrite(&timestamp, sizeof(time_t), 1, fptr);
190
 
191
        fclose(fptr);
192
 
193
        return true;
194
}
195
 
276 daniel-mar 196
int binary_replace_file(const char* filename, unsigned int search, unsigned int replace) {
197
        unsigned int srecord = 0;
198
        int found = 0;
199
 
200
        FILE* fptr = fopen(filename, "rb+");
201
        if (fptr == NULL) return -1;
202
 
203
        while ((fread(&srecord, sizeof(srecord), 1, fptr) == 1))
204
        {
205
                if (srecord == search) {
206
                        srecord = replace;
207
                        fseek(fptr, -1*(long)sizeof(srecord), SEEK_CUR);
208
                        fwrite(&srecord, (int)sizeof(srecord), 1, fptr);
209
                        fseek(fptr, 0, SEEK_CUR); // important!
210
                        found++;
211
                }
212
                else {
213
                        fseek(fptr, -1*(long)(sizeof(srecord) - 1), SEEK_CUR);
214
                }
215
        }
216
        fclose(fptr);
217
 
218
        return found;
219
}
220
 
281 daniel-mar 221
//DOS .EXE header
222
struct image_dos_header
223
{
224
        uint16_t e_magic;                     // Magic number
225
        uint16_t e_cblp;                      // Bytes on last page of file
226
        uint16_t e_cp;                        // Pages in file
227
        uint16_t e_crlc;                      // Relocations
228
        uint16_t e_cparhdr;                   // Size of header in paragraphs
229
        uint16_t e_minalloc;                  // Minimum extra paragraphs needed
230
        uint16_t e_maxalloc;                  // Maximum extra paragraphs needed
231
        uint16_t e_ss;                        // Initial (relative) SS value
232
        uint16_t e_sp;                        // Initial SP value
233
        uint16_t e_csum;                      // Checksum
234
        uint16_t e_ip;                        // Initial IP value
235
        uint16_t e_cs;                        // Initial (relative) CS value
236
        uint16_t e_lfarlc;                    // File address of relocation table
237
        uint16_t e_ovno;                      // Overlay number
238
        uint16_t e_res[4];                    // Reserved words
239
        uint16_t e_oemid;                     // OEM identifier (for e_oeminfo)
240
        uint16_t e_oeminfo;                   // OEM information; e_oemid specific
241
        uint16_t e_res2[10];                  // Reserved words
242
        int32_t  e_lfanew;                    // File address of new exe header
243
};
244
 
245
struct image_file_header
246
{
247
        uint16_t Machine;
248
        uint16_t NumberOfSections;
249
        uint32_t TimeDateStamp;
250
        uint32_t PointerToSymbolTable;
251
        uint32_t NumberOfSymbols;
252
        uint16_t SizeOfOptionalHeader;
253
        uint16_t Characteristics;
254
};
255
 
256
uint32_t calculate_checksum(const char* filename) {
257
        //Calculate checksum of image
258
        // Taken from "PE Bliss" Cross-Platform Portable Executable C++ Library
259
        // https://github.com/mrexodia/portable-executable-library/blob/master/pe_lib/pe_checksum.cpp
260
        // Converted from C++ to C by Daniel Marschall
261
 
262
        FILE* fptr;
263
        unsigned long long checksum = 0;
264
        struct image_dos_header header;
265
        size_t filesize;
266
        unsigned long long top;
267
        unsigned long pe_checksum_pos;
268
        static const unsigned long checksum_pos_in_optional_headers = 64;
269
        size_t i;
270
 
271
        fptr = fopen(filename, "rb");
272
        if (fptr == NULL) return 0x00000000;
273
 
274
        //Read DOS header
275
        fseek(fptr, 0, SEEK_SET);
276
        fread(&header, sizeof(struct image_dos_header), 1, fptr);
277
 
278
        //Calculate PE checksum
279
        fseek(fptr, 0, SEEK_SET);
280
        top = 0xFFFFFFFF;
281
        top++;
282
 
283
        //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+
284
        //Calculate real PE headers "CheckSum" field position
285
        //Sum is safe here
286
        pe_checksum_pos = header.e_lfanew + sizeof(struct image_file_header) + sizeof(uint32_t) + checksum_pos_in_optional_headers;
287
 
288
        //Calculate checksum for each byte of file
289
        fseek(fptr, 0L, SEEK_END);
290
        filesize = ftell(fptr);
291
        fseek(fptr, 0L, SEEK_SET);
292
        for (i = 0; i < filesize; i += 4)
293
        {
294
                unsigned long dw = 0;
295
 
296
                //Read DWORD from file
297
                fread(&dw, sizeof(dw), 1, fptr);
298
                //Skip "CheckSum" DWORD
299
                if (i == pe_checksum_pos)
300
                        continue;
301
 
302
                //Calculate checksum
303
                checksum = (checksum & 0xffffffff) + dw + (checksum >> 32);
304
                if (checksum > top)
305
                        checksum = (checksum & 0xffffffff) + (checksum >> 32);
306
        }
307
 
308
        //Finish checksum
309
        checksum = (checksum & 0xffff) + (checksum >> 16);
310
        checksum = (checksum)+(checksum >> 16);
311
        checksum = checksum & 0xffff;
312
 
313
        checksum += (unsigned long)(filesize);
314
 
315
        fclose(fptr);
316
 
317
        //Return checksum
318
        return (uint32_t)checksum;
319
}
320
 
321
Boolean repair_pe_checksum(const char* filename) {
322
        size_t peoffset;
323
        FILE* fptr;
324
 
325
        uint32_t checksum = calculate_checksum(filename);
326
        //if (checksum == 0x00000000) return false;
327
 
328
        fptr = fopen(filename, "rb+");
329
        if (fptr == NULL) return false;
330
 
331
        fseek(fptr, 0x3C, SEEK_SET);
332
        fread(&peoffset, sizeof(peoffset), 1, fptr);
333
 
334
        fseek(fptr, (long)peoffset + 88, SEEK_SET);
335
        fwrite(&checksum, sizeof(uint32_t), 1, fptr);
336
 
337
        fclose(fptr);
338
 
339
        return true;
340
}
341
 
274 daniel-mar 342
Boolean doresources(HMODULE srcmod,char *dstname, int bits){
258 daniel-mar 343
        HRSRC datarsrc,aetersrc,manifestsrc;
344
        HGLOBAL datah,aeteh,hupdate,manifesth;
345
        Ptr newpipl = NULL, newaete = NULL;
346
        LPVOID datap, aetep, manifestp;
347
        PARM_T *pparm = NULL;
348
        size_t piplsize,aetesize,origsize,manifestsize;
349
        Str255 title;
350
        LPCTSTR parm_type;
351
        int i,parm_id;
352
        Boolean discard = true;
276 daniel-mar 353
        unsigned int obfuscseed = 0;
258 daniel-mar 354
        long event_id;
319 daniel-mar 355
        Boolean mustFreeSrcMod;
258 daniel-mar 356
 
319 daniel-mar 357
        if (srcmod == NULL) {
358
                srcmod = LoadLibraryEx(dstname, NULL, LOAD_LIBRARY_AS_DATAFILE);
359
                if (!srcmod) {
360
                        dbglasterror(_strdup("LoadLibraryEx"));
361
                        return false;
362
                }
363
                mustFreeSrcMod = true;
364
        }
365
        else {
366
                mustFreeSrcMod = false;
367
        }
368
 
258 daniel-mar 369
        if( (hupdate = _BeginUpdateResource(dstname,false)) ){
370
                DBG("BeginUpdateResource OK");
308 daniel-mar 371
                if( (datarsrc = FindResource(srcmod,MAKEINTRESOURCE(16000), "TPLT"))
258 daniel-mar 372
                        && (datah = LoadResource(srcmod,datarsrc))
373
                        && (datap = (Ptr)LockResource(datah))
374
                        && (aetersrc = FindResource(srcmod, MAKEINTRESOURCE(16000), "AETE"))
375
                        && (aeteh = LoadResource(srcmod, aetersrc))
376
                        && (aetep = (Ptr)LockResource(aeteh))
377
                        && (manifestsrc = FindResource(srcmod, MAKEINTRESOURCE(50), "TPLT"))
378
                        && (manifesth = LoadResource(srcmod, manifestsrc))
379
                        && (manifestp = (Ptr)LockResource(manifesth)) )
380
                {
381
                        char newmanifest[5000];
382
 
383
                        DBG("loaded DATA, PiPL");
384
 
385
                        PLstrcpy(title,gdata->parm.title);
386
                        if(gdata->parm.popDialog)
387
                                PLstrcat(title,(StringPtr)"\003...");
388
 
389
                        origsize = SizeofResource(srcmod,datarsrc);
390
 
391
                        if( (newpipl = (Ptr)malloc(origsize+0x300))
392
                         && (newaete = (Ptr)malloc(4096))
393
                         && (pparm = (PARM_T*)malloc(sizeof(PARM_T))) )
394
                        {
395
                                // ====== Generate AETE and PIPL
396
 
397
                                /* add user-specified title and category to new PiPL */
398
                                memcpy(newpipl,datap,origsize);
399
                                /* note that Windows PiPLs have 2 byte version datum in front
400
                                   that isn't reflected in struct definition or Mac resource template: */
401
                                piplsize = fixpipl((PIPropertyList*)(newpipl+2),origsize-2,title, &event_id) + 2;
402
 
403
                                /* set up the PARM resource with saved parameters */
404
                                memcpy(pparm,&gdata->parm,sizeof(PARM_T));
405
 
406
                                /* Generate 'aete' resource (contains names of the parameters for the "Actions" tab in Photoshop) */
407
                                aetesize = aete_generate(newaete, pparm, event_id);
408
 
409
                                // ====== Change Pascal strings to C-Strings
410
 
411
                                /* convert to C strings for Windows PARM resource */
412
                                // Don't do it before aete_generate, because they need Pascal strings
413
                                myp2cstr(pparm->category);
414
                                myp2cstr(pparm->title);
415
                                myp2cstr(pparm->copyright);
416
                                myp2cstr(pparm->author);
417
                                for (i = 0; i < 4; ++i)
418
                                        myp2cstr(pparm->map[i]);
419
                                for (i = 0; i < 8; ++i)
420
                                        myp2cstr(pparm->ctl[i]);
421
 
274 daniel-mar 422
                                manifestsize = domanifest(newmanifest, (const char*)manifestp, pparm, bits);
258 daniel-mar 423
 
424
                                // ====== Change version attributes
425
 
426
                                changeVersionInfo(dstname, pparm, hupdate);
427
 
428
                                // ====== Obfuscate pparm!
429
 
292 daniel-mar 430
                                if (gdata->obfusc) {
258 daniel-mar 431
                                        parm_type = RT_RCDATA;
432
                                        parm_id = OBFUSCDATA_ID;
276 daniel-mar 433
 
434
                                        // Note: After we have finished updating the resources, we will write <obfuscseed> into the binary code of the 8BF file
292 daniel-mar 435
                                        obfuscseed = obfusc(pparm);
258 daniel-mar 436
                                }else{
437
                                        parm_type = "PARM";
438
                                        parm_id = PARM_ID;
439
                                }
440
 
441
                                // ====== Save AETE, PIPL, Manifest and PARM/RCDATA
442
 
443
                                /* Attention: The resource we have found using FindResource() might have a different
444
                                   language than the resource we are saving (Neutral), so we might end up having
445
                                   multiple languages for the same resource. Therefore, the language "Neutral" was
446
                                   set in the Scripting.rc file for the resource AETE and PIPL.rc for the resources PIPL. */
274 daniel-mar 447
 
308 daniel-mar 448
                                if(_UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(50), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0)  // clean up things we don't need in the standalone plugin
449
                                        && _UpdateResource(hupdate, "TPLT" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
450
                                        && _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
451
                                        && _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
452
                                        && _UpdateResource(hupdate, RT_GROUP_ICON, "CAUTION_ICO", MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
453
                                        && _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
454
                                        && _UpdateResource(hupdate, RT_GROUP_CURSOR, MAKEINTRESOURCE(IDC_FF_HAND_QUESTION), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
455
                                        && _UpdateResource(hupdate, RT_CURSOR, MAKEINTRESOURCE(6)/*QuestionHand*/, MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), NULL, 0) // clean up things we don't need in the standalone plugin
456
                                        && _UpdateResource(hupdate, "PIPL" /* note: caps!! */,MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),newpipl,(DWORD)piplsize)
258 daniel-mar 457
                                        && _UpdateResource(hupdate, "AETE" /* note: caps!! */, MAKEINTRESOURCE(16000), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newaete, (DWORD)aetesize)
458
                                        && _UpdateResource(hupdate, RT_MANIFEST, MAKEINTRESOURCE(1), MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL), newmanifest, (DWORD)manifestsize)
308 daniel-mar 459
                                        && _UpdateResource(hupdate, parm_type,MAKEINTRESOURCE(parm_id), MAKELANGID(LANG_NEUTRAL,SUBLANG_NEUTRAL),pparm,sizeof(PARM_T)) )
258 daniel-mar 460
                                {
461
                                        discard = false;
462
                                } else {
463
                                        dbglasterror(_strdup("UpdateResource"));
464
                                }
465
                        }
466
 
467
                }else dbglasterror(_strdup("Find-, Load- or LockResource"));
468
 
276 daniel-mar 469
                // Here, the file will be saved
319 daniel-mar 470
                if (mustFreeSrcMod) {
471
                        FreeLibrary(srcmod);
472
                }
473
                if (!_EndUpdateResource(hupdate, discard)) {
258 daniel-mar 474
                        dbglasterror(_strdup("EndUpdateResource"));
319 daniel-mar 475
                }
476
                else {
258 daniel-mar 477
 
319 daniel-mar 478
                        if (gdata->obfusc) {
479
                                // We modify the binary code to replace the deobfuscate-seed from <cObfuscV4Seed> to <obfuscseed>
480
                                if (binary_replace_file(dstname, cObfuscV4Seed, obfuscseed) != 1) {
481
                                        // The seed must only be exactly 1 time inside the 8BF file,
482
                                        // since "const volatile" makes sure that the compiler won't place
483
                                        // it at several locations in the code.
484
                                        dbg("binary_replace_file failed");
485
                                        discard = true;
486
                                }
276 daniel-mar 487
                        }
488
 
319 daniel-mar 489
                        update_pe_timestamp(dstname, time(0));
278 daniel-mar 490
 
319 daniel-mar 491
                        repair_pe_checksum(dstname);
492
                }
493
 
258 daniel-mar 494
                if(pparm) free(pparm);
495
                if(newpipl) free(newpipl);
496
                if(newaete) free(newaete);
497
        }else
498
                dbglasterror(_strdup("BeginUpdateResource"));
499
        return !discard;
500
}
501
 
278 daniel-mar 502
Boolean remove_64_filename_prefix(char* dstname) {
274 daniel-mar 503
        // foobar.8bf => foobar.8bf
504
        // foobar64.8bf => foobar.8bf
276 daniel-mar 505
        size_t i;
274 daniel-mar 506
        for (i = strlen(dstname); i > 2; i--) {
507
                if (dstname[i] == '.') {
508
                        if ((dstname[i - 2] == '6') && (dstname[i - 1] == '4')) {
276 daniel-mar 509
                                size_t tmp = strlen(dstname);
274 daniel-mar 510
                                memcpy(&dstname[i - 2], &dstname[i], strlen(dstname) - i + 1);
511
                                dstname[tmp - 2] = 0;
512
                                return true;
513
                        }
514
                }
515
        }
516
        return false;
517
}
518
 
278 daniel-mar 519
Boolean add_64_filename_prefix(char* dstname) {
274 daniel-mar 520
        // foobar.8bf => foobar64.8bf
276 daniel-mar 521
        size_t i;
274 daniel-mar 522
        for (i = strlen(dstname); i > 2; i--) {
523
                if (dstname[i] == '.') {
276 daniel-mar 524
                        size_t tmp = strlen(dstname);
274 daniel-mar 525
                        memcpy(&dstname[i + 2], &dstname[i], strlen(dstname) - i + 1);
526
                        dstname[i] = '6';
527
                        dstname[i + 1] = '4';
528
                        dstname[tmp + 2] = 0;
529
                        return true;
530
                }
531
        }
532
        return false;
533
}
534
 
535
BOOL FileExists(LPCTSTR szPath) {
536
        DWORD dwAttrib = GetFileAttributes(szPath);
537
        return (dwAttrib != INVALID_FILE_ATTRIBUTES &&
538
                !(dwAttrib & FILE_ATTRIBUTE_DIRECTORY));
539
}
540
 
314 daniel-mar 541
Boolean extract_file(LPCTSTR lpType, LPCTSTR lpName, const char* outName) {
308 daniel-mar 542
        HGLOBAL datah;
543
        LPVOID datap;
544
        HRSRC datarsrc;
545
        size_t datalen;
546
 
547
        if ((datarsrc = FindResource((HMODULE)hDllInstance, lpName, lpType))
548
                && (datah = LoadResource((HMODULE)hDllInstance, datarsrc))
549
                && (datalen = SizeofResource((HMODULE)hDllInstance, datarsrc))
550
                && (datap = (Ptr)LockResource(datah))) {
551
 
552
                FILE* fp = fopen(outName, "wb+");
553
                if (fp == NULL) return false;
554
                if (fwrite(datap, 1, datalen, fp) != datalen) return false;
555
                if (fclose(fp)) return false;
556
 
557
                return true;
558
        }
559
        else {
560
                return false;
561
        }
562
}
563
 
564
OSErr do_make_standalone(char* dstname, int bits) {
274 daniel-mar 565
        Boolean res;
292 daniel-mar 566
        char err[MAX_PATH + 200];
567
 
274 daniel-mar 568
        //DeleteFile(dstname);
314 daniel-mar 569
        if (extract_file("TPLT", MAKEINTRESOURCE(1000 + bits), dstname)) {
319 daniel-mar 570
                res = doresources(NULL, dstname, bits);
571
                if (!res) {
292 daniel-mar 572
                        DeleteFile(dstname);
319 daniel-mar 573
                        sprintf(err, "Could not create %d bit standalone plugin (doresources failed).", bits);
292 daniel-mar 574
                        alertuser(_strdup(&err[0]), _strdup(""));
274 daniel-mar 575
                }
576
        }
577
        else {
308 daniel-mar 578
                // 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 579
                res = false;
292 daniel-mar 580
                //DeleteFile(dstname);
308 daniel-mar 581
                sprintf(err, "Could not create %d bit standalone plugin (File extraction failed).", bits);
274 daniel-mar 582
                alertuser(_strdup(&err[0]), _strdup(""));
583
        }
584
 
585
        return res ? noErr : ioErr;
586
}
587
 
314 daniel-mar 588
Boolean check_unicows() {
589
        // Unicows.dll is required for Win9x to implement the BeginUpdateResource functionalities
590
 
591
        if (isWin32NT()) {
592
                // Modern Windows don't require UnicoWS
593
                return true;
594
        } else {
258 daniel-mar 595
                HMODULE hLib;
596
 
597
                hLib = LoadLibraryA("UNICOWS.DLL");
598
                if (!hLib) {
318 daniel-mar 599
                        char dstname[MAX_PATH + 1];
258 daniel-mar 600
 
314 daniel-mar 601
                        // Try to install UnicoWS automatically
318 daniel-mar 602
                        GetSystemDirectoryA(&dstname[0], MAX_PATH);
603
                        strcat(&dstname[0], "\\UNICOWS.DLL");
604
                        extract_file("DLL", "UNICOWS", &dstname[0]); // included in make_win.rc
279 daniel-mar 605
 
314 daniel-mar 606
                        hLib = LoadLibraryA("UNICOWS.DLL");
607
                        if (!hLib) {
608
                                // This should not happen
316 daniel-mar 609
                                simplealert(_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 your system directory"));
258 daniel-mar 610
 
314 daniel-mar 611
                                return false;
612
                        }
613
                        else {
614
                                FreeLibrary(hLib);
615
                                return true;
616
                        }
258 daniel-mar 617
                }
618
                else {
619
                        FreeLibrary(hLib);
314 daniel-mar 620
                        return true;
258 daniel-mar 621
                }
622
        }
314 daniel-mar 623
}
258 daniel-mar 624
 
314 daniel-mar 625
OSErr make_standalone(StandardFileReply *sfr){
626
        OSErr tmpErr, outErr;
627
        char dstname[MAX_PATH+1];
628
 
274 daniel-mar 629
        outErr = noErr;
314 daniel-mar 630
 
631
        check_unicows();
308 daniel-mar 632
 
633
        // Make 32 bit:
634
        // Destfile = no64_or_32(chosenname)
274 daniel-mar 635
        myp2cstrcpy(dstname, sfr->sfFile.name);
636
        remove_64_filename_prefix(dstname);
308 daniel-mar 637
        tmpErr = do_make_standalone(&dstname[0], 32);
274 daniel-mar 638
        if (tmpErr != noErr)
639
                outErr = tmpErr;
640
        else
308 daniel-mar 641
                showmessage(_strdup("32 bit standalone filter was successfully created"));
274 daniel-mar 642
 
308 daniel-mar 643
        if (isWin32NT()) {
644
                // Make 64 bit:
645
                // Destfile = no64_or_32(chosenname) + 64
274 daniel-mar 646
                myp2cstrcpy(dstname, sfr->sfFile.name);
647
                remove_64_filename_prefix(dstname);
308 daniel-mar 648
                add_64_filename_prefix(dstname);
649
                tmpErr = do_make_standalone(&dstname[0], 64);
274 daniel-mar 650
                if (tmpErr != noErr)
651
                        outErr = tmpErr;
652
                else
308 daniel-mar 653
                        showmessage(_strdup("64 bit standalone filter was successfully created"));
277 daniel-mar 654
        }
279 daniel-mar 655
        else {
656
                // Unicows.dll cannot edit resources of 64 bit DLLs.
657
                // The normal Kernel function BeginUpdateResource can edit 64 bit DLLs, even in NT4.0 SP6
658
                simplealert(_strdup("Note: A 64 bit standalone filter cannot be created with your Windows version"));
659
        }
274 daniel-mar 660
 
661
        return outErr;
258 daniel-mar 662
}
308 daniel-mar 663