Subversion Repositories filter_foundry

Rev

Rev 556 | 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
536 daniel-mar 3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.net
541 daniel-mar 4
    Copyright (C) 2018-2023 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
 
518 daniel-mar 36
#define BUFSIZE 4L<<10
37
#define MAXLINE 0x200
256 daniel-mar 38
 
553 daniel-mar 39
FFLoadingResult readparams_afs_pff(Handle h, Boolean premiereOrder){
552 daniel-mar 40
        FFLoadingResult res = MSG_LOADFILE_UNKNOWN_FORMAT_ID;
544 daniel-mar 41
        char linebuf[MAXLINE] = { 0 };
42
        char curexpr[MAXEXPR] = { 0 };
454 daniel-mar 43
        char *p, *dataend, *q;
256 daniel-mar 44
        char c;
45
        int linecnt, lineptr, exprcnt;
46
 
552 daniel-mar 47
        //if (!h) return nilHandleErr;
256 daniel-mar 48
 
49
        p = PILOCKHANDLE(h,false);
50
        dataend = p + PIGETHANDLESIZE(h);
51
 
52
        q = curexpr;
53
        linecnt = exprcnt = lineptr = 0;
54
 
55
        while(p < dataend){
56
 
57
                c = *p++;
58
 
59
                if(c==CR || c==LF){ /* detected end of line */
60
 
421 daniel-mar 61
                        /* look ahead to see if we need to skip a line feed (DOS CRLF EOL convention) */
62
                        if(p < dataend && c == CR && *p == LF)
256 daniel-mar 63
                                ++p;
64
 
539 daniel-mar 65
                        linebuf[lineptr] = '\0'; /* add terminating NUL to line buffer */
256 daniel-mar 66
 
67
                        /* process complete line */
68
                        if(linecnt==0){
539 daniel-mar 69
                                if(strcmp(linebuf,"%RGB-1.0") != 0){
553 daniel-mar 70
                                        res = MSG_INVALID_FILE_SIGNATURE_ID;
256 daniel-mar 71
                                        break;
72
                                }
73
                        }else if(linecnt<=8){
453 daniel-mar 74
                                int v;
75
                                v = atoi(linebuf);
76
                                if (v < 0) v = 0;
456 daniel-mar 77
                                else if (v > 255) v = 255;
550 daniel-mar 78
                                gdata->parm.val[linecnt-1] = (uint8_t)v;
256 daniel-mar 79
                        }else{
80
                                if(lineptr){
81
                                        /* it's not an empty line; append it to current expr string */
544 daniel-mar 82
                                        if( (q-curexpr) + lineptr >= MAXEXPR) {
552 daniel-mar 83
                                                res = MSG_EXPRESSION1024_FOUND_ID;
256 daniel-mar 84
                                                break;
85
                                        }
86
                                        q = cat(q,linebuf);
87
                                }else{
88
                                        /* it's an empty line: we've completed the expr string */
539 daniel-mar 89
                                        *q = '\0';
553 daniel-mar 90
                                        if (premiereOrder) {
555 daniel-mar 91
                                                // Premiere has the order BGRA, while Photoshop (and our internal order) is RGBA
553 daniel-mar 92
                                                if (exprcnt == 0) strcpy(gdata->parm.szFormula[2], curexpr);
93
                                                else if (exprcnt == 2) strcpy(gdata->parm.szFormula[0], curexpr);
94
                                                else strcpy(gdata->parm.szFormula[exprcnt], curexpr);
95
                                        }
96
                                        else {
97
                                                strcpy(gdata->parm.szFormula[exprcnt], curexpr);
98
                                        }
256 daniel-mar 99
 
100
                                        if(++exprcnt == 4){
557 daniel-mar 101
                                                res = LOADING_OK;
256 daniel-mar 102
                                                break; /* got everything we want */
103
                                        }
104
 
105
                                        q = curexpr; /* empty current expr, ready for next one */
106
                                }
107
                        }
108
 
109
                        ++linecnt;
110
                        lineptr = 0;
111
                }else{
112
                        /* store character */
113
                        if(c=='\\'){ /* escape sequence */
114
                                if(p < dataend){
115
                                        c = *p++;
116
                                        switch(c){
117
                                        case 'r':
268 daniel-mar 118
                                                #if WIN_ENV
119
                                                c = CR;
544 daniel-mar 120
                                                if (lineptr < MAXLINE-1)
274 daniel-mar 121
                                                        linebuf[lineptr++] = c;
268 daniel-mar 122
                                                c = LF;
123
                                                #else
124
                                                c = CR;
125
                                                #endif
126
                                                break;
256 daniel-mar 127
                                        case '\\': break;
408 daniel-mar 128
                                        //default:
492 daniel-mar 129
                                        //      if(alerts) alertuser((TCHAR*)TEXT("Warning:"),TEXT("Unknown escape sequence in input.")); // TODO (Not so important): TRANSLATE
256 daniel-mar 130
                                        }
492 daniel-mar 131
                                }//else if(alerts) alertuser((TCHAR*)TEXT("Warning:"),TEXT("truncated escape sequence ends input")); // TODO (Not so important): TRANSLATE
256 daniel-mar 132
                        }
133
 
544 daniel-mar 134
                        if(lineptr < MAXLINE-1)
256 daniel-mar 135
                                linebuf[lineptr++] = c;
136
                }
137
        }
138
 
139
        PIUNLOCKHANDLE(h);
140
 
141
        return res;
142
}
143
 
