Subversion Repositories filter_foundry

Rev

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

Rev Author Line No. Line
256 daniel-mar 1
/*
2
    This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
4
    Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
5
 
6
    This program is free software; you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation; either version 2 of the License, or
9
    (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with this program; if not, write to the Free Software
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
*/
20
 
21
#include "ff.h"
22
 
23
#include "file_compat.h"
24
 
25
#ifdef MAC_ENV
26
#include <Endian.h>
27
#else
28
int EndianS32_LtoN(int num) {
272 daniel-mar 29
        return ((num>>24)&0xff) +      // move byte 3 to byte 0
30
               ((num<<8)&0xff0000) +   // move byte 1 to byte 2
31
               ((num>>8)&0xff00) +     // move byte 2 to byte 1
256 daniel-mar 32
               ((num<<24)&0xff000000); // byte 0 to byte 3
33
}
34
#endif
35
 
36
enum{
37
        BUFSIZE = 4L<<10,
38
        MAXLINE = 0x200,
39
};
40
 
41
Boolean readparams(Handle h,Boolean alerts,char **reason){
42
        Boolean res = false;
43
        char linebuf[MAXLINE+1],curexpr[MAXEXPR+1],*p,*dataend,*q;
44
        char c;
45
        int linecnt, lineptr, exprcnt;
46
 
47
        if(!h){
48
                *reason = _strdup("readparams: Null parameter handle.");
49
                return false;
50
        }
51
 
52
        p = PILOCKHANDLE(h,false);
53
        dataend = p + PIGETHANDLESIZE(h);
54
 
55
        q = curexpr;
56
        linecnt = exprcnt = lineptr = 0;
57
 
58
        *reason = _strdup("File was too short.");
59
        while(p < dataend){
60
 
61
                c = *p++;
62
 
63
                if(c==CR || c==LF){ /* detected end of line */
64
 
65
                        /* look ahead to see if we need to skip a line feed (DOS EOL convention) */
66
                        if(c == CR && *p == LF && p < dataend)
67
                                ++p;
68
 
69
                        linebuf[lineptr] = 0; /* add terminating NUL to line buffer */
70
 
71
                        /* process complete line */
72
                        if(linecnt==0){
73
                                if(strcmp(linebuf,"%RGB-1.0")){
74
                                        if(alerts)
75
                                                *reason = _strdup("This doesn't look like a Filter Factory file (first line is not \"%RGB-1.0\").");
76
                                        break;
77
                                }
78
                        }else if(linecnt<=8){
79
                                slider[linecnt-1] = atoi(linebuf);
80
                        }else{
81
                                if(lineptr){
82
                                        /* it's not an empty line; append it to current expr string */
83
                                        if( q+lineptr > curexpr+MAXEXPR ){
84
                                                *reason = _strdup("Found an expression longer than 1024 characters.");
85
                                                break;
86
                                        }
87
                                        q = cat(q,linebuf);
88
                                }else{
89
                                        /* it's an empty line: we've completed the expr string */
90
                                        if(expr[exprcnt])
91
                                                free(expr[exprcnt]);
92
                                        *q = 0;
93
                                        if(!(expr[exprcnt] = my_strdup(curexpr))){
94
                                                *reason = _strdup("Could not get memory for expression.");
95
                                                break;
96
                                        }
97
 
98
                                        if(++exprcnt == 4){
99
                                                res = true;
100
                                                break; /* got everything we want */
101
                                        }
102
 
103
                                        q = curexpr; /* empty current expr, ready for next one */
104
                                }
105
                        }
106
 
107
                        ++linecnt;
108
                        lineptr = 0;
109
                }else{
110
                        /* store character */
111
                        if(c=='\\'){ /* escape sequence */
112
                                if(p < dataend){
113
                                        c = *p++;
114
                                        switch(c){
115
                                        case 'r':
268 daniel-mar 116
                                                #if WIN_ENV
117
                                                c = CR;
118
                                                if (lineptr < MAXLINE)
274 daniel-mar 119
                                                        linebuf[lineptr++] = c;
268 daniel-mar 120
                                                c = LF;
121
                                                #else
122
                                                c = CR;
123
                                                #endif
124
                                                break;
256 daniel-mar 125
                                        case '\\': break;
126
                                        default:
127
                                                if(alerts) alertuser(_strdup("Warning:"),_strdup("Unknown escape sequence in input."));
128
                                        }
129
                                }//else if(alerts) alertuser(_strdup("Warning:"),_strdup("truncated escape sequence ends input"));
130
                        }
131
 
132
                        if(lineptr < MAXLINE)
133
                                linebuf[lineptr++] = c;
134
                }
135
        }
136
 
137
        PIUNLOCKHANDLE(h);
138
 
139
        if (res) *reason = NULL; // no error
140
        return res;
141
}
142
 
