Subversion Repositories filter_foundry

Rev

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