144
void convert_premiere_to_photoshop(PARM_T* photoshop, PARM_T_PREMIERE* premiere) {
145
        int i;
146
 
147
        photoshop->cbSize = sizeof(PARM_T);
148
        photoshop->standalone = premiere->standalone;
149
        for (i=0;i<8;++i)
272 daniel-mar 150
                photoshop->val[i] = premiere->val[i];
256 daniel-mar 151
        photoshop->popDialog = premiere->popDialog;
152
        photoshop->unknown1 = premiere->unknown1;
153
        photoshop->unknown2 = premiere->unknown2;
154
        photoshop->unknown3 = premiere->unknown3;
155
        for (i=0;i<4;++i)
272 daniel-mar 156
                photoshop->map_used[i] = premiere->map_used[i];
256 daniel-mar 157
        for (i=0;i<8;++i)
272 daniel-mar 158
                photoshop->ctl_used[i] = premiere->ctl_used[i];
393 daniel-mar 159
        sprintf(photoshop->szCategory, "Filter Factory"); // Premiere plugins do not have a category attribute
256 daniel-mar 160
        photoshop->iProtected = 0; // Premiere plugins do not have a protect flag
393 daniel-mar 161
        memcpy((void*)photoshop->szTitle, (void*)premiere->szTitle, sizeof(photoshop->szTitle));
162
        memcpy((void*)photoshop->szCopyright, (void*)premiere->szCopyright, sizeof(photoshop->szCopyright));
163
        memcpy((void*)photoshop->szAuthor, (void*)premiere->szAuthor, sizeof(photoshop->szAuthor));
256 daniel-mar 164
        for (i=0;i<4;++i)
393 daniel-mar 165
                memcpy((void*)photoshop->szMap[i], (void*)premiere->szMap[i], sizeof(photoshop->szMap[i]));
256 daniel-mar 166
        for (i=0;i<8;++i)
393 daniel-mar 167
                memcpy((void*)photoshop->szCtl[i], (void*)premiere->szCtl[i], sizeof(photoshop->szCtl[i]));
256 daniel-mar 168
 
169
        if (premiere->singleExpression) {
393 daniel-mar 170
                memcpy((void*)photoshop->szFormula[0], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
171
                memcpy((void*)photoshop->szFormula[1], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
172
                memcpy((void*)photoshop->szFormula[2], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
173
                memcpy((void*)photoshop->szFormula[3], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
256 daniel-mar 174
        } else {
393 daniel-mar 175
                memcpy((void*)photoshop->szFormula[0], (void*)premiere->szFormula[2], sizeof(photoshop->szFormula[2]));
176
                memcpy((void*)photoshop->szFormula[1], (void*)premiere->szFormula[1], sizeof(photoshop->szFormula[1]));
177
                memcpy((void*)photoshop->szFormula[2], (void*)premiere->szFormula[0], sizeof(photoshop->szFormula[0]));
178
                memcpy((void*)photoshop->szFormula[3], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
256 daniel-mar 179
        }
180
}
181
 
366 daniel-mar 182
char* _ffx_read_str(char** q) {
183
        uint32_t len;
184
        char* val;
185
 
186
        len = *((uint32_t*)*q);
187
        *q += sizeof(uint32_t);
454 daniel-mar 188
        val = (char*)malloc((size_t)len + 1);
366 daniel-mar 189
        if (val != NULL) {
190
                memcpy(val, (char*)*q, len);
539 daniel-mar 191
                val[len] = '\0';
366 daniel-mar 192
        }
193
        *q += len;
194
        return val;
195
}
196
 
552 daniel-mar 197
FFLoadingResult readfile_ffx(StandardFileReply* sfr) {
366 daniel-mar 198
        Handle h;
552 daniel-mar 199
        FFLoadingResult res = MSG_LOADFILE_UNKNOWN_FORMAT_ID;
366 daniel-mar 200
        FILEREF refnum;
201
        uint32_t len;
202
        char* val;
367 daniel-mar 203
        int format_version = -1;
366 daniel-mar 204
        int i;
205
 
206
        if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
207
                if ((h = readfileintohandle(refnum))) {
208
                        char* q = (char*)PILOCKHANDLE(h, false);
209
 
210
                        len = *((uint32_t*)q);
554 daniel-mar 211
                        if (len != 6) {
212
                                res = MSG_INVALID_FILE_SIGNATURE_ID;
213
                        } else {
366 daniel-mar 214
                                val = _ffx_read_str(&q);
367 daniel-mar 215
                                if (strcmp(val, "FFX1.0") == 0) format_version = 10;
216
                                else if (strcmp(val, "FFX1.1") == 0) format_version = 11;
217
                                else if (strcmp(val, "FFX1.2") == 0) format_version = 12;
366 daniel-mar 218
                                free(val);
554 daniel-mar 219
                                if (format_version < 0) {
220
                                        res = MSG_INVALID_FILE_SIGNATURE_ID;
221
                                } else {
492 daniel-mar 222
                                        simplewarning_id(MSG_FILTERS_UNLIMITED_WARNING_ID);
368 daniel-mar 223
 
366 daniel-mar 224
                                        val = _ffx_read_str(&q);
541 daniel-mar 225
                                        if (strlen(val) >= sizeof(gdata->parm.szTitle)) {
226
                                                val[sizeof(gdata->parm.szTitle) - 1] = '\0';
227
                                        }
393 daniel-mar 228
                                        strcpy(gdata->parm.szTitle, val);
366 daniel-mar 229
                                        free(val);
230
 
231
                                        val = _ffx_read_str(&q);
541 daniel-mar 232
                                        if (strlen(val) >= sizeof(gdata->parm.szCategory)) {
233
                                                val[sizeof(gdata->parm.szCategory) - 1] = '\0';
234
                                        }
393 daniel-mar 235
                                        strcpy(gdata->parm.szCategory, val);
366 daniel-mar 236
                                        free(val);
237
 
238
                                        val = _ffx_read_str(&q);
541 daniel-mar 239
                                        if (strlen(val) >= sizeof(gdata->parm.szAuthor)) {
240
                                                val[sizeof(gdata->parm.szAuthor) - 1] = '\0';
241
                                        }
393 daniel-mar 242
                                        strcpy(gdata->parm.szAuthor, val);
366 daniel-mar 243
                                        free(val);
244
 
245
                                        val = _ffx_read_str(&q);
541 daniel-mar 246
                                        if (strlen(val) >= sizeof(gdata->parm.szCopyright)) {
247
                                                val[sizeof(gdata->parm.szCopyright) - 1] = '\0';
248
                                        }
393 daniel-mar 249
                                        strcpy(gdata->parm.szCopyright, val);
366 daniel-mar 250
                                        free(val);
251
 
252
                                        // Channels I, R, G, B, A
253
                                        for (i = 0; i < 4; i++) {
254
                                                val = _ffx_read_str(&q);
255
                                                if (i == 0) {
370 daniel-mar 256
                                                        char* val2 = _ffx_read_str(&q);
366 daniel-mar 257
                                                        if (strcmp(val, "0") != 0) {
258
                                                                // "Intro channel" existing
370 daniel-mar 259
                                                                // C++ wrong warning: Using uninitialized memory "val2" (C6001)
260
                                                                #pragma warning(suppress : 6001)
541 daniel-mar 261
                                                                char* combined = (char*)malloc(strlen(val) + strlen(",") + strlen(val2) + 1/*NUL byte*/);
370 daniel-mar 262
                                                                if (combined != NULL) {
263
                                                                        sprintf(combined, "%s,%s", val, val2);
264
                                                                        free(val);
265
                                                                        free(val2);
266
                                                                        val = combined;
267
                                                                }
366 daniel-mar 268
                                                        }
269
                                                        else {
270
                                                                free(val);
370 daniel-mar 271
                                                                val = val2;
366 daniel-mar 272
                                                        }
273
                                                }
393 daniel-mar 274
                                                if (strlen(val) >= sizeof(gdata->parm.szFormula[i])) {
368 daniel-mar 275
                                                        if (i == 0) {
492 daniel-mar 276
                                                                simplealert_id(MSG_FORMULA_IR_1023_TRUNCATED_ID);
368 daniel-mar 277
                                                        }
278
                                                        else if (i == 1) {
492 daniel-mar 279
                                                                simplealert_id(MSG_FORMULA_G_1023_TRUNCATED_ID);
368 daniel-mar 280
                                                        }
281
                                                        else if (i == 2) {
492 daniel-mar 282
                                                                simplealert_id(MSG_FORMULA_B_1023_TRUNCATED_ID);
368 daniel-mar 283
                                                        }
284
                                                        else if (i == 3) {
492 daniel-mar 285
                                                                simplealert_id(MSG_FORMULA_A_1023_TRUNCATED_ID);
368 daniel-mar 286
                                                        }
370 daniel-mar 287
                                                        // C++ wrong warning: Buffer overflow (C6386)
288
                                                        #pragma warning(suppress : 6386)
393 daniel-mar 289
                                                        val[sizeof(gdata->parm.szFormula[i]) - 1] = '\0';
368 daniel-mar 290
                                                }
393 daniel-mar 291
                                                strcpy(gdata->parm.szFormula[i], val);
366 daniel-mar 292
                                                free(val);
293
                                        }
294
 
295
                                        // Sliders
296
                                        for (i = 0; i < 8; i++) {
367 daniel-mar 297
                                                char* sliderName;
453 daniel-mar 298
                                                int v;
366 daniel-mar 299
                                                val = _ffx_read_str(&q);
367 daniel-mar 300
                                                sliderName = val;
301
                                                if (format_version >= 12) {
302
                                                        // Format FFX1.2 has prefixes {S} = Slider, {C} = Checkbox, none = Slider
303
                                                        if ((sliderName[0] == '{') && (sliderName[1] == 'S') && (sliderName[2] == '}')) sliderName += 3;
304
                                                        else if ((sliderName[0] == '{') && (sliderName[1] == 'C') && (sliderName[2] == '}')) sliderName += 3;
305
                                                }
541 daniel-mar 306
                                                if (strlen(val) >= sizeof(gdata->parm.szCtl[i])) {
307
                                                        val[sizeof(gdata->parm.szCtl[i]) - 1] = '\0';
308
                                                }
393 daniel-mar 309
                                                strcpy(gdata->parm.szCtl[i], sliderName);
366 daniel-mar 310
                                                free(val);
367 daniel-mar 311
                                                gdata->parm.ctl_used[i] = (bool32_t)*((byte*)q);
366 daniel-mar 312
                                                q += sizeof(byte);
313
                                                gdata->parm.val[i] = *((uint32_t*)q);
453 daniel-mar 314
                                                v = *((uint32_t*)q);
315
                                                if (v < 0) v = 0;
456 daniel-mar 316
                                                else if (v > 255) v = 255;
550 daniel-mar 317
                                                gdata->parm.val[i] = (uint8_t)v;
366 daniel-mar 318
                                                q += sizeof(uint32_t);
319
                                        }
320
 
390 daniel-mar 321
                                        // Maps (are not part of the format!)
393 daniel-mar 322
                                        strcpy(gdata->parm.szMap[0], "Map 0:");
323
                                        strcpy(gdata->parm.szMap[1], "Map 1:");
324
                                        strcpy(gdata->parm.szMap[2], "Map 2:");
325
                                        strcpy(gdata->parm.szMap[3], "Map 3:");
390 daniel-mar 326
 
557 daniel-mar 327
                                        res = LOADING_OK;
366 daniel-mar 328
                                }
329
                        }
330
                        PIDISPOSEHANDLE(h);
331
                }
332
                FSClose(refnum);
333
        }
334
 
557 daniel-mar 335
        if (res == LOADING_OK) gdata->obfusc = false;
366 daniel-mar 336
        return res;
337
}
338
 
552 daniel-mar 339
FFLoadingResult readfile_8bf(StandardFileReply *sfr){
256 daniel-mar 340
        unsigned char magic[2];
341
        FILECOUNT count;
342
        Handle h;
552 daniel-mar 343
        FFLoadingResult res = MSG_LOADFILE_UNKNOWN_FORMAT_ID;
256 daniel-mar 344
        FILEREF refnum;
345
 
346
        if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&refnum) == noErr){
347
                // check DOS EXE magic number
348
                count = 2;
349
                if(FSRead(refnum,&count,magic) == noErr /*&& magic[0]=='M' && magic[1]=='Z'*/){
309 daniel-mar 350
                        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 351
                                if( (h = readfileintohandle(refnum)) ){
352
                                        long *q = (long*)PILOCKHANDLE(h,false);
353
 
354
                                        // look for signature at start of valid PARM resource
355
                                        // This signature is observed in Filter Factory standalones.
356
                                        for( count /= 4 ; count >= PARM_SIZE/4 ; --count, ++q )
357
                                        {
394 daniel-mar 358
                                                res = readPARM(&gdata->parm, (Ptr)q);
557 daniel-mar 359
                                                if (res == LOADING_OK) break;
256 daniel-mar 360
                                        }
341 daniel-mar 361
 
256 daniel-mar 362
                                        PIDISPOSEHANDLE(h);
363
                                }
364
                        }
365
                } // else no point in proceeding
366
                FSClose(refnum);
367
        }else
552 daniel-mar 368
                res = MSG_CANNOT_OPEN_FILE_ID;
256 daniel-mar 369
 
557 daniel-mar 370
        if (res == LOADING_OK) gdata->obfusc = false;
256 daniel-mar 371
        return res;
372
}
373
 
552 daniel-mar 374
FFLoadingResult readPARM(PARM_T* pparm, Ptr p){
394 daniel-mar 375
        Boolean towin, tomac, fromwin, frommac;
376
        unsigned int signature = *((unsigned int*)p);
377
        unsigned int standalone = *((unsigned int*)p+1);
256 daniel-mar 378
 
394 daniel-mar 379
        // Find out our OS ("reader") the OS of the plugin ("source")
380
        #ifdef MAC_ENV
381
        towin = false;
382
        tomac = true;
383
        fromwin = ((EndianS32_LtoN(signature) == PARM_SIZE) ||
384
                (EndianS32_LtoN(signature) == PARM_SIZE_PREMIERE) ||
385
                (EndianS32_LtoN(signature) == PARM_SIG_MAC)) && EndianS32_LtoN(standalone) == 1;
386
        frommac = ((signature == PARM_SIZE) ||
387
                (signature == PARM_SIZE_PREMIERE) ||
388
                (signature == PARM_SIG_MAC)) && standalone == 1;
389
        #else
390
        towin = true;
391
        tomac = false;
392
        fromwin = ((signature == PARM_SIZE) ||
393
                (signature == PARM_SIZE_PREMIERE) ||
394
                (signature == PARM_SIG_MAC)) && standalone == 1;
395
        frommac = ((EndianS32_LtoN(signature) == PARM_SIZE) ||
396
                (EndianS32_LtoN(signature) == PARM_SIZE_PREMIERE) ||
397
                (EndianS32_LtoN(signature) == PARM_SIG_MAC)) && EndianS32_LtoN(standalone) == 1;
398
        #endif
399
 
400
        // Is it a valid signature?
401
        if (!fromwin && !frommac) {
402
                // No valid signature found
552 daniel-mar 403
                return MSG_INVALID_FILE_SIGNATURE_ID;
394 daniel-mar 404
        }
405
 
406
        // Does it come from Premiere or Photoshop?
407
        // Initialize pparm
408
        if ((signature == PARM_SIZE_PREMIERE) || (EndianS32_LtoN(signature) == PARM_SIZE_PREMIERE)) {
409
                // It comes from Premiere. Swap R and B channel and convert to a Photoshop PARM_T
256 daniel-mar 410
                convert_premiere_to_photoshop(pparm, (PARM_T_PREMIERE*)p);
411
        } else {
394 daniel-mar 412
                // It is already Photoshop. Just copy to pparm.
413
                memcpy(pparm, p, sizeof(PARM_T));
256 daniel-mar 414
        }
415
 
394 daniel-mar 416
        // Do we need to do string conversion?
417
        if (frommac) {
456 daniel-mar 418
                int i;
419
 
394 daniel-mar 420
                /* Mac PARM resource stores Pascal strings - convert to C strings, since this is what we work internally with (regardles of OS) */
393 daniel-mar 421
                myp2cstr((unsigned char*)pparm->szCategory);
422
                myp2cstr((unsigned char*)pparm->szTitle);
423
                myp2cstr((unsigned char*)pparm->szCopyright);
424
                myp2cstr((unsigned char*)pparm->szAuthor);
394 daniel-mar 425
                for (i = 0; i < 4; ++i)
393 daniel-mar 426
                        myp2cstr((unsigned char*)pparm->szMap[i]);
394 daniel-mar 427
                for (i = 0; i < 8; ++i)
393 daniel-mar 428
                        myp2cstr((unsigned char*)pparm->szCtl[i]);
256 daniel-mar 429
        }
430
 
394 daniel-mar 431
        // Case #1: Mac is reading Windows (Win16/32/64) plugin
432
        if (fromwin && tomac) {
433
                size_t i;
434
 
435
                // Convert copyright CRLF to CR (actually, just removing LF)
454 daniel-mar 436
                char copyrightCRLF[256] = { 0 };
456 daniel-mar 437
                char* pCopyright = &copyrightCRLF[0];
394 daniel-mar 438
                for (i = 0; i < strlen(pparm->szCopyright); i++) {
439
                        if (pparm->szCopyright[i] != LF) {
456 daniel-mar 440
                                *pCopyright++ = pparm->szCopyright[i];
394 daniel-mar 441
                        }
442
                }
456 daniel-mar 443
                *pCopyright++ = '\0';
394 daniel-mar 444
                strcpy(pparm->szCopyright, copyrightCRLF);
445
 
446
                // these are the only numeric fields we *have* to swap
447
                // all the rest are bool_t flags which (if we're careful) will work in either ordering
448
                for (i = 0; i < 8; ++i)
449
                        pparm->val[i] = EndianS32_LtoN(pparm->val[i]);
450
        }
451
 
452
        // Case #2: Mac is reading Mac (in case the normal resource extraction didn't work)
453
        // Nothing to do
454
 
455
        // 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)
456
        // Nothing to do
457
 
458
        // Case #4: Windows is reading an old FilterFactory Mac file
459
        // Note: You must read the ".rsrc" resource fork, not the standalone binary!
460
        if (frommac && towin) {
461
                size_t i;
462
 
463
                // Convert CR in the copyright field to CRLF.
454 daniel-mar 464
                char copyrightCRLF[256] = { 0 };
456 daniel-mar 465
                char* pCopyright = &copyrightCRLF[0];
394 daniel-mar 466
                for (i = 0; i < strlen(pparm->szCopyright); i++) {
456 daniel-mar 467
                        *pCopyright++ = pparm->szCopyright[i];
394 daniel-mar 468
                        if (pparm->szCopyright[i] == CR) {
456 daniel-mar 469
                                *pCopyright++ = LF;
394 daniel-mar 470
                        }
471
                }
456 daniel-mar 472
                *pCopyright++ = '\0';
394 daniel-mar 473
                strcpy(pparm->szCopyright, copyrightCRLF);
474
 
475
                // these are the only numeric fields we *have* to swap
476
                // all the rest are bool_t flags which (if we're careful) will work in either ordering
477
                for (i = 0; i < 8; ++i)
478
                        pparm->val[i] = EndianS32_LtoN(pparm->val[i]);
479
        }
480
 
552 daniel-mar 481
        return 0;
256 daniel-mar 482
}
483
 
484
Handle readfileintohandle(FILEREF r){
485
        FILEPOS n;
486
        Handle h;
487
        Ptr p;
488
 
489
        if( GetEOF(r,&n) == noErr && (h = PINEWHANDLE(n)) ){
490
                p = PILOCKHANDLE(h,false);
491
                if(SetFPos(r,fsFromStart,0) == noErr && FSRead(r,(FILECOUNT*)&n,p) == noErr){
492
                        PIUNLOCKHANDLE(h);
493
                        return h;
494
                }
495
                PIDISPOSEHANDLE(h);
496
        }
497
        return NULL;
498
}
499
 
385 daniel-mar 500
Boolean _picoLineContainsKey(char* line, char** content, const char* searchkey/*=NULL*/) {
386 daniel-mar 501
        size_t i;
502
        for (i = 0; i < strlen(line); i++) {
388 daniel-mar 503
                if (line[i] == '?') break; // avoid that "a?b:c" is detected as key
385 daniel-mar 504
                if (line[i] == ':') {
386 daniel-mar 505
                        // Note: We are ignoring whitespaces, i.e. " A :" != "A:" (TODO: should we change this?)
506
                        if ((searchkey == NULL) || ((i == strlen(searchkey)) && (memcmp(line, searchkey, i) == 0))) {
507
                                i++; // jump over ':' char
387 daniel-mar 508
                                //while ((line[i] == ' ') || (line[i] == TAB)) i++; // Trim value left
385 daniel-mar 509
                                *content = line + i;
510
                                return true;
511
                        }
512
                }
513
        }
514
        *content = line;
515
        return false;
516
}
517
 
388 daniel-mar 518
void _ffdcomp_removebrackets(char* x, char* maxptr) {
519
        char* closingBracketPos = NULL;
520
        Boolean openingBracketFound = false;
521
        if (x[0] == '[') {
522
                openingBracketFound = true;
523
        }
524
        x[0] = ':';
525
        x++;
526
        while (x < maxptr) {
527
                if ((!openingBracketFound) && (x[0] == '[')) {
528
                        openingBracketFound = true;
529
                        x[0] = ' ';
530
                }
531
                else if (openingBracketFound) {
532
                        if (x[0] == ']') {
533
                                closingBracketPos = x;
534
                        }
535
                        else if ((x[0] == CR) || (x[0] == LF)) {
536
                                if (closingBracketPos) closingBracketPos[0] = ' '; // last closing pos before CR/LF
537
                                break;
538
                        }
539
                }
540
                x++;
541
        }
542
}
543
 
393 daniel-mar 544
// isFormula=false => outputFile is C string. TXT linebreaks become spaces.
386 daniel-mar 545
// isFormula=true  => outputFile is C string. TXT line breaks become CRLF line breaks
505 daniel-mar 546
Boolean _picoReadProperty(char* inputFile, size_t maxInput, const char* property, char* outputFile, size_t maxOutput, Boolean isFormula) {
547
        size_t i;
386 daniel-mar 548
        char* outputwork;
549
        char* sline;
550
        char* svalue;
551
        char* inputwork;
552
        char* inputworkinitial;
553
        outputwork = outputFile;
554
        sline = NULL;
555
        svalue = NULL;
385 daniel-mar 556
        // Check parameters
386 daniel-mar 557
        if (maxOutput == 0) return false;
539 daniel-mar 558
        if (inputFile == NULL) return false;
385 daniel-mar 559
        // Let input memory be read-only, +1 for terminal zero
560
        //char* inputwork = inputFile;
541 daniel-mar 561
        inputwork = (char*)malloc((size_t)maxInput + 1/*NUL byte*/);
386 daniel-mar 562
        inputworkinitial = inputwork;
539 daniel-mar 563
        if (inputwork == NULL) return false;
385 daniel-mar 564
        memcpy(inputwork, inputFile, maxInput);
539 daniel-mar 565
        inputwork[maxInput] = '\0'; // otherwise strstr() will crash
388 daniel-mar 566
 
567
        // Transform "FFDecomp" TXT file into the similar "PluginCommander" TXT file
568
        if (strstr(inputwork, "Filter Factory Plugin Information:")) {
569
                char* x;
570
                char* k1;
571
                char* k2;
572
                // Metadata:
573
                x = strstr(inputwork, "CATEGORY:");
389 daniel-mar 574
                if (x) memcpy(x, "Category:", strlen("Category:"));
388 daniel-mar 575
                x = strstr(inputwork, "TITLE:");
389 daniel-mar 576
                if (x) memcpy(x, "Title:", strlen("Title:"));
388 daniel-mar 577
                x = strstr(inputwork, "COPYRIGHT:");
389 daniel-mar 578
                if (x) memcpy(x, "Copyright:", strlen("Copyright:"));
388 daniel-mar 579
                x = strstr(inputwork, "AUTHOR:");
389 daniel-mar 580
                if (x) memcpy(x, "Author:", strlen("Author:"));
388 daniel-mar 581
                // Controls:
582
                for (i = 0; i < 8; i++) {
541 daniel-mar 583
                        k1 = (char*)malloc(strlen("Control X:") + 1/*NUL byte*/);
505 daniel-mar 584
                        sprintf(k1, "Control %d:", (int)i);
388 daniel-mar 585
                        x = strstr(inputwork, k1);
586
                        if (x) {
541 daniel-mar 587
                                k2 = (char*)malloc(strlen("ctl[X]:   ") + 1/*NUL byte*/);
505 daniel-mar 588
                                sprintf(k2, "ctl[%d]:   ", (int)i);
389 daniel-mar 589
                                memcpy(x, k2, strlen(k2));
388 daniel-mar 590
                                x += strlen("ctl[X]");
591
                                _ffdcomp_removebrackets(x, inputwork + maxInput - 1);
592
                                free(k2);
593
                        }
594
                        free(k1);
595
                }
596
                // Maps:
597
                for (i = 0; i < 4; i++) {
541 daniel-mar 598
                        k1 = (char*)malloc(strlen("Map X:") + 1/*NUL byte*/);
505 daniel-mar 599
                        sprintf(k1, "Map %d:", (int)i);
388 daniel-mar 600
                        x = strstr(inputwork, k1);
601
                        if (x) {
541 daniel-mar 602
                                k2 = (char*)malloc(strlen("map[X]:") + 1/*NUL byte*/);
505 daniel-mar 603
                                sprintf(k2, "map[%d]:", (int)i);
389 daniel-mar 604
                                memcpy(x, k2, strlen(k2));
388 daniel-mar 605
                                x += strlen("map[X]");
606
                                _ffdcomp_removebrackets(x, inputwork + maxInput - 1);
607
                                free(k2);
608
                        }
609
                        free(k1);
610
                }
611
                // Convert all '\r' to '\n' for the next step to be easier
612
                for (i = 0; i < maxInput; i++) {
613
                        if (inputworkinitial[i] == CR) inputworkinitial[i] = LF;
614
                }
615
                x = strstr(inputwork, "\nR=\n");
389 daniel-mar 616
                if (x) memcpy(x, "\nR:\n", strlen("\nR:\n"));
388 daniel-mar 617
                x = strstr(inputwork, "\nG=\n");
389 daniel-mar 618
                if (x) memcpy(x, "\nG:\n", strlen("\nG:\n"));
388 daniel-mar 619
                x = strstr(inputwork, "\nB=\n");
389 daniel-mar 620
                if (x) memcpy(x, "\nB:\n", strlen("\nB:\n"));
388 daniel-mar 621
                x = strstr(inputwork, "\nA=\n");
389 daniel-mar 622
                if (x) memcpy(x, "\nA:\n", strlen("\nA:\n"));
388 daniel-mar 623
        }
385 daniel-mar 624
        // Replace all \r and \n with \0, so that we can parse easier
386 daniel-mar 625
        for (i = 0; i < maxInput; i++) {
539 daniel-mar 626
                if (inputworkinitial[i] == CR) inputworkinitial[i] = '\0';
627
                else if (inputworkinitial[i] == LF) inputworkinitial[i] = '\0';
385 daniel-mar 628
        }
388 daniel-mar 629
 
385 daniel-mar 630
        // Find line that contains out key
388 daniel-mar 631
        inputwork = inputworkinitial;
385 daniel-mar 632
        do {
633
                if (inputwork > inputworkinitial + maxInput) {
634
                        // Key not found. Set output to empty string
539 daniel-mar 635
                        outputwork[0] = '\0';
385 daniel-mar 636
                        free(inputworkinitial);
637
                        return false;
638
                }
639
                sline = inputwork;
640
                inputwork += strlen(sline) + 1;
641
                if (inputwork - 1 > inputworkinitial + maxInput) {
642
                        // Key not found. Set output to empty string
643
                        // TODO: will that be ever called?
539 daniel-mar 644
                        outputwork[0] = '\0';
385 daniel-mar 645
                        free(inputworkinitial);
646
                        return false;
647
                }
648
        } while (!_picoLineContainsKey(sline, &svalue, property));
388 daniel-mar 649
 
385 daniel-mar 650
        // Read line(s) until we find a line with another key, or the line end
651
        do {
387 daniel-mar 652
                while ((svalue[0] == ' ') || (svalue[0] == TAB)) svalue++; // Trim left
539 daniel-mar 653
                while ((svalue[strlen(svalue) - 1] == ' ') || (svalue[strlen(svalue) - 1] == TAB)) svalue[strlen(svalue) - 1] = '\0'; // Trim right
386 daniel-mar 654
 
385 daniel-mar 655
                if (strlen(svalue) > 0) {
393 daniel-mar 656
                        if (outputwork + strlen(svalue) + (isFormula ? 3/*CRLF+NUL*/ : 2/*space+NUL*/) > outputFile + maxOutput) {
444 daniel-mar 657
                                size_t remaining = maxOutput - (outputwork - outputFile) - 1;
385 daniel-mar 658
                                //printf("BUFFER FULL (remaining = %d)\n", remaining);
659
                                memcpy(outputwork, svalue, remaining);
660
                                outputwork += remaining;
539 daniel-mar 661
                                outputwork[0] = '\0';
385 daniel-mar 662
                                free(inputworkinitial);
663
                                return true;
664
                        }
665
                        else {
666
                                memcpy(outputwork, svalue, strlen(svalue));
667
                                outputwork += strlen(svalue);
386 daniel-mar 668
                                if (isFormula) {
669
                                        // Formulas: TXT line break stays line break (important if you have comments!)
388 daniel-mar 670
                                        outputwork[0] = CR;
671
                                        outputwork[1] = LF;
387 daniel-mar 672
                                        outputwork += 2;
386 daniel-mar 673
                                }
674
                                else {
675
                                        // Everything else: TXT line breaks becomes single whitespace
676
                                        outputwork[0] = ' ';
677
                                        outputwork++;
678
                                }
385 daniel-mar 679
                        }
680
                }
539 daniel-mar 681
                outputwork[0] = '\0';
385 daniel-mar 682
 
683
                // Process next line
684
                if (inputwork > inputworkinitial + maxInput) break;
685
                sline = inputwork;
686
                inputwork += strlen(sline) + 1;
386 daniel-mar 687
                if (inputwork - 1 > inputworkinitial + maxInput) break; // TODO: will that be ever called?
385 daniel-mar 688
        } while (!_picoLineContainsKey(sline, &svalue, NULL));
388 daniel-mar 689
 
385 daniel-mar 690
        // Remove trailing whitespace
691
        if (outputwork > outputFile) {
692
                outputwork -= 1;
539 daniel-mar 693
                outputwork[0] = '\0';
385 daniel-mar 694
        }
695
        free(inputworkinitial);
696
        return true;
697
}
698
 
552 daniel-mar 699
FFLoadingResult readfile_picotxt_or_ffdecomp(StandardFileReply* sfr) {
385 daniel-mar 700
        Handle h;
552 daniel-mar 701
        FFLoadingResult res = MSG_LOADFILE_UNKNOWN_FORMAT_ID;
385 daniel-mar 702
        FILEREF refnum;
703
 
704
        if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
705
                if ((h = readfileintohandle(refnum))) {
505 daniel-mar 706
                        FILECOUNT count = (FILECOUNT)PIGETHANDLESIZE(h);
385 daniel-mar 707
                        char* q = PILOCKHANDLE(h, false);
708
 
541 daniel-mar 709
                        char dummy[256];
710
                        if (_picoReadProperty(q, count, "Title", dummy, sizeof(dummy), false)) {
386 daniel-mar 711
                                int i;
385 daniel-mar 712
 
713
                                // Plugin infos
393 daniel-mar 714
                                _picoReadProperty(q, count, "Title", gdata->parm.szTitle, sizeof(gdata->parm.szTitle), false);
715
                                _picoReadProperty(q, count, "Category", gdata->parm.szCategory, sizeof(gdata->parm.szCategory), false);
716
                                _picoReadProperty(q, count, "Author", gdata->parm.szAuthor, sizeof(gdata->parm.szAuthor), false);
717
                                _picoReadProperty(q, count, "Copyright", gdata->parm.szCopyright, sizeof(gdata->parm.szCopyright), false);
718
                                //_picoReadProperty(q, count, "Filename", gdata->parm.xxx, sizeof(gdata->parm.xxx), false);
385 daniel-mar 719
 
720
                                // Expressions
393 daniel-mar 721
                                if (!_picoReadProperty(q, count, "R", gdata->parm.szFormula[0], sizeof(gdata->parm.szFormula[0]), true))
722
                                        strcpy(gdata->parm.szFormula[0], "r");
723
                                if (!_picoReadProperty(q, count, "G", gdata->parm.szFormula[1], sizeof(gdata->parm.szFormula[1]), true))
724
                                        strcpy(gdata->parm.szFormula[1], "g");
725
                                if (!_picoReadProperty(q, count, "B", gdata->parm.szFormula[2], sizeof(gdata->parm.szFormula[2]), true))
726
                                        strcpy(gdata->parm.szFormula[2], "b");
727
                                if (!_picoReadProperty(q, count, "A", gdata->parm.szFormula[3], sizeof(gdata->parm.szFormula[3]), true))
728
                                        strcpy(gdata->parm.szFormula[3], "a");
385 daniel-mar 729
 
386 daniel-mar 730
                                for (i = 0; i < 8; i++) {
550 daniel-mar 731
                                        if (gdata->parm.ctl_used[i]) {
732
                                                int v;
733
                                                char keyname[6/*strlen("ctl[X]")*/ + 1/*strlen("\0")*/], tmp[5];
537 daniel-mar 734
 
550 daniel-mar 735
                                                // Slider names
736
                                                sprintf(keyname, "ctl[%d]", i);
737
                                                _picoReadProperty(q, count, keyname, gdata->parm.szCtl[i], sizeof(gdata->parm.szCtl[i]), false);
385 daniel-mar 738
 
550 daniel-mar 739
                                                // Slider values
740
                                                sprintf(keyname, "val[%d]", i);
385 daniel-mar 741
                                                if (!_picoReadProperty(q, count, keyname, tmp, sizeof(tmp), false)) {
550 daniel-mar 742
                                                        sprintf(keyname, "def[%d]", i);
743
                                                        if (!_picoReadProperty(q, count, keyname, tmp, sizeof(tmp), false)) {
744
                                                                strcpy(tmp, "0");
745
                                                        }
385 daniel-mar 746
                                                }
550 daniel-mar 747
                                                v = atoi(tmp);
748
                                                if (v < 0) v = 0;
749
                                                else if (v > 255) v = 255;
750
                                                gdata->parm.val[i] = gdata->parm.val[i] = (uint8_t)v;
385 daniel-mar 751
                                        }
752
                                }
753
 
754
                                // Map names
386 daniel-mar 755
                                for (i = 0; i < 4; i++) {
550 daniel-mar 756
                                        if (gdata->parm.map_used[i]) {
757
                                                char keyname[6/*strlen("map[X]")*/ + 1/*strlen("\0")*/];
758
                                                sprintf(keyname, "map[%d]", i);
759
                                                _picoReadProperty(q, count, keyname, gdata->parm.szMap[i], sizeof(gdata->parm.szMap[i]), false);
760
                                        }
385 daniel-mar 761
                                }
762
 
557 daniel-mar 763
                                res = LOADING_OK;
385 daniel-mar 764
                        }
765
 
766
                        PIUNLOCKHANDLE(h);
767
                        PIDISPOSEHANDLE(h);
768
                }
769
                FSClose(refnum);
770
        }
771
 
772
        return res;
773
}
774
 
