Subversion Repositories filter_foundry

Rev

Rev 395 | Rev 420 | 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
 
408 daniel-mar 41
Boolean readparams_afs_pff(Handle h,char **reason){
256 daniel-mar 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
 
408 daniel-mar 58
        //*reason = _strdup("File was too short.");
256 daniel-mar 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")){
408 daniel-mar 74
                                        // *reason = _strdup("This doesn't look like a Filter Factory file (first line is not \"%RGB-1.0\").");
256 daniel-mar 75
                                        break;
76
                                }
77
                        }else if(linecnt<=8){
78
                                slider[linecnt-1] = atoi(linebuf);
79
                        }else{
80
                                if(lineptr){
81
                                        /* it's not an empty line; append it to current expr string */
82
                                        if( q+lineptr > curexpr+MAXEXPR ){
83
                                                *reason = _strdup("Found an expression longer than 1024 characters.");
84
                                                break;
85
                                        }
86
                                        q = cat(q,linebuf);
87
                                }else{
88
                                        /* it's an empty line: we've completed the expr string */
89
                                        if(expr[exprcnt])
90
                                                free(expr[exprcnt]);
91
                                        *q = 0;
92
                                        if(!(expr[exprcnt] = my_strdup(curexpr))){
93
                                                *reason = _strdup("Could not get memory for expression.");
94
                                                break;
95
                                        }
96
 
97
                                        if(++exprcnt == 4){
98
                                                res = true;
99
                                                break; /* got everything we want */
100
                                        }
101
 
102
                                        q = curexpr; /* empty current expr, ready for next one */
103
                                }
104
                        }
105
 
106
                        ++linecnt;
107
                        lineptr = 0;
108
                }else{
109
                        /* store character */
110
                        if(c=='\\'){ /* escape sequence */
111
                                if(p < dataend){
112
                                        c = *p++;
113
                                        switch(c){
114
                                        case 'r':
268 daniel-mar 115
                                                #if WIN_ENV
116
                                                c = CR;
117
                                                if (lineptr < MAXLINE)
274 daniel-mar 118
                                                        linebuf[lineptr++] = c;
268 daniel-mar 119
                                                c = LF;
120
                                                #else
121
                                                c = CR;
122
                                                #endif
123
                                                break;
256 daniel-mar 124
                                        case '\\': break;
408 daniel-mar 125
                                        //default:
126
                                        //      if(alerts) alertuser(_strdup("Warning:"),_strdup("Unknown escape sequence in input."));
256 daniel-mar 127
                                        }
128
                                }//else if(alerts) alertuser(_strdup("Warning:"),_strdup("truncated escape sequence ends input"));
129
                        }
130
 
131
                        if(lineptr < MAXLINE)
132
                                linebuf[lineptr++] = c;
133
                }
134
        }
135
 
136
        PIUNLOCKHANDLE(h);
137
 
138
        return res;
139
}
140
 
