Subversion Repositories filter_foundry

Rev

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