539 daniel-mar 775
Boolean _gufReadProperty(char* fileContents, size_t argMaxInputLength, const char* section, const char* keyname, char* argOutput, size_t argMaxOutLength) {
776
        size_t iTmp;
777
        char* tmpFileContents, * tmpSection, * tmpStart, * tmpStart2, * tmpEnd, * tmpKeyname, * tmpStart3, * tmpStart4, * inputwork;
778
 
779
        // Check parameters
780
        if (argMaxOutLength == 0) return false;
781
        if (fileContents == NULL) return false;
782
 
783
        // Handle argMaxInputLength
784
        //char* inputwork = fileContents;
541 daniel-mar 785
        inputwork = (char*)malloc((size_t)argMaxInputLength + 1/*NUL byte*/);
539 daniel-mar 786
        if (inputwork == NULL) return false;
787
        memcpy(inputwork, fileContents, argMaxInputLength);
788
        inputwork[argMaxInputLength] = '\0';
789
 
790
        // Prepare the input file contents to make it easier parse-able
791
        iTmp = strlen(inputwork) + strlen("\n\n[");
541 daniel-mar 792
        tmpFileContents = (char*)malloc(iTmp + 1/*NUL byte*/);
539 daniel-mar 793
        if (tmpFileContents == NULL) return false;
794
        sprintf(tmpFileContents, "\n%s\n[", inputwork);
795
        for (iTmp = 0; iTmp < strlen(tmpFileContents); iTmp++) {
557 daniel-mar 796
                if (tmpFileContents[iTmp] == CR) tmpFileContents[iTmp] = LF;
539 daniel-mar 797
        }
798
 
799
        // Find the section begin
800
        iTmp = strlen(section) + strlen("\n[]\n");
541 daniel-mar 801
        tmpSection = (char*)malloc(iTmp + 1/*NUL byte*/);
539 daniel-mar 802
        if (tmpSection == NULL) return false;
803
        sprintf(tmpSection, "\n[%s]\n", section);
804
        tmpStart = strstr(tmpFileContents, tmpSection);
805
        if (tmpStart == NULL) return false;
806
        tmpStart += iTmp;
807
 
808
        // Find the end of the section and set a NULL terminator to it
809
        iTmp = strlen(tmpStart) + strlen("\n");
810
        tmpStart2 = (char*)malloc(iTmp + 1/*NUL byte*/);
811
        if (tmpStart2 == NULL) return false;
812
        sprintf(tmpStart2, "\n%s", tmpStart);
813
        tmpEnd = strstr(tmpStart2, "\n[");
814
        if (tmpEnd == NULL) return false;
815
        tmpEnd[0] = '\0';
816
 
817
        // Find the start of the value
818
        iTmp = strlen(keyname) + strlen("\n=");
819
        tmpKeyname = (char*)malloc(iTmp + 1/*NUL byte*/);
820
        if (tmpKeyname == NULL) return false;
821
        sprintf(tmpKeyname, "\n%s=", keyname);
822
        tmpStart3 = strstr(tmpStart2, tmpKeyname);
823
        if (tmpStart3 == NULL) return false;
824
        tmpStart3 += strlen("\n");
825
        tmpStart4 = strstr(tmpStart3, "=");
826
        if (tmpStart4 == NULL) return false;
827
        tmpStart4 += strlen("=");
828
 
829
        // Find the end of the value
830
        tmpEnd = strstr(tmpStart4, "\n");
831
        if (tmpEnd == NULL) return false;
832
        tmpEnd[0] = '\0';
833
 
834
        // Copy to output
835
        if (strlen(tmpStart4) < argMaxOutLength + 1) argMaxOutLength = strlen(tmpStart4) + 1;
836
        memcpy(argOutput, tmpStart4, argMaxOutLength);
837
        argOutput[argMaxOutLength - 1] = '\0';
838
 
839
        // Free all temporary stuff
840
        //for (iTmp = 0; iTmp < strlen(tmpFileContents); iTmp++) tmpFileContents[iTmp] = '\0';
841
        free(tmpFileContents);
842
        //for (iTmp = 0; iTmp < strlen(tmpSection); iTmp++) tmpSection[iTmp] = '\0';
843
        free(tmpSection);
844
        //for (iTmp = 0; iTmp < strlen(tmpKeyname); iTmp++) tmpKeyname[iTmp] = '\0';
845
        free(tmpKeyname);
846
        //for (iTmp = 0; iTmp < strlen(tmpStart2); iTmp++) tmpStart2[iTmp] = '\0';
847
        free(tmpStart2);
848
 
849
        // Return success
850
        return true;
537 daniel-mar 851
}
852
 