141
void convert_premiere_to_photoshop(PARM_T* photoshop, PARM_T_PREMIERE* premiere) {
142
        int i;
143
 
144
        photoshop->cbSize = sizeof(PARM_T);
145
        photoshop->standalone = premiere->standalone;
146
        for (i=0;i<8;++i)
272 daniel-mar 147
                photoshop->val[i] = premiere->val[i];
256 daniel-mar 148
        photoshop->popDialog = premiere->popDialog;
149
        photoshop->unknown1 = premiere->unknown1;
150
        photoshop->unknown2 = premiere->unknown2;
151
        photoshop->unknown3 = premiere->unknown3;
152
        for (i=0;i<4;++i)
272 daniel-mar 153
                photoshop->map_used[i] = premiere->map_used[i];
256 daniel-mar 154
        for (i=0;i<8;++i)
272 daniel-mar 155
                photoshop->ctl_used[i] = premiere->ctl_used[i];
393 daniel-mar 156
        sprintf(photoshop->szCategory, "Filter Factory"); // Premiere plugins do not have a category attribute
256 daniel-mar 157
        photoshop->iProtected = 0; // Premiere plugins do not have a protect flag
393 daniel-mar 158
        memcpy((void*)photoshop->szTitle, (void*)premiere->szTitle, sizeof(photoshop->szTitle));
159
        memcpy((void*)photoshop->szCopyright, (void*)premiere->szCopyright, sizeof(photoshop->szCopyright));
160
        memcpy((void*)photoshop->szAuthor, (void*)premiere->szAuthor, sizeof(photoshop->szAuthor));
256 daniel-mar 161
        for (i=0;i<4;++i)
393 daniel-mar 162
                memcpy((void*)photoshop->szMap[i], (void*)premiere->szMap[i], sizeof(photoshop->szMap[i]));
256 daniel-mar 163
        for (i=0;i<8;++i)
393 daniel-mar 164
                memcpy((void*)photoshop->szCtl[i], (void*)premiere->szCtl[i], sizeof(photoshop->szCtl[i]));
256 daniel-mar 165
 
166
        if (premiere->singleExpression) {
393 daniel-mar 167
                memcpy((void*)photoshop->szFormula[0], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
168
                memcpy((void*)photoshop->szFormula[1], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
169
                memcpy((void*)photoshop->szFormula[2], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
170
                memcpy((void*)photoshop->szFormula[3], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
256 daniel-mar 171
        } else {
393 daniel-mar 172
                memcpy((void*)photoshop->szFormula[0], (void*)premiere->szFormula[2], sizeof(photoshop->szFormula[2]));
173
                memcpy((void*)photoshop->szFormula[1], (void*)premiere->szFormula[1], sizeof(photoshop->szFormula[1]));
174
                memcpy((void*)photoshop->szFormula[2], (void*)premiere->szFormula[0], sizeof(photoshop->szFormula[0]));
175
                memcpy((void*)photoshop->szFormula[3], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
256 daniel-mar 176
        }
177
}
178
 
366 daniel-mar 179
char* _ffx_read_str(char** q) {
180
        uint32_t len;
181
        char* val;
182
 
183
        len = *((uint32_t*)*q);
184
        *q += sizeof(uint32_t);
185
        val = (char*)malloc(len + 1);
186
        if (val != NULL) {
187
                memcpy(val, (char*)*q, len);
188
                val[len] = 0;
189
        }
190
        *q += len;
191
        return val;
192
}
193
 
194
Boolean readfile_ffx(StandardFileReply* sfr, char** reason) {
195
        Handle h;
196
        Boolean res = false;
197
        FILEREF refnum;
198
        uint32_t len;
199
        char* val;
367 daniel-mar 200
        int format_version = -1;
366 daniel-mar 201
        int i;
202
 
203
        if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
204
                if ((h = readfileintohandle(refnum))) {
205
                        char* q = (char*)PILOCKHANDLE(h, false);
206
 
207
                        len = *((uint32_t*)q);
208
                        if (len == 6) {
209
                                val = _ffx_read_str(&q);
367 daniel-mar 210
                                if (strcmp(val, "FFX1.0") == 0) format_version = 10;
211
                                else if (strcmp(val, "FFX1.1") == 0) format_version = 11;
212
                                else if (strcmp(val, "FFX1.2") == 0) format_version = 12;
366 daniel-mar 213
                                free(val);
367 daniel-mar 214
                                if (format_version > 0) {
368 daniel-mar 215
                                        simplewarning(_strdup("Attention! You are loading 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."));
216
 
366 daniel-mar 217
                                        val = _ffx_read_str(&q);
393 daniel-mar 218
                                        strcpy(gdata->parm.szTitle, val);
366 daniel-mar 219
                                        free(val);
220
 
221
                                        val = _ffx_read_str(&q);
393 daniel-mar 222
                                        strcpy(gdata->parm.szCategory, val);
366 daniel-mar 223
                                        free(val);
224
 
225
                                        val = _ffx_read_str(&q);
393 daniel-mar 226
                                        strcpy(gdata->parm.szAuthor, val);
366 daniel-mar 227
                                        free(val);
228
 
229
                                        val = _ffx_read_str(&q);
393 daniel-mar 230
                                        strcpy(gdata->parm.szCopyright, val);
366 daniel-mar 231
                                        free(val);
232
 
233
                                        // Channels I, R, G, B, A
234
                                        for (i = 0; i < 4; i++) {
235
                                                val = _ffx_read_str(&q);
236
                                                if (i == 0) {
370 daniel-mar 237
                                                        char* val2 = _ffx_read_str(&q);
366 daniel-mar 238
                                                        if (strcmp(val, "0") != 0) {
239
                                                                // "Intro channel" existing
370 daniel-mar 240
                                                                // C++ wrong warning: Using uninitialized memory "val2" (C6001)
241
                                                                #pragma warning(suppress : 6001)
242
                                                                char* combined = (char*)malloc(strlen(val) + strlen(",") + strlen(val2) + 1);
243
                                                                if (combined != NULL) {
244
                                                                        sprintf(combined, "%s,%s", val, val2);
245
                                                                        free(val);
246
                                                                        free(val2);
247
                                                                        val = combined;
248
                                                                }
366 daniel-mar 249
                                                        }
250
                                                        else {
251
                                                                free(val);
370 daniel-mar 252
                                                                val = val2;
366 daniel-mar 253
                                                        }
254
                                                }
393 daniel-mar 255
                                                if (strlen(val) >= sizeof(gdata->parm.szFormula[i])) {
368 daniel-mar 256
                                                        if (i == 0) {
381 daniel-mar 257
                                                                simplealert(_strdup("Attention! The formula for channel I/R was too long (longer than 1023 characters) and was truncated."));
368 daniel-mar 258
                                                        }
259
                                                        else if (i == 1) {
381 daniel-mar 260
                                                                simplealert(_strdup("Attention! The formula for channel G was too long (longer than 1023 characters) and was truncated."));
368 daniel-mar 261
                                                        }
262
                                                        else if (i == 2) {
381 daniel-mar 263
                                                                simplealert(_strdup("Attention! The formula for channel B was too long (longer than 1023 characters) and was truncated."));
368 daniel-mar 264
                                                        }
265
                                                        else if (i == 3) {
381 daniel-mar 266
                                                                simplealert(_strdup("Attention! The formula for channel A was too long (longer than 1023 characters) and was truncated."));
368 daniel-mar 267
                                                        }
370 daniel-mar 268
                                                        // C++ wrong warning: Buffer overflow (C6386)
269
                                                        #pragma warning(suppress : 6386)
393 daniel-mar 270
                                                        val[sizeof(gdata->parm.szFormula[i]) - 1] = '\0';
368 daniel-mar 271
                                                }
395 daniel-mar 272
                                                if (expr[i]) free(expr[i]);
366 daniel-mar 273
                                                expr[i] = my_strdup(val);
393 daniel-mar 274
                                                strcpy(gdata->parm.szFormula[i], val);
366 daniel-mar 275
                                                free(val);
276
                                        }
277
 
278
                                        // Sliders
279
                                        for (i = 0; i < 8; i++) {
367 daniel-mar 280
                                                char* sliderName;
366 daniel-mar 281
                                                val = _ffx_read_str(&q);
367 daniel-mar 282
                                                sliderName = val;
283
                                                if (format_version >= 12) {
284
                                                        // Format FFX1.2 has prefixes {S} = Slider, {C} = Checkbox, none = Slider
285
                                                        if ((sliderName[0] == '{') && (sliderName[1] == 'S') && (sliderName[2] == '}')) sliderName += 3;
286
                                                        else if ((sliderName[0] == '{') && (sliderName[1] == 'C') && (sliderName[2] == '}')) sliderName += 3;
287
                                                }
393 daniel-mar 288
                                                strcpy(gdata->parm.szCtl[i], sliderName);
366 daniel-mar 289
                                                free(val);
367 daniel-mar 290
                                                gdata->parm.ctl_used[i] = (bool32_t)*((byte*)q);
366 daniel-mar 291
                                                q += sizeof(byte);
292
                                                gdata->parm.val[i] = *((uint32_t*)q);
293
                                                slider[i] = *((uint32_t*)q);
294
                                                q += sizeof(uint32_t);
295
                                        }
296
 
390 daniel-mar 297
                                        // Maps (are not part of the format!)
393 daniel-mar 298
                                        strcpy(gdata->parm.szMap[0], "Map 0:");
299
                                        strcpy(gdata->parm.szMap[1], "Map 1:");
300
                                        strcpy(gdata->parm.szMap[2], "Map 2:");
301
                                        strcpy(gdata->parm.szMap[3], "Map 3:");
390 daniel-mar 302
 
366 daniel-mar 303
                                        res = true;
304
                                }
305
                        }
306
                        PIDISPOSEHANDLE(h);
307
                }
308
                FSClose(refnum);
309
        }
310
 
311
        if (res) gdata->obfusc = false;
312
        return res;
313
}
314
 
373 daniel-mar 315
Boolean readfile_8bf(StandardFileReply *sfr,char **reason){
256 daniel-mar 316
        unsigned char magic[2];
317
        FILECOUNT count;
318
        Handle h;
319
        Boolean res = false;
320
        FILEREF refnum;
321
 
322
        if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&refnum) == noErr){
323
                // check DOS EXE magic number
324
                count = 2;
325
                if(FSRead(refnum,&count,magic) == noErr /*&& magic[0]=='M' && magic[1]=='Z'*/){
309 daniel-mar 326
                        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 327
                                if( (h = readfileintohandle(refnum)) ){
328
                                        long *q = (long*)PILOCKHANDLE(h,false);
329
 
330
                                        // look for signature at start of valid PARM resource
331
                                        // This signature is observed in Filter Factory standalones.
332
                                        for( count /= 4 ; count >= PARM_SIZE/4 ; --count, ++q )
333
                                        {
394 daniel-mar 334
                                                res = readPARM(&gdata->parm, (Ptr)q);
256 daniel-mar 335
                                                if (res) break;
336
                                        }
341 daniel-mar 337
 
256 daniel-mar 338
                                        PIDISPOSEHANDLE(h);
339
                                }
340
                        }
341
                } // else no point in proceeding
342
                FSClose(refnum);
343
        }else
344
                *reason = _strdup("Could not open file.");
345
 
346
        if (res) gdata->obfusc = false;
347
        return res;
348
}
349
 
394 daniel-mar 350
Boolean readPARM(PARM_T* pparm, Ptr p){
256 daniel-mar 351
        int i;
394 daniel-mar 352
        Boolean towin, tomac, fromwin, frommac;
353
        unsigned int signature = *((unsigned int*)p);
354
        unsigned int standalone = *((unsigned int*)p+1);
256 daniel-mar 355
 
394 daniel-mar 356
        // Find out our OS ("reader") the OS of the plugin ("source")
357
        #ifdef MAC_ENV
358
        towin = false;
359
        tomac = true;
360
        fromwin = ((EndianS32_LtoN(signature) == PARM_SIZE) ||
361
                (EndianS32_LtoN(signature) == PARM_SIZE_PREMIERE) ||
362
                (EndianS32_LtoN(signature) == PARM_SIG_MAC)) && EndianS32_LtoN(standalone) == 1;
363
        frommac = ((signature == PARM_SIZE) ||
364
                (signature == PARM_SIZE_PREMIERE) ||
365
                (signature == PARM_SIG_MAC)) && standalone == 1;
366
        #else
367
        towin = true;
368
        tomac = false;
369
        fromwin = ((signature == PARM_SIZE) ||
370
                (signature == PARM_SIZE_PREMIERE) ||
371
                (signature == PARM_SIG_MAC)) && standalone == 1;
372
        frommac = ((EndianS32_LtoN(signature) == PARM_SIZE) ||
373
                (EndianS32_LtoN(signature) == PARM_SIZE_PREMIERE) ||
374
                (EndianS32_LtoN(signature) == PARM_SIG_MAC)) && EndianS32_LtoN(standalone) == 1;
375
        #endif
376
 
377
        // Is it a valid signature?
378
        if (!fromwin && !frommac) {
379
                // No valid signature found
380
                return false;
381
        }
382
 
383
        // Does it come from Premiere or Photoshop?
384
        // Initialize pparm
385
        if ((signature == PARM_SIZE_PREMIERE) || (EndianS32_LtoN(signature) == PARM_SIZE_PREMIERE)) {
386
                // It comes from Premiere. Swap R and B channel and convert to a Photoshop PARM_T
256 daniel-mar 387
                convert_premiere_to_photoshop(pparm, (PARM_T_PREMIERE*)p);
388
        } else {
394 daniel-mar 389
                // It is already Photoshop. Just copy to pparm.
390
                memcpy(pparm, p, sizeof(PARM_T));
256 daniel-mar 391
        }
392
 
394 daniel-mar 393
        // Do we need to do string conversion?
394
        if (frommac) {
395
                /* Mac PARM resource stores Pascal strings - convert to C strings, since this is what we work internally with (regardles of OS) */
393 daniel-mar 396
                myp2cstr((unsigned char*)pparm->szCategory);
397
                myp2cstr((unsigned char*)pparm->szTitle);
398
                myp2cstr((unsigned char*)pparm->szCopyright);
399
                myp2cstr((unsigned char*)pparm->szAuthor);
394 daniel-mar 400
                for (i = 0; i < 4; ++i)
393 daniel-mar 401
                        myp2cstr((unsigned char*)pparm->szMap[i]);
394 daniel-mar 402
                for (i = 0; i < 8; ++i)
393 daniel-mar 403
                        myp2cstr((unsigned char*)pparm->szCtl[i]);
256 daniel-mar 404
        }
405
 
394 daniel-mar 406
        // Case #1: Mac is reading Windows (Win16/32/64) plugin
407
        if (fromwin && tomac) {
408
                size_t i;
409
 
410
                // Convert copyright CRLF to CR (actually, just removing LF)
411
                char copyrightCRLF[256];
412
                char* p = &copyrightCRLF[0];
413
                for (i = 0; i < strlen(pparm->szCopyright); i++) {
414
                        if (pparm->szCopyright[i] != LF) {
415
                                *p++ = pparm->szCopyright[i];
416
                        }
417
                }
418
                *p++ = '\0';
419
                strcpy(pparm->szCopyright, copyrightCRLF);
420
 
421
                // these are the only numeric fields we *have* to swap
422
                // all the rest are bool_t flags which (if we're careful) will work in either ordering
423
                for (i = 0; i < 8; ++i)
424
                        pparm->val[i] = EndianS32_LtoN(pparm->val[i]);
425
        }
426
 
427
        // Case #2: Mac is reading Mac (in case the normal resource extraction didn't work)
428
        // Nothing to do
429
 
430
        // Case #3: Windows is reading a Windows plugin (if Resource API failed, e.g. Win64 tries to open Win16 NE file or Win32 tries to open Win64 file)
431
        // Nothing to do
432
 
433
        // Case #4: Windows is reading an old FilterFactory Mac file
434
        // Note: You must read the ".rsrc" resource fork, not the standalone binary!
435
        if (frommac && towin) {
436
                size_t i;
437
 
438
                // Convert CR in the copyright field to CRLF.
439
                char copyrightCRLF[256];
440
                char* p = &copyrightCRLF[0];
441
                for (i = 0; i < strlen(pparm->szCopyright); i++) {
442
                        *p++ = pparm->szCopyright[i];
443
                        if (pparm->szCopyright[i] == CR) {
444
                                *p++ = LF;
445
                        }
446
                }
447
                *p++ = '\0';
448
                strcpy(pparm->szCopyright, copyrightCRLF);
449
 
450
                // these are the only numeric fields we *have* to swap
451
                // all the rest are bool_t flags which (if we're careful) will work in either ordering
452
                for (i = 0; i < 8; ++i)
453
                        pparm->val[i] = EndianS32_LtoN(pparm->val[i]);
454
        }
455
 
456
        // Now set the values in pparm into the working variables expr[] and slider[], so that they are visible in the GUI
457
 
256 daniel-mar 458
        for(i = 0; i < 4; ++i){
459
                if(expr[i]) free(expr[i]);
393 daniel-mar 460
                expr[i] = my_strdup(pparm->szFormula[i]);
256 daniel-mar 461
        }
462
 
339 daniel-mar 463
        for (i = 0; i < 8; ++i) {
394 daniel-mar 464
                slider[i] = (uint8_t)pparm->val[i];
465
                /*
466
                if (slider[i] > 0xFF) {
339 daniel-mar 467
                        // Wrong endianess (e.g. reading a Mac rsrc on Windows)
394 daniel-mar 468
                        // Should not happen since we did the stuff above
469
                        slider[i] = (uint8_t)EndianS32_LtoN(slider[i]);
339 daniel-mar 470
                }
394 daniel-mar 471
                */
339 daniel-mar 472
        }
256 daniel-mar 473
 
474
        return true;
475
}
476
 
477
Handle readfileintohandle(FILEREF r){
478
        FILEPOS n;
479
        Handle h;
480
        Ptr p;
481
 
482
        if( GetEOF(r,&n) == noErr && (h = PINEWHANDLE(n)) ){
483
                p = PILOCKHANDLE(h,false);
484
                if(SetFPos(r,fsFromStart,0) == noErr && FSRead(r,(FILECOUNT*)&n,p) == noErr){
485
                        PIUNLOCKHANDLE(h);
486
                        return h;
487
                }
488
                PIDISPOSEHANDLE(h);
489
        }
490
        return NULL;
491
}
492
 
385 daniel-mar 493
Boolean _picoLineContainsKey(char* line, char** content, const char* searchkey/*=NULL*/) {
386 daniel-mar 494
        size_t i;
495
        for (i = 0; i < strlen(line); i++) {
388 daniel-mar 496
                if (line[i] == '?') break; // avoid that "a?b:c" is detected as key
385 daniel-mar 497
                if (line[i] == ':') {
386 daniel-mar 498
                        // Note: We are ignoring whitespaces, i.e. " A :" != "A:" (TODO: should we change this?)
499
                        if ((searchkey == NULL) || ((i == strlen(searchkey)) && (memcmp(line, searchkey, i) == 0))) {
500
                                i++; // jump over ':' char
387 daniel-mar 501
                                //while ((line[i] == ' ') || (line[i] == TAB)) i++; // Trim value left
385 daniel-mar 502
                                *content = line + i;
503
                                return true;
504
                        }
505
                }
506
        }
507
        *content = line;
508
        return false;
509
}
510
 
388 daniel-mar 511
void _ffdcomp_removebrackets(char* x, char* maxptr) {
512
        char* closingBracketPos = NULL;
513
        Boolean openingBracketFound = false;
514
        if (x[0] == '[') {
515
                openingBracketFound = true;
516
        }
517
        x[0] = ':';
518
        x++;
519
        while (x < maxptr) {
520
                if ((!openingBracketFound) && (x[0] == '[')) {
521
                        openingBracketFound = true;
522
                        x[0] = ' ';
523
                }
524
                else if (openingBracketFound) {
525
                        if (x[0] == ']') {
526
                                closingBracketPos = x;
527
                        }
528
                        else if ((x[0] == CR) || (x[0] == LF)) {
529
                                if (closingBracketPos) closingBracketPos[0] = ' '; // last closing pos before CR/LF
530
                                break;
531
                        }
532
                }
533
                x++;
534
        }
535
}
536
 
393 daniel-mar 537
// isFormula=false => outputFile is C string. TXT linebreaks become spaces.
386 daniel-mar 538
// isFormula=true  => outputFile is C string. TXT line breaks become CRLF line breaks
539
Boolean _picoReadProperty(char* inputFile, int maxInput, const char* property, char* outputFile, size_t maxOutput, Boolean isFormula) {
540
        int i;
541
        char* outputwork;
542
        char* sline;
543
        char* svalue;
544
        char* inputwork;
545
        char* inputworkinitial;
546
        outputwork = outputFile;
547
        sline = NULL;
548
        svalue = NULL;
385 daniel-mar 549
        // Check parameters
386 daniel-mar 550
        if (maxOutput == 0) return false;
385 daniel-mar 551
        if (inputFile == 0) return false;
552
        // Let input memory be read-only, +1 for terminal zero
553
        //char* inputwork = inputFile;
386 daniel-mar 554
        inputwork = (char*)malloc(maxInput + 1);
555
        inputworkinitial = inputwork;
385 daniel-mar 556
        if (inputwork == 0) return false;
557
        memcpy(inputwork, inputFile, maxInput);
388 daniel-mar 558
        inputwork[maxInput] = 0; // otherwise strstr() will crash
559
 
560
        // Transform "FFDecomp" TXT file into the similar "PluginCommander" TXT file
561
        if (strstr(inputwork, "Filter Factory Plugin Information:")) {
562
                char* x;
563
                char* k1;
564
                char* k2;
565
                // Metadata:
566
                x = strstr(inputwork, "CATEGORY:");
389 daniel-mar 567
                if (x) memcpy(x, "Category:", strlen("Category:"));
388 daniel-mar 568
                x = strstr(inputwork, "TITLE:");
389 daniel-mar 569
                if (x) memcpy(x, "Title:", strlen("Title:"));
388 daniel-mar 570
                x = strstr(inputwork, "COPYRIGHT:");
389 daniel-mar 571
                if (x) memcpy(x, "Copyright:", strlen("Copyright:"));
388 daniel-mar 572
                x = strstr(inputwork, "AUTHOR:");
389 daniel-mar 573
                if (x) memcpy(x, "Author:", strlen("Author:"));
388 daniel-mar 574
                // Controls:
575
                for (i = 0; i < 8; i++) {
576
                        k1 = (char*)malloc(strlen("Control X:") + 1);
577
                        sprintf(k1, "Control %d:", i);
578
                        x = strstr(inputwork, k1);
579
                        if (x) {
580
                                k2 = (char*)malloc(strlen("ctl[X]:   ") + 1);
581
                                sprintf(k2, "ctl[%d]:   ", i);
389 daniel-mar 582
                                memcpy(x, k2, strlen(k2));
388 daniel-mar 583
                                x += strlen("ctl[X]");
584
                                _ffdcomp_removebrackets(x, inputwork + maxInput - 1);
585
                                free(k2);
586
                        }
587
                        free(k1);
588
                }
589
                // Maps:
590
                for (i = 0; i < 4; i++) {
591
                        k1 = (char*)malloc(strlen("Map X:") + 1);
592
                        sprintf(k1, "Map %d:", i);
593
                        x = strstr(inputwork, k1);
594
                        if (x) {
595
                                k2 = (char*)malloc(strlen("map[X]:") + 1);
596
                                sprintf(k2, "map[%d]:", i);
389 daniel-mar 597
                                memcpy(x, k2, strlen(k2));
388 daniel-mar 598
                                x += strlen("map[X]");
599
                                _ffdcomp_removebrackets(x, inputwork + maxInput - 1);
600
                                free(k2);
601
                        }
602
                        free(k1);
603
                }
604
                // Convert all '\r' to '\n' for the next step to be easier
605
                for (i = 0; i < maxInput; i++) {
606
                        if (inputworkinitial[i] == CR) inputworkinitial[i] = LF;
607
                }
608
                x = strstr(inputwork, "\nR=\n");
389 daniel-mar 609
                if (x) memcpy(x, "\nR:\n", strlen("\nR:\n"));
388 daniel-mar 610
                x = strstr(inputwork, "\nG=\n");
389 daniel-mar 611
                if (x) memcpy(x, "\nG:\n", strlen("\nG:\n"));
388 daniel-mar 612
                x = strstr(inputwork, "\nB=\n");
389 daniel-mar 613
                if (x) memcpy(x, "\nB:\n", strlen("\nB:\n"));
388 daniel-mar 614
                x = strstr(inputwork, "\nA=\n");
389 daniel-mar 615
                if (x) memcpy(x, "\nA:\n", strlen("\nA:\n"));
388 daniel-mar 616
        }
385 daniel-mar 617
        // Replace all \r and \n with \0, so that we can parse easier
386 daniel-mar 618
        for (i = 0; i < maxInput; i++) {
388 daniel-mar 619
                if (inputworkinitial[i] == CR) inputworkinitial[i] = 0;
393 daniel-mar 620
                else if (inputworkinitial[i] == LF) inputworkinitial[i] = 0;
385 daniel-mar 621
        }
388 daniel-mar 622
 
385 daniel-mar 623
        // Find line that contains out key
388 daniel-mar 624
        inputwork = inputworkinitial;
385 daniel-mar 625
        do {
626
                if (inputwork > inputworkinitial + maxInput) {
627
                        // Key not found. Set output to empty string
628
                        outputwork[0] = 0;
629
                        free(inputworkinitial);
630
                        return false;
631
                }
632
                sline = inputwork;
633
                inputwork += strlen(sline) + 1;
634
                if (inputwork - 1 > inputworkinitial + maxInput) {
635
                        // Key not found. Set output to empty string
636
                        // TODO: will that be ever called?
637
                        outputwork[0] = 0;
638
                        free(inputworkinitial);
639
                        return false;
640
                }
641
        } while (!_picoLineContainsKey(sline, &svalue, property));
388 daniel-mar 642
 
385 daniel-mar 643
        // Read line(s) until we find a line with another key, or the line end
644
        do {
387 daniel-mar 645
                while ((svalue[0] == ' ') || (svalue[0] == TAB)) svalue++; // Trim left
646
                while ((svalue[strlen(svalue) - 1] == ' ') || (svalue[strlen(svalue) - 1] == TAB)) svalue[strlen(svalue) - 1] = 0; // Trim right
386 daniel-mar 647
 
385 daniel-mar 648
                if (strlen(svalue) > 0) {
393 daniel-mar 649
                        if (outputwork + strlen(svalue) + (isFormula ? 3/*CRLF+NUL*/ : 2/*space+NUL*/) > outputFile + maxOutput) {
385 daniel-mar 650
                                int remaining = maxOutput - (outputwork - outputFile) - 1;
651
                                //printf("BUFFER FULL (remaining = %d)\n", remaining);
652
                                memcpy(outputwork, svalue, remaining);
653
                                outputwork += remaining;
654
                                outputwork[0] = 0;
655
                                free(inputworkinitial);
656
                                return true;
657
                        }
658
                        else {
659
                                memcpy(outputwork, svalue, strlen(svalue));
660
                                outputwork += strlen(svalue);
386 daniel-mar 661
                                if (isFormula) {
662
                                        // Formulas: TXT line break stays line break (important if you have comments!)
388 daniel-mar 663
                                        outputwork[0] = CR;
664
                                        outputwork[1] = LF;
387 daniel-mar 665
                                        outputwork += 2;
386 daniel-mar 666
                                }
667
                                else {
668
                                        // Everything else: TXT line breaks becomes single whitespace
669
                                        outputwork[0] = ' ';
670
                                        outputwork++;
671
                                }
385 daniel-mar 672
                        }
673
                }
674
                outputwork[0] = 0;
675
 
676
                // Process next line
677
                if (inputwork > inputworkinitial + maxInput) break;
678
                sline = inputwork;
679
                inputwork += strlen(sline) + 1;
386 daniel-mar 680
                if (inputwork - 1 > inputworkinitial + maxInput) break; // TODO: will that be ever called?
385 daniel-mar 681
        } while (!_picoLineContainsKey(sline, &svalue, NULL));
388 daniel-mar 682
 
385 daniel-mar 683
        // Remove trailing whitespace
684
        if (outputwork > outputFile) {
685
                outputwork -= 1;
686
                outputwork[0] = 0;
687
        }
688
        free(inputworkinitial);
689
        return true;
690
}
691
 
692
Boolean readfile_picotxt(StandardFileReply* sfr, char** reason) {
389 daniel-mar 693
        extern int ctls[], maps[];
694
 
385 daniel-mar 695
        Handle h;
696
        Boolean res = false;
697
        FILEREF refnum;
698
 
699
        if (!fileHasExtension(sfr, ".txt")) return false;
700
 
701
        if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
702
                if ((h = readfileintohandle(refnum))) {
703
                        FILECOUNT count = PIGETHANDLESIZE(h);
704
                        char* q = PILOCKHANDLE(h, false);
705
 
706
                        char out[256];
707
                        if (_picoReadProperty(q, count, "Title", out, sizeof(out), false)) {
386 daniel-mar 708
                                int i;
385 daniel-mar 709
 
710
                                // Plugin infos
393 daniel-mar 711
                                _picoReadProperty(q, count, "Title", gdata->parm.szTitle, sizeof(gdata->parm.szTitle), false);
712
                                _picoReadProperty(q, count, "Category", gdata->parm.szCategory, sizeof(gdata->parm.szCategory), false);
713
                                _picoReadProperty(q, count, "Author", gdata->parm.szAuthor, sizeof(gdata->parm.szAuthor), false);
714
                                _picoReadProperty(q, count, "Copyright", gdata->parm.szCopyright, sizeof(gdata->parm.szCopyright), false);
715
                                //_picoReadProperty(q, count, "Filename", gdata->parm.xxx, sizeof(gdata->parm.xxx), false);
385 daniel-mar 716
 
717
                                // Expressions
393 daniel-mar 718
                                if (!_picoReadProperty(q, count, "R", gdata->parm.szFormula[0], sizeof(gdata->parm.szFormula[0]), true))
719
                                        strcpy(gdata->parm.szFormula[0], "r");
720
                                if (!_picoReadProperty(q, count, "G", gdata->parm.szFormula[1], sizeof(gdata->parm.szFormula[1]), true))
721
                                        strcpy(gdata->parm.szFormula[1], "g");
722
                                if (!_picoReadProperty(q, count, "B", gdata->parm.szFormula[2], sizeof(gdata->parm.szFormula[2]), true))
723
                                        strcpy(gdata->parm.szFormula[2], "b");
724
                                if (!_picoReadProperty(q, count, "A", gdata->parm.szFormula[3], sizeof(gdata->parm.szFormula[3]), true))
725
                                        strcpy(gdata->parm.szFormula[3], "a");
386 daniel-mar 726
                                for (i = 0; i < 4; i++) {
385 daniel-mar 727
                                        if (expr[i]) free(expr[i]);
393 daniel-mar 728
                                        expr[i] = my_strdup(gdata->parm.szFormula[i]);
385 daniel-mar 729
                                }
730
 
731
                                // Slider names
386 daniel-mar 732
                                for (i = 0; i < 8; i++) {
385 daniel-mar 733
                                        char keyname[7];
734
                                        sprintf(keyname, "ctl[%d]", i);
393 daniel-mar 735
                                        _picoReadProperty(q, count, keyname, gdata->parm.szCtl[i], sizeof(gdata->parm.szCtl[i]), false);
385 daniel-mar 736
                                }
737
 
738
                                // Slider values
386 daniel-mar 739
                                for (i = 0; i < 8; i++) {
740
                                        char keyname[7], tmp[5];
385 daniel-mar 741
                                        sprintf(keyname, "val[%d]", i);
742
                                        if (!_picoReadProperty(q, count, keyname, tmp, sizeof(tmp), false)) {
743
                                                sprintf(keyname, "def[%d]", i);
744
                                                if (!_picoReadProperty(q, count, keyname, tmp, sizeof(tmp), false)) {
393 daniel-mar 745
                                                        strcpy(tmp,"0");
385 daniel-mar 746
                                                }
747
                                        }
748
                                        gdata->parm.val[i] = slider[i] = atoi(tmp);
749
                                }
750
 
751
                                // Map names
386 daniel-mar 752
                                for (i = 0; i < 4; i++) {
385 daniel-mar 753
                                        char keyname[7];
754
                                        sprintf(keyname, "map[%d]", i);
393 daniel-mar 755
                                        _picoReadProperty(q, count, keyname, gdata->parm.szMap[i], sizeof(gdata->parm.szMap[i]), false);
385 daniel-mar 756
                                }
757
 
389 daniel-mar 758
                                //These will be set when the expressions are evaluated anyway. So this part is optional:
759
                                checksliders(4, ctls, maps);
760
                                for (i = 0; i < 8; i++) gdata->parm.ctl_used[i] = ctls[i];
761
                                for (i = 0; i < 4; i++) gdata->parm.map_used[i] = maps[i];
385 daniel-mar 762
 
763
                                res = true;
764
                        }
765
 
766
                        PIUNLOCKHANDLE(h);
767
                        PIDISPOSEHANDLE(h);
768
                }
769
                FSClose(refnum);
770
        }
771
 
772
        return res;
773
}
774
 
366 daniel-mar 775
Boolean readfile_afs_pff(StandardFileReply *sfr,char **reason){
256 daniel-mar 776
        FILEREF r;
777
        Handle h;
778
        Boolean res = false;
779
 
780
        if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&r) == noErr){
781
                if( (h = readfileintohandle(r)) ){
408 daniel-mar 782
                        if( (res = readparams_afs_pff(h,reason)) ) {
256 daniel-mar 783
                                gdata->standalone = false; // so metadata fields will default, if user chooses Make...
784
 
785
                                if (fileHasExtension(sfr, ".pff")) {
786
                                        // If it is a Premiere settings file, we need to swap the channels red and blue
263 daniel-mar 787
                                        // We just swap the pointers!
256 daniel-mar 788
                                        char* tmp;
263 daniel-mar 789
                                        tmp = expr[0];
790
                                        expr[0] = expr[2];
791
                                        expr[2] = tmp;
256 daniel-mar 792
                                }
793
                        }
794
 
795
                        PIDISPOSEHANDLE(h);
796
                }
797
                FSClose(r);
798
        }else
799
                *reason = _strdup("Could not open the file.");
800
 
801
        return res;
802
}