143
void convert_premiere_to_photoshop(PARM_T* photoshop, PARM_T_PREMIERE* premiere) {
144
        int i;
145
 
146
        photoshop->cbSize = sizeof(PARM_T);
147
        photoshop->standalone = premiere->standalone;
148
        for (i=0;i<8;++i)
272 daniel-mar 149
                photoshop->val[i] = premiere->val[i];
256 daniel-mar 150
        photoshop->popDialog = premiere->popDialog;
151
        photoshop->unknown1 = premiere->unknown1;
152
        photoshop->unknown2 = premiere->unknown2;
153
        photoshop->unknown3 = premiere->unknown3;
154
        for (i=0;i<4;++i)
272 daniel-mar 155
                photoshop->map_used[i] = premiere->map_used[i];
256 daniel-mar 156
        for (i=0;i<8;++i)
272 daniel-mar 157
                photoshop->ctl_used[i] = premiere->ctl_used[i];
256 daniel-mar 158
        sprintf((char*)photoshop->category, "Filter Factory"); // Premiere plugins do not have a category attribute
159
        photoshop->iProtected = 0; // Premiere plugins do not have a protect flag
160
        memcpy((void*)photoshop->title, (void*)premiere->title, sizeof(photoshop->title));
161
        memcpy((void*)photoshop->copyright, (void*)premiere->copyright, sizeof(photoshop->copyright));
162
        memcpy((void*)photoshop->author, (void*)premiere->author, sizeof(photoshop->author));
163
        for (i=0;i<4;++i)
272 daniel-mar 164
                memcpy((void*)photoshop->map[i], (void*)premiere->map[i], sizeof(photoshop->map[i]));
256 daniel-mar 165
        for (i=0;i<8;++i)
272 daniel-mar 166
                memcpy((void*)photoshop->ctl[i], (void*)premiere->ctl[i], sizeof(photoshop->ctl[i]));
256 daniel-mar 167
 
168
        if (premiere->singleExpression) {
169
                memcpy((void*)photoshop->formula[0], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
170
                memcpy((void*)photoshop->formula[1], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
171
                memcpy((void*)photoshop->formula[2], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
172
                memcpy((void*)photoshop->formula[3], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
173
        } else {
174
                memcpy((void*)photoshop->formula[0], (void*)premiere->formula[2], sizeof(photoshop->formula[2]));
175
                memcpy((void*)photoshop->formula[1], (void*)premiere->formula[1], sizeof(photoshop->formula[1]));
176
                memcpy((void*)photoshop->formula[2], (void*)premiere->formula[0], sizeof(photoshop->formula[0]));
177
                memcpy((void*)photoshop->formula[3], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
178
        }
179
}
180
 
366 daniel-mar 181
char* _ffx_read_str(char** q) {
182
        uint32_t len;
183
        char* val;
184
 
185
        len = *((uint32_t*)*q);
186
        *q += sizeof(uint32_t);
187
        val = (char*)malloc(len + 1);
188
        if (val != NULL) {
189
                memcpy(val, (char*)*q, len);
190
                val[len] = 0;
191
        }
192
        *q += len;
193
        return val;
194
}
195
 
196
Boolean readfile_ffx(StandardFileReply* sfr, char** reason) {
197
        Handle h;
198
        Boolean res = false;
199
        FILEREF refnum;
200
        uint32_t len;
201
        char* val;
202
        Boolean valid_file;
203
        int i;
204
 
205
        if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
206
                if ((h = readfileintohandle(refnum))) {
207
                        char* q = (char*)PILOCKHANDLE(h, false);
208
 
209
                        len = *((uint32_t*)q);
210
                        if (len == 6) {
211
                                val = _ffx_read_str(&q);
212
                                valid_file = (strcmp(val, "FFX1.0") == 0) || (strcmp(val, "FFX1.1") == 0) || (strcmp(val, "FFX1.2") == 0);
213
                                free(val);
214
                                if (valid_file) {
215
                                        val = _ffx_read_str(&q);
216
                                        myc2pstrcpy(gdata->parm.title, val);
217
                                        free(val);
218
 
219
                                        val = _ffx_read_str(&q);
220
                                        myc2pstrcpy(gdata->parm.category, val);
221
                                        free(val);
222
 
223
                                        val = _ffx_read_str(&q);
224
                                        myc2pstrcpy(gdata->parm.author, val);
225
                                        free(val);
226
 
227
                                        val = _ffx_read_str(&q);
228
                                        myc2pstrcpy(gdata->parm.copyright, val);
229
                                        free(val);
230
 
231
                                        // Channels I, R, G, B, A
232
                                        for (i = 0; i < 4; i++) {
233
                                                val = _ffx_read_str(&q);
234
                                                if (i == 0) {
235
                                                        if (strcmp(val, "0") != 0) {
236
                                                                // "Intro channel" existing
237
                                                                char* val2 = _ffx_read_str(&q);
238
                                                                strcat(val, ",");
239
                                                                strcat(val, val2);
240
                                                                free(val2);
241
                                                        }
242
                                                        else {
243
                                                                free(val);
244
                                                                val = _ffx_read_str(&q);
245
                                                        }
246
                                                }
247
                                                expr[i] = my_strdup(val);
248
                                                myc2pstrcpy(gdata->parm.formula[i], val);
249
                                                free(val);
250
                                        }
251
 
252
                                        // Sliders
253
                                        for (i = 0; i < 8; i++) {
254
                                                val = _ffx_read_str(&q);
255
                                                myc2pstrcpy(gdata->parm.ctl[i], val);
256
                                                free(val);
257
                                                gdata->parm.ctl_used[i] = (bool32_t) * ((byte*)q);
258
                                                q += sizeof(byte);
259
                                                gdata->parm.val[i] = *((uint32_t*)q);
260
                                                slider[i] = *((uint32_t*)q);
261
                                                q += sizeof(uint32_t);
262
                                        }
263
 
264
                                        simplewarning(_strdup("Attention! You loaded a \"Filters Unlimited\" file. Please note that Filter Foundry only implements the basic Filter Factory functions. Therefore, most \"Filters Unlimited\" filters won't work with Filter Foundry."));
265
 
266
                                        res = true;
267
                                }
268
                        }
269
                        PIDISPOSEHANDLE(h);
270
                }
271
                FSClose(refnum);
272
        }
273
 
274
        if (res) gdata->obfusc = false;
275
        return res;
276
}
277
 
256 daniel-mar 278
Boolean read8bfplugin(StandardFileReply *sfr,char **reason){
279
        unsigned char magic[2];
280
        FILECOUNT count;
281
        Handle h;
282
        Boolean res = false;
283
        FILEREF refnum;
284
 
285
        if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&refnum) == noErr){
286
                // check DOS EXE magic number
287
                count = 2;
288
                if(FSRead(refnum,&count,magic) == noErr /*&& magic[0]=='M' && magic[1]=='Z'*/){
309 daniel-mar 289
                        if(GetEOF(refnum,(FILEPOS*)&count) == noErr && count < 4096L<<10){ // sanity check file size < 4MiB (note that "Debug" builds can have approx 700 KiB while "Release" builds have approx 300 KiB)
256 daniel-mar 290
                                if( (h = readfileintohandle(refnum)) ){
291
                                        long *q = (long*)PILOCKHANDLE(h,false);
292
 
293
                                        // look for signature at start of valid PARM resource
294
                                        // This signature is observed in Filter Factory standalones.
295
                                        for( count /= 4 ; count >= PARM_SIZE/4 ; --count, ++q )
296
                                        {
297
 
268 daniel-mar 298
                                                #ifdef MAC_ENV
256 daniel-mar 299
                                                // Case #1: Mac is reading Windows (Win16/32/64) plugin
300
                                                if( ((EndianS32_LtoN(q[0]) == PARM_SIZE) ||
301
                                                     (EndianS32_LtoN(q[0]) == PARM_SIZE_PREMIERE) ||
302
                                                     (EndianS32_LtoN(q[0]) == PARM_SIG_MAC)) && EndianS32_LtoN(q[1]) == 1
303
                                                        && (res = readPARM((char*)q, &gdata->parm, reason, 1 /*Windows format resource*/)) )
304
                                                {
305
                                                        // these are the only numeric fields we *have* to swap
306
                                                        // all the rest are flags which (if we're careful) will work in either ordering
307
                                                        for(i = 0; i < 8; ++i)
308
                                                                slider[i] = EndianS32_LtoN(slider[i]);
309
                                                }
268 daniel-mar 310
                                                #else
256 daniel-mar 311
                                                // Case #2: Windows is reading a Windows plugin (if Resource API failed, e.g. Win64 tries to open NE file, Win32 tries to open 64bit file)
312
                                                if( ((q[0] == PARM_SIZE) ||
313
                                                     (q[0] == PARM_SIZE_PREMIERE) ||
314
                                                     (q[0] == PARM_SIG_MAC)) && q[1] == 1
308 daniel-mar 315
                                                        && (res = readPARM((char*)q, &gdata->parm, reason, 1/*fromwin*/)))
256 daniel-mar 316
                                                {
317
                                                }
318
 
339 daniel-mar 319
                                                // Case #3: Windows is reading an old FilterFactory Mac file
320
                                                // Note: You must read the ".rsrc" resource fork, not the standalone binary!
256 daniel-mar 321
                                                else if( ((EndianS32_LtoN(q[0]) == PARM_SIZE) ||
322
                                                     (EndianS32_LtoN(q[0]) == PARM_SIZE_PREMIERE) ||
323
                                                     (EndianS32_LtoN(q[0]) == PARM_SIG_MAC)) && EndianS32_LtoN(q[1]) == 1
324
                                                        && (res = readPARM((char*)q, &gdata->parm, reason, 0 /*Strings are already PStrings*/)) )
325
                                                {
339 daniel-mar 326
                                                        // Note: slider[i] = EndianS32_LtoN(slider[i]); will be done in readPARM()
327
                                                        // All the rest are flags which (if we're careful) will work in either ordering
328
 
341 daniel-mar 329
                                                        // Convert '\r' in the copyright field to '\r\n'.
330
                                                        int i, j;
339 daniel-mar 331
                                                        for (i = 1; i < gdata->parm.copyright[0]; i++) {
332
                                                                if (gdata->parm.copyright[i] == '\r') {
341 daniel-mar 333
                                                                        for (j = gdata->parm.copyright[0]; j>i; j--) {
334
                                                                                gdata->parm.copyright[j+1] = gdata->parm.copyright[j];
335
                                                                        }
336
                                                                        gdata->parm.copyright[0]++;
337
                                                                        gdata->parm.copyright[i+1] = '\n';
339 daniel-mar 338
                                                                }
339
                                                        }
256 daniel-mar 340
                                                }
268 daniel-mar 341
                                                #endif
256 daniel-mar 342
 
343
                                                if (res) break;
344
                                        }
341 daniel-mar 345
 
256 daniel-mar 346
                                        PIDISPOSEHANDLE(h);
347
                                }
348
                        }
349
                } // else no point in proceeding
350
                FSClose(refnum);
351
        }else
352
                *reason = _strdup("Could not open file.");
353
 
354
        if (res) gdata->obfusc = false;
355
        return res;
356
}
357
 
358
Boolean readPARM(Ptr p,PARM_T *pparm,char **reasonstr,int fromwin){
359
        int i;
360
 
361
        if (*((unsigned int*)p) == PARM_SIZE_PREMIERE) {
362
                convert_premiere_to_photoshop(pparm, (PARM_T_PREMIERE*)p);
363
        } else {
364
                // Assume it is Photoshop. Signature either PARM_SIZE (0x2068) or 0x1C68
365
                memcpy(pparm,p,sizeof(PARM_T));
366
        }
367
 
368
        if(fromwin){
369
                /* Windows PARM resource stores C strings - convert to Pascal strings  */
370
                myc2pstr((char*)pparm->category);
371
                myc2pstr((char*)pparm->title);
372
                myc2pstr((char*)pparm->copyright);
373
                myc2pstr((char*)pparm->author);
374
                for(i = 0; i < 4; ++i)
375
                        myc2pstr((char*)pparm->map[i]);
376
                for(i = 0; i < 8; ++i)
377
                        myc2pstr((char*)pparm->ctl[i]);
378
        }
379
 
380
        for(i = 0; i < 4; ++i){
381
                if(expr[i]) free(expr[i]);
366 daniel-mar 382
                expr[i] = my_strdup((char*)pparm->formula[i]);
256 daniel-mar 383
        }
384
 
339 daniel-mar 385
        for (i = 0; i < 8; ++i) {
386
                if (pparm->val[i] > 0xFF) {
387
                        // Wrong endianess (e.g. reading a Mac rsrc on Windows)
388
                        slider[i] = (uint8_t)EndianS32_LtoN(pparm->val[i]);
389
                }
390
                else {
391
                        slider[i] = (uint8_t)pparm->val[i];
392
                }
393
        }
256 daniel-mar 394
 
395
        return true;
396
}
397
 
398
Handle readfileintohandle(FILEREF r){
399
        FILEPOS n;
400
        Handle h;
401
        Ptr p;
402
 
403
        if( GetEOF(r,&n) == noErr && (h = PINEWHANDLE(n)) ){
404
                p = PILOCKHANDLE(h,false);
405
                if(SetFPos(r,fsFromStart,0) == noErr && FSRead(r,(FILECOUNT*)&n,p) == noErr){
406
                        PIUNLOCKHANDLE(h);
407
                        return h;
408
                }
409
                PIDISPOSEHANDLE(h);
410
        }
411
        return NULL;
412
}
413
 
414
Boolean fileHasExtension(StandardFileReply *sfr, const char* extension) {
268 daniel-mar 415
        #ifdef WIN_ENV
416
 
256 daniel-mar 417
        char name[MAX_PATH+1];
263 daniel-mar 418
        return sfr->nFileExtension && !strcasecmp(myp2cstrcpy(name,sfr->sfFile.name) + sfr->nFileExtension - 1,extension);
268 daniel-mar 419
 
420
        #else
421
 
256 daniel-mar 422
        char name[1025]; // https://stackoverflow.com/questions/1295135/longest-pathname-string-in-mac-os-x-hfs
423
        char* s = myp2cstrcpy(name,sfr->sfFile.name);
424
        return strcmp(s + strlen(s) - strlen(extension), extension) == 0;
268 daniel-mar 425
 
426
        #endif
256 daniel-mar 427
}
428
 
366 daniel-mar 429
Boolean readfile_afs_pff(StandardFileReply *sfr,char **reason){
256 daniel-mar 430
        FILEREF r;
431
        Handle h;
432
        Boolean res = false;
433
 
434
        if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&r) == noErr){
435
                if( (h = readfileintohandle(r)) ){
436
                        if( (res = readparams(h,true,reason)) ) {
437
                                gdata->standalone = false; // so metadata fields will default, if user chooses Make...
438
 
439
                                if (fileHasExtension(sfr, ".pff")) {
440
                                        // If it is a Premiere settings file, we need to swap the channels red and blue
263 daniel-mar 441
                                        // We just swap the pointers!
256 daniel-mar 442
                                        char* tmp;
263 daniel-mar 443
                                        tmp = expr[0];
444
                                        expr[0] = expr[2];
445
                                        expr[2] = tmp;
256 daniel-mar 446
                                }
447
                        }
448
 
449
                        PIDISPOSEHANDLE(h);
450
                }
451
                FSClose(r);
452
        }else
453
                *reason = _strdup("Could not open the file.");
454
 
455
        return res;
456
}