552 daniel-mar 853
FFLoadingResult readfile_guf(StandardFileReply* sfr) {
537 daniel-mar 854
        Handle h;
552 daniel-mar 855
        FFLoadingResult res = MSG_LOADFILE_UNKNOWN_FORMAT_ID;
537 daniel-mar 856
        FILEREF refnum;
857
 
541 daniel-mar 858
        // TODO: Decode UTF-8 to ANSI (or "?" for unknown characters)
859
 
537 daniel-mar 860
        if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
861
                if ((h = readfileintohandle(refnum))) {
862
                        FILECOUNT count = (FILECOUNT)PIGETHANDLESIZE(h);
863
                        char* q = PILOCKHANDLE(h, false);
553 daniel-mar 864
                        char protocol[256];
537 daniel-mar 865
 
553 daniel-mar 866
                        if (!_gufReadProperty(q, count, "GUF", "Protocol", protocol, sizeof(protocol))) {
867
                                res = MSG_INVALID_FILE_SIGNATURE_ID;
537 daniel-mar 868
                        }
553 daniel-mar 869
                        else if (strcmp(protocol, "1") != 0) {
870
                                res = MSG_INCOMPATIBLE_GUF_FILE_ID;
871
                        }
537 daniel-mar 872
                        else {
873
                                int i;
541 daniel-mar 874
                                char tmp[256];
875
                                char* tmp2;
537 daniel-mar 876
 
877
                                // Plugin infos
878
                                _gufReadProperty(q, count, "Info", "Title", gdata->parm.szTitle, sizeof(gdata->parm.szTitle));
541 daniel-mar 879
                                _gufReadProperty(q, count, "Info", "Category", tmp, sizeof(tmp));
880
                                tmp2 = strrchr(tmp, '/');
881
                                if (tmp2 == NULL) {
882
                                        strcpy(gdata->parm.szCategory, tmp);
883
                                } else {
884
                                        strcpy(gdata->parm.szCategory, tmp2+1);
885
                                }
537 daniel-mar 886
                                _gufReadProperty(q, count, "Info", "Author", gdata->parm.szAuthor, sizeof(gdata->parm.szAuthor));
887
                                _gufReadProperty(q, count, "Info", "Copyright", gdata->parm.szCopyright, sizeof(gdata->parm.szCopyright));
888
                                //_gufReadProperty(q, count, "Filter Factory", "8bf", gdata->parm.xxx, sizeof(gdata->parm.xxx));
889
 
890
                                // Expressions
891
                                if (!_gufReadProperty(q, count, "Code", "R", gdata->parm.szFormula[0], sizeof(gdata->parm.szFormula[0])))
892
                                        strcpy(gdata->parm.szFormula[0], "r");
893
                                if (!_gufReadProperty(q, count, "Code", "G", gdata->parm.szFormula[1], sizeof(gdata->parm.szFormula[1])))
894
                                        strcpy(gdata->parm.szFormula[1], "g");
895
                                if (!_gufReadProperty(q, count, "Code", "B", gdata->parm.szFormula[2], sizeof(gdata->parm.szFormula[2])))
896
                                        strcpy(gdata->parm.szFormula[2], "b");
897
                                if (!_gufReadProperty(q, count, "Code", "A", gdata->parm.szFormula[3], sizeof(gdata->parm.szFormula[3])))
898
                                        strcpy(gdata->parm.szFormula[3], "a");
899
 
900
                                for (i = 0; i < 8; i++) {
550 daniel-mar 901
                                        if (gdata->parm.ctl_used[i]) {
902
                                                int v;
903
                                                char keyname[9/*strlen("Control X")*/ + 1/*strlen("\0")*/], tmp[5];
904
                                                sprintf(keyname, "Control %d", i);
537 daniel-mar 905
 
550 daniel-mar 906
                                                // Slider names
907
                                                _gufReadProperty(q, count, keyname, "Label", gdata->parm.szCtl[i], sizeof(gdata->parm.szCtl[i]));
537 daniel-mar 908
 
550 daniel-mar 909
                                                // Slider values
910
                                                if (!_gufReadProperty(q, count, keyname, "Preset", tmp, sizeof(tmp))) {
911
                                                        strcpy(tmp, "0");
912
                                                }
913
                                                v = atoi(tmp);
914
                                                if (v < 0) v = 0;
915
                                                else if (v > 255) v = 255;
916
                                                gdata->parm.val[i] = gdata->parm.val[i] = (uint8_t)v;
537 daniel-mar 917
                                        }
918
                                }
919
 
920
                                // Map names
921
                                for (i = 0; i < 4; i++) {
550 daniel-mar 922
                                        if (gdata->parm.map_used[i]) {
923
                                                char keyname[5/*strlen("Map X")*/ + 1/*strlen("\0")*/];
924
                                                sprintf(keyname, "Map %d", i);
925
                                                _gufReadProperty(q, count, keyname, "Label", gdata->parm.szMap[i], sizeof(gdata->parm.szMap[i]));
926
                                        }
537 daniel-mar 927
                                }
928
 
557 daniel-mar 929
                                res = LOADING_OK;
537 daniel-mar 930
                        }
931
 
932
                        PIUNLOCKHANDLE(h);
933
                        PIDISPOSEHANDLE(h);
934
                }
935
                FSClose(refnum);
936
        }
