Login | ViewVC Help
View File | Revision Log | Show Annotations | Download File | View Changeset | Root Listing
root/filter_foundry/trunk/make_win.c
Revision: 357
Committed: Sat Oct 16 18:45:48 2021 UTC (7 months, 1 week ago) by daniel-marschall
Content type: text/x-csrc
File size: 24190 byte(s)
Log Message:
In case filter is digitally signed, the signature will be removed for standalone filters

File Contents

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