937
 
938
        return res;
939
}
940
 
552 daniel-mar 941
FFLoadingResult readfile_afs_pff(StandardFileReply *sfr){
256 daniel-mar 942
        FILEREF r;
943
        Handle h;
552 daniel-mar 944
        FFLoadingResult res = MSG_LOADFILE_UNKNOWN_FORMAT_ID;
256 daniel-mar 945
 
946
        if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&r) == noErr){
947
                if( (h = readfileintohandle(r)) ){
554 daniel-mar 948
                        // Note in re fileHasExtension(): Mac does not have file extensions like Windows,
949
                        // so, the detection if the channel order is BGRA (Premiere *.pff) or RGBA (Photoshop *.afs)
950
                        // is not possible, except if the file has an extension (e.g. when it was copied from a Windows system)
951
                        res = readparams_afs_pff(h, fileHasExtension(sfr, TEXT(".pff")));
256 daniel-mar 952
                        PIDISPOSEHANDLE(h);
953
                }
954
                FSClose(r);
492 daniel-mar 955
        }
956
        else
552 daniel-mar 957
                res = MSG_CANNOT_OPEN_FILE_ID;
256 daniel-mar 958
 
959
        return res;
960
}
544 daniel-mar 961
 
552 daniel-mar 962
FFLoadingResult readfile_ffl(StandardFileReply* sfr) {
544 daniel-mar 963
        FILEREF rTmp, refnum;
964
        Handle h, hTmp;
557 daniel-mar 965
        FFLoadingResult res = LOADING_OK;
544 daniel-mar 966
        StandardFileReply sfrTmp;
967
        OSErr e;
968
        char* p, * start;
969
        size_t est;
553 daniel-mar 970
        int foundFilters = 0;
544 daniel-mar 971
 
972
        if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
973
                if ((h = readfileintohandle(refnum))) {
974
                        FILECOUNT count = (FILECOUNT)PIGETHANDLESIZE(h);
975
                        char* q = PILOCKHANDLE(h, false);
976
 
547 daniel-mar 977
                        char* q2, * tmp_cur_filter_str[29], *token;
544 daniel-mar 978
                        int lineNumber = 0;
547 daniel-mar 979
 
556 daniel-mar 980
                        if (count < 6) {
554 daniel-mar 981
                                res = MSG_INVALID_FILE_SIGNATURE_ID;
547 daniel-mar 982
                        }
553 daniel-mar 983
                        else {
556 daniel-mar 984
                                char testsig[7];
985
                                memcpy(testsig, q, 6); // only read 6 chars. Avoid reading the whole file yet
986
                                testsig[6] = '\0';
987
                                if (strcmp(testsig, "FFL1.0") != 0) {
988
                                        res = MSG_INVALID_FILE_SIGNATURE_ID;
554 daniel-mar 989
                                }
990
                                else {
556 daniel-mar 991
                                        // This is required to make strtok work, because q is not zero-terminated...
992
                                        q2 = (char*)malloc(count + 1/*NUL byte*/);
993
                                        if (q2 == NULL) {
994
                                                res = MSG_OUT_OF_MEMORY_ID;
995
                                        }
996
                                        else {
997
                                                memcpy(q2, q, count);
998
                                                q2[count] = '\0';
554 daniel-mar 999
 
556 daniel-mar 1000
                                                token = strtok(q2, "\n");
1001
                                                while (token != NULL) {
1002
                                                        size_t i;
1003
                                                        char* token2 = my_strdup(token);
1004
                                                        for (i = 0; i < strlen(token2); i++) {
557 daniel-mar 1005
                                                                if (token2[i] == CR) token2[i] = '\0';
554 daniel-mar 1006
                                                        }
556 daniel-mar 1007
                                                        if (lineNumber == 0) {
1008
                                                                // We already checked it above (in order to avoid an unnecessary memory copy)
1009
                                                                /*
1010
                                                                if (strcmp(token2, "FFL1.0") != 0) {
1011
                                                                        res = MSG_INVALID_FILE_SIGNATURE_ID;
1012
                                                                        break;
1013
                                                                }
1014
                                                                */
1015
                                                        }
1016
                                                        else if (lineNumber == 1) {
1017
                                                                // We don't check that. We just stop at every 28th line of each filter
1018
                                                                /*
1019
                                                                countFilters = atoi(token2);
1020
                                                                */
1021
                                                        }
1022
                                                        else
1023
                                                        {
1024
                                                                /*
1025
                                                                * 0 filter_file1.8bf
1026
                                                                * 1 Category 1 here
1027
                                                                * 2 Filter Name 1 here
1028
                                                                * 3 Autor 1 here
1029
                                                                * 4 Copyright 1 here
1030
                                                                * 5 Map1 name or empty line to disable map
1031
                                                                * 6 Map2 name or empty line to disable map
1032
                                                                * 7 Map3 name or empty line to disable map
1033
                                                                * 8 Map4 name or empty line to disable map
1034
                                                                * 9 Slider 1
1035
                                                                * 10 Slider 2
1036
                                                                * 11 Slider 3
1037
                                                                * 12 Slider 4
1038
                                                                * 13 Slider 5
1039
                                                                * 14 Slider 6
1040
                                                                * 15 Slider 7
1041
                                                                * 16 Slider 8
1042
                                                                * 17 100
1043
                                                                * 18 110
1044
                                                                * 19 120
1045
                                                                * 20 130
1046
                                                                * 21 140
1047
                                                                * 22 150
1048
                                                                * 23 160
1049
                                                                * 24 170
1050
                                                                * 25 r
1051
                                                                * 26 g
1052
                                                                * 27 b
1053
                                                                * 28 a
1054
                                                                */
1055
                                                                int filterLineNumber = (lineNumber - 2) % 29;
1056
                                                                tmp_cur_filter_str[filterLineNumber] = token2;
1057
                                                                if (filterLineNumber == 28) {
1058
                                                                        TCHAR* curFileNameOrig;
1059
                                                                        TCHAR* curFileName;
1060
                                                                        char n[5];
544 daniel-mar 1061
 
556 daniel-mar 1062
                                                                        foundFilters++;
544 daniel-mar 1063
 
556 daniel-mar 1064
                                                                        curFileNameOrig = curFileName = (TCHAR*)malloc(MAX_PATH * sizeof(TCHAR));
544 daniel-mar 1065
 
556 daniel-mar 1066
                                                                        strcpy_advance(&curFileName, sfr->sfFile.szName);
1067
                                                                        curFileName -= 4; // remove ".ffl" extension
1068
                                                                        *curFileName = (TCHAR)0;
544 daniel-mar 1069
 
556 daniel-mar 1070
                                                                        xstrcat(curFileNameOrig, TEXT("__"));
1071
                                                                        curFileName += strlen("__");
1072
 
1073
                                                                        sprintf(n, "%04d", foundFilters);
1074
                                                                        strcpy_advance_a(&curFileName, n);
544 daniel-mar 1075
 
556 daniel-mar 1076
                                                                        xstrcat(curFileNameOrig, TEXT("_"));
1077
                                                                        curFileName += strlen("_");
1078
 
1079
                                                                        strcpy_advance_a(&curFileName, tmp_cur_filter_str[0]);
1080
                                                                        curFileName -= 4; // remove ".8bf" extension
1081
                                                                        *curFileName = (TCHAR)0;
1082
 
553 daniel-mar 1083
#ifdef WIN_ENV
556 daniel-mar 1084
                                                                        xstrcat(curFileNameOrig, TEXT(".txt"));
553 daniel-mar 1085
#endif
544 daniel-mar 1086
 
556 daniel-mar 1087
                                                                        sfrTmp.sfGood = true;
1088
                                                                        sfrTmp.sfReplacing = true;
1089
                                                                        sfrTmp.sfType = TEXT_FILETYPE;
1090
                                                                        xstrcpy(sfrTmp.sfFile.szName, curFileNameOrig);
553 daniel-mar 1091
#ifdef WIN_ENV
556 daniel-mar 1092
                                                                        sfrTmp.nFileExtension = (WORD)(xstrlen(curFileNameOrig) - strlen(".txt") + 1);
553 daniel-mar 1093
#endif
556 daniel-mar 1094
                                                                        sfrTmp.sfScript = smSystemScript;
544 daniel-mar 1095
 
556 daniel-mar 1096
                                                                        est = 16000;
544 daniel-mar 1097
 
556 daniel-mar 1098
                                                                        FSpDelete(&sfrTmp.sfFile);
1099
                                                                        if (FSpCreate(&sfrTmp.sfFile, SIG_SIMPLETEXT, TEXT_FILETYPE, sfr->sfScript) == noErr) {
1100
                                                                                if (FSpOpenDF(&sfrTmp.sfFile, fsWrPerm, &rTmp) == noErr) {
1101
                                                                                        if ((hTmp = PINEWHANDLE(1))) { // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that.
1102
                                                                                                PIUNLOCKHANDLE(hTmp); // should not be necessary
1103
                                                                                                if (!(e = PISETHANDLESIZE(hTmp, (int32)(est))) && (p = start = PILOCKHANDLE(hTmp, false))) {
544 daniel-mar 1104
 
556 daniel-mar 1105
                                                                                                        p += sprintf(p, "Category: %s\n", tmp_cur_filter_str[1]);
1106
                                                                                                        p += sprintf(p, "Title: %s\n", tmp_cur_filter_str[2]);
1107
                                                                                                        p += sprintf(p, "Copyright: %s\n", tmp_cur_filter_str[4]);
1108
                                                                                                        p += sprintf(p, "Author: %s\n", tmp_cur_filter_str[3]);
1109
                                                                                                        p += sprintf(p, "Filename: %s\n", tmp_cur_filter_str[0]);
1110
                                                                                                        p += sprintf(p, "\n");
1111
                                                                                                        p += sprintf(p, "R:\n");
1112
                                                                                                        p += sprintf(p, "%s\n", tmp_cur_filter_str[25]);
1113
                                                                                                        p += sprintf(p, "\n");
1114
                                                                                                        p += sprintf(p, "G:\n");
1115
                                                                                                        p += sprintf(p, "%s\n", tmp_cur_filter_str[26]);
1116
                                                                                                        p += sprintf(p, "\n");
1117
                                                                                                        p += sprintf(p, "B:\n");
1118
                                                                                                        p += sprintf(p, "%s\n", tmp_cur_filter_str[27]);
1119
                                                                                                        p += sprintf(p, "\n");
1120
                                                                                                        p += sprintf(p, "A:\n");
1121
                                                                                                        p += sprintf(p, "%s\n", tmp_cur_filter_str[28]);
1122
                                                                                                        p += sprintf(p, "\n");
553 daniel-mar 1123
 
556 daniel-mar 1124
                                                                                                        // Maps
1125
                                                                                                        for (i = 0; i < 4; i++) {
1126
                                                                                                                char* tmp = tmp_cur_filter_str[5 + i];
1127
                                                                                                                if (strcmp(tmp, "") != 0) {
1128
                                                                                                                        p += sprintf(p, "map[%d]: %s\n", (int)i, tmp_cur_filter_str[5 + i]);
1129
                                                                                                                }
554 daniel-mar 1130
                                                                                                        }
556 daniel-mar 1131
                                                                                                        p += sprintf(p, "\n");
544 daniel-mar 1132
 
556 daniel-mar 1133
                                                                                                        // Controls
1134
                                                                                                        for (i = 0; i < 8; i++) {
1135
                                                                                                                char* tmp = tmp_cur_filter_str[9 + i];
1136
                                                                                                                if (strcmp(tmp, "") != 0) {
1137
                                                                                                                        p += sprintf(p, "ctl[%d]: %s\n", (int)i, tmp_cur_filter_str[9 + i]);
1138
                                                                                                                }
1139
                                                                                                                tmp = tmp_cur_filter_str[17 + i];
1140
                                                                                                                if (strcmp(tmp, "") != 0) {
1141
                                                                                                                        p += sprintf(p, "val[%d]: %s\n", (int)i, tmp_cur_filter_str[17 + i]);
1142
                                                                                                                }
554 daniel-mar 1143
                                                                                                        }
556 daniel-mar 1144
                                                                                                        p += sprintf(p, "\n");
1145
 
1146
                                                                                                        PIUNLOCKHANDLE(hTmp);
1147
                                                                                                        e = PISETHANDLESIZE(hTmp, (int32)(p - start)); // could ignore this error, maybe
553 daniel-mar 1148
                                                                                                }
556 daniel-mar 1149
                                                                                                savehandleintofile(hTmp, rTmp);
1150
                                                                                                PIDISPOSEHANDLE(hTmp);
544 daniel-mar 1151
                                                                                        }
556 daniel-mar 1152
                                                                                        else res = MSG_OUT_OF_MEMORY_ID;
1153
                                                                                        FSClose(rTmp);
544 daniel-mar 1154
                                                                                }
556 daniel-mar 1155
                                                                                else res = MSG_CANNOT_OPEN_FILE_ID;
544 daniel-mar 1156
                                                                        }
556 daniel-mar 1157
                                                                        else res = MSG_CANNOT_CREATE_FILE_ID;
554 daniel-mar 1158
 
556 daniel-mar 1159
                                                                        free(curFileNameOrig);
1160
                                                                        for (i = 0; i < 29; i++) {
1161
                                                                                free(tmp_cur_filter_str[i]); // free all "token2"
1162
                                                                        }
544 daniel-mar 1163
                                                                }
1164
                                                        }
556 daniel-mar 1165
                                                        lineNumber++;
1166
                                                        token = strtok(NULL, "\n");
544 daniel-mar 1167
                                                }
1168
                                        }
556 daniel-mar 1169
 
1170
                                        free(q2);
544 daniel-mar 1171
                                }
1172
                        }
1173
 
1174
                        PIUNLOCKHANDLE(h);
1175
                        PIDISPOSEHANDLE(h);
1176
                }
1177
                FSClose(refnum);
1178
        }
1179
 
557 daniel-mar 1180
        if (res == LOADING_OK) {
553 daniel-mar 1181
                res = foundFilters == 0 ? MSG_FFL_NO_FILTERS_DETECTED_ID : MSG_FFL_CONVERTED_ID;
1182
        }
1183
        return res;
544 daniel-mar 1184
}