Subversion Repositories filter_foundry

Rev

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

Rev Author Line No. Line
2 toby 1
/*
18 toby 2
    This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
192 daniel-mar 3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
4
    Copyright (C) 2018-2019 Daniel Marschall, ViaThinkSoft
2 toby 5
 
6
    This program is free software; you can redistribute it and/or modify
131 dmarschall 7
    it under the terms of the GNU General Public License as published by
2 toby 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
 
131 dmarschall 16
    You should have received a copy of the GNU General Public License
2 toby 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
 
149 dmarschall 25
#ifdef MAC_ENV
26
#include <Endian.h>
152 dmarschall 27
#else
28
int EndianS32_LtoN(int num) {
189 dmarschall 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
32
               ((num<<24)&0xff000000); // byte 0 to byte 3
152 dmarschall 33
}
149 dmarschall 34
#endif
35
 
2 toby 36
enum{
189 dmarschall 37
        BUFSIZE = 4L<<10,
38
        MAXLINE = 0x200,
2 toby 39
};
40
 
41
Boolean readparams(Handle h,Boolean alerts,char **reason){
189 dmarschall 42
        Boolean res = false;
43
        char linebuf[MAXLINE+1],curexpr[MAXEXPR+1],*p,*dataend,*q;
44
        int c,linecnt,lineptr,exprcnt;
2 toby 45
 
189 dmarschall 46
        if(!h){
47
                *reason = "readparams: Null parameter handle.";
48
                return false;
49
        }
15 toby 50
 
189 dmarschall 51
        p = PILOCKHANDLE(h,false);
52
        dataend = p + PIGETHANDLESIZE(h);
131 dmarschall 53
 
189 dmarschall 54
        q = curexpr;
55
        linecnt = exprcnt = lineptr = 0;
2 toby 56
 
189 dmarschall 57
        *reason = "File was too short.";
58
        while(p < dataend){
2 toby 59
 
189 dmarschall 60
                c = *p++;
2 toby 61
 
189 dmarschall 62
                if(c==CR || c==LF){ /* detected end of line */
131 dmarschall 63
 
189 dmarschall 64
                        /* look ahead to see if we need to skip a line feed (DOS EOL convention) */
65
                        if(c == CR && *p == LF && p < dataend)
66
                                ++p;
131 dmarschall 67
 
189 dmarschall 68
                        linebuf[lineptr] = 0; /* add terminating NUL to line buffer */
2 toby 69
 
189 dmarschall 70
                        /* process complete line */
71
                        if(linecnt==0){
72
                                if(strcmp(linebuf,"%RGB-1.0")){
73
                                        if(alerts)
74
                                                *reason = "This doesn't look like a Filter Factory file (first line is not \"%RGB-1.0\").";
75
                                        break;
76
                                }
77
                        }else if(linecnt<=8){
78
                                slider[linecnt-1] = atoi(linebuf);
79
                        }else{
80
                                if(lineptr){
81
                                        /* it's not an empty line; append it to current expr string */
82
                                        if( q+lineptr > curexpr+MAXEXPR ){
83
                                                *reason = "Found an expression longer than 1024 characters.";
84
                                                break;
85
                                        }
86
                                        q = cat(q,linebuf);
87
                                }else{
88
                                        /* it's an empty line: we've completed the expr string */
89
                                        if(expr[exprcnt])
90
                                                free(expr[exprcnt]);
91
                                        *q = 0;
92
                                        if(!(expr[exprcnt] = my_strdup(curexpr))){
93
                                                *reason = "Could not get memory for expression.";
94
                                                break;
95
                                        }
2 toby 96
 
189 dmarschall 97
                                        if(++exprcnt == 4){
98
                                                res = true;
99
                                                break; /* got everything we want */
100
                                        }
2 toby 101
 
189 dmarschall 102
                                        q = curexpr; /* empty current expr, ready for next one */
103
                                }
104
                        }
131 dmarschall 105
 
189 dmarschall 106
                        ++linecnt;
107
                        lineptr = 0;
108
                }else{
109
                        /* store character */
110
                        if(c=='\\'){ /* escape sequence */
111
                                if(p < dataend){
112
                                        c = *p++;
113
                                        switch(c){
114
                                        case 'r': c = CR;
115
                                        case '\\': break;
116
                                        default:
117
                                                if(alerts) alertuser("Warning:","Unknown escape sequence in input.");
118
                                        }
119
                                }//else if(alerts) alertuser("Warning:","truncated escape sequence ends input");
120
                        }
2 toby 121
 
189 dmarschall 122
                        if(lineptr < MAXLINE)
123
                                linebuf[lineptr++] = c;
124
                }
125
        }
131 dmarschall 126
 
189 dmarschall 127
        PIUNLOCKHANDLE(h);
2 toby 128
 
189 dmarschall 129
        return res;
2 toby 130
}
131
 
145 dmarschall 132
void convert_premiere_to_photoshop(PARM_T* photoshop, PARM_T_PREMIERE* premiere) {
189 dmarschall 133
        int i;
145 dmarschall 134
 
189 dmarschall 135
        photoshop->cbSize = sizeof(PARM_T);
136
        photoshop->standalone = premiere->standalone;
137
        for (i=0;i<8;++i)
138
          photoshop->val[i] = premiere->val[i];
139
        photoshop->popDialog = premiere->popDialog;
140
        photoshop->unknown1 = premiere->unknown1;
141
        photoshop->unknown2 = premiere->unknown2;
142
        photoshop->unknown3 = premiere->unknown3;
143
        for (i=0;i<4;++i)
144
          photoshop->map_used[i] = premiere->map_used[i];
145
        for (i=0;i<8;++i)
146
          photoshop->ctl_used[i] = premiere->ctl_used[i];
147
        sprintf((char*)photoshop->category, "Filter Factory"); // Premiere plugins do not have a category attribute
148
        photoshop->iProtected = 0; // Premiere plugins do not have a protect flag
149
        memcpy((void*)photoshop->title, (void*)premiere->title, sizeof(photoshop->title));
150
        memcpy((void*)photoshop->copyright, (void*)premiere->copyright, sizeof(photoshop->copyright));
151
        memcpy((void*)photoshop->author, (void*)premiere->author, sizeof(photoshop->author));
152
        for (i=0;i<4;++i)
153
          memcpy((void*)photoshop->map[i], (void*)premiere->map[i], sizeof(photoshop->map[i]));
154
        for (i=0;i<8;++i)
155
          memcpy((void*)photoshop->ctl[i], (void*)premiere->ctl[i], sizeof(photoshop->ctl[i]));
145 dmarschall 156
 
189 dmarschall 157
        if (premiere->singleExpression) {
158
                memcpy((void*)photoshop->formula[0], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
159
                memcpy((void*)photoshop->formula[1], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
160
                memcpy((void*)photoshop->formula[2], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
161
                memcpy((void*)photoshop->formula[3], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
162
        } else {
163
                memcpy((void*)photoshop->formula[0], (void*)premiere->formula[2], sizeof(photoshop->formula[2]));
164
                memcpy((void*)photoshop->formula[1], (void*)premiere->formula[1], sizeof(photoshop->formula[1]));
165
                memcpy((void*)photoshop->formula[2], (void*)premiere->formula[0], sizeof(photoshop->formula[0]));
166
                memcpy((void*)photoshop->formula[3], (void*)premiere->formula[3], sizeof(photoshop->formula[3]));
167
        }
145 dmarschall 168
}
169
 
149 dmarschall 170
Boolean read8bfplugin(StandardFileReply *sfr,char **reason){
189 dmarschall 171
        unsigned char magic[2];
172
        FILECOUNT count;
173
        Handle h;
174
        Boolean res = false;
175
        FILEREF refnum;
176
        int i;
149 dmarschall 177
 
189 dmarschall 178
        if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&refnum) == noErr){
179
                // check DOS EXE magic number
180
                count = 2;
181
                if(FSRead(refnum,&count,magic) == noErr /*&& magic[0]=='M' && magic[1]=='Z'*/){
182
                        if(GetEOF(refnum,(FILEPOS*)&count) == noErr && count < 256L<<10){ // sanity check file size < 256K
183
                                if( (h = readfileintohandle(refnum)) ){
184
                                        long *q = (long*)PILOCKHANDLE(h,false);
149 dmarschall 185
 
189 dmarschall 186
                                        // look for signature at start of valid PARM resource
187
                                        // This signature is observed in Filter Factory standalones.
188
                                        for( count /= 4 ; count >= PARM_SIZE/4 ; --count, ++q )
189
                                        {
149 dmarschall 190
 
191
#ifdef MAC_ENV
189 dmarschall 192
                                                // Case #1: Mac is reading Windows (Win16/32) plugin
193
                                                if( ((EndianS32_LtoN(q[0]) == PARM_SIZE) ||
194
                                                     (EndianS32_LtoN(q[0]) == PARM_SIZE_PREMIERE) ||
195
                                                     (EndianS32_LtoN(q[0]) == PARM_SIG_MAC)) && EndianS32_LtoN(q[1]) == 1
196
                                                        && (res = readPARM((char*)q, &gdata->parm, reason, 1 /*Windows format resource*/)) )
197
                                                {
198
                                                        // these are the only numeric fields we *have* to swap
199
                                                        // all the rest are flags which (if we're careful) will work in either ordering
200
                                                        for(i = 0; i < 8; ++i)
201
                                                                slider[i] = EndianS32_LtoN(slider[i]);
202
                                                }
149 dmarschall 203
#else
189 dmarschall 204
                                                // Case #2: Windows is reading a Windows plugin (if Resource API failed, i.e. Win64 tries to open NE file)
205
                                                if( ((q[0] == PARM_SIZE) ||
206
                                                     (q[0] == PARM_SIZE_PREMIERE) ||
207
                                                     (q[0] == PARM_SIG_MAC)) && q[1] == 1
208
                                                        && (res = readPARM((char*)q, &gdata->parm, reason, 1)) )
209
                                                {
210
                                                }
152 dmarschall 211
 
189 dmarschall 212
                                                // Case #3: Windows is reading an old FilterFactory Mac file (.bin)
213
                                                else if( ((EndianS32_LtoN(q[0]) == PARM_SIZE) ||
214
                                                     (EndianS32_LtoN(q[0]) == PARM_SIZE_PREMIERE) ||
215
                                                     (EndianS32_LtoN(q[0]) == PARM_SIG_MAC)) && EndianS32_LtoN(q[1]) == 1
216
                                                        && (res = readPARM((char*)q, &gdata->parm, reason, 0 /*Strings are already PStrings*/)) )
217
                                                {
218
                                                        // these are the only numeric fields we *have* to swap
219
                                                        // all the rest are flags which (if we're careful) will work in either ordering
220
                                                        for(i = 0; i < 8; ++i)
221
                                                                slider[i] = EndianS32_LtoN(slider[i]);
222
                                                }
149 dmarschall 223
#endif
224
 
189 dmarschall 225
                                                if (res) break;
226
                                        }
227
                                        PIDISPOSEHANDLE(h);
228
                                }
229
                        }
230
                } // else no point in proceeding
231
                FSClose(refnum);
232
        }else
233
                *reason = "Could not open file.";
234
        return res;
149 dmarschall 235
}
236
 
45 toby 237
Boolean readPARM(Ptr p,PARM_T *pparm,char **reasonstr,int fromwin){
189 dmarschall 238
        int i;
2 toby 239
 
189 dmarschall 240
        if (*((unsigned int*)p) == PARM_SIZE_PREMIERE) {
241
                convert_premiere_to_photoshop(pparm, (PARM_T_PREMIERE*)p);
242
        } else {
243
                // Assume it is Photoshop. Signature either PARM_SIZE (0x2068) or 0x1C68
244
                memcpy(pparm,p,sizeof(PARM_T));
245
        }
2 toby 246
 
189 dmarschall 247
        if(fromwin){
248
                /* Windows PARM resource stores C strings - convert to Pascal strings  */
249
                myc2pstr((char*)pparm->category);
250
                myc2pstr((char*)pparm->title);
251
                myc2pstr((char*)pparm->copyright);
252
                myc2pstr((char*)pparm->author);
253
                for(i = 0; i < 4; ++i)
254
                        myc2pstr((char*)pparm->map[i]);
255
                for(i = 0; i < 8; ++i)
256
                        myc2pstr((char*)pparm->ctl[i]);
257
        }
45 toby 258
 
189 dmarschall 259
        for(i = 0; i < 4; ++i){
260
                if(expr[i]) free(expr[i]);
261
                expr[i] = my_strdup(pparm->formula[i]);
262
        }
2 toby 263
 
189 dmarschall 264
        for(i = 0; i < 8; ++i)
265
                slider[i] = pparm->val[i];
2 toby 266
 
189 dmarschall 267
        return true;
2 toby 268
}
269
 
270
Handle readfileintohandle(FILEREF r){
189 dmarschall 271
        FILEPOS n;
272
        Handle h;
273
        Ptr p;
2 toby 274
 
189 dmarschall 275
        if( GetEOF(r,&n) == noErr && (h = PINEWHANDLE(n)) ){
276
                p = PILOCKHANDLE(h,false);
277
                if(SetFPos(r,fsFromStart,0) == noErr && FSRead(r,(FILECOUNT*)&n,p) == noErr){
278
                        PIUNLOCKHANDLE(h);
279
                        return h;
280
                }
281
                PIDISPOSEHANDLE(h);
282
        }
283
        return NULL;
2 toby 284
}
285
 
188 dmarschall 286
Boolean fileHasExtension(StandardFileReply *sfr, const char* extension) {
287
#ifdef WIN_ENV
189 dmarschall 288
        char name[MAX_PATH+1];
289
        return sfr->nFileExtension && !strcasecmp(myp2cstrcpy(name,sfr->sfFile.name) + sfr->nFileExtension,extension);
188 dmarschall 290
#else
189 dmarschall 291
        char name[1025]; // https://stackoverflow.com/questions/1295135/longest-pathname-string-in-mac-os-x-hfs
292
        char* s = myp2cstrcpy(name,sfr->sfFile.name);
293
        return strcmp(s + strlen(s) - strlen(extension), extension) == 0;
188 dmarschall 294
#endif
295
}
296
 
2 toby 297
Boolean readfile(StandardFileReply *sfr,char **reason){
189 dmarschall 298
        FILEREF r;
299
        Handle h;
300
        Boolean res = false;
2 toby 301
 
189 dmarschall 302
        if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&r) == noErr){
303
                if( (h = readfileintohandle(r)) ){
304
                        if( (res = readparams(h,true,reason)) ) {
305
                                gdata->standalone = false; // so metadata fields will default, if user chooses Make...
145 dmarschall 306
 
189 dmarschall 307
                                if (fileHasExtension(sfr, ".pff")) {
308
                                        // If it is a Premiere settings file, we need to swap the channels red and blue
309
                                        char* tmp;
310
                                        tmp = my_strdup(expr[0]);
311
                                        memcpy((void*)expr[0], (void*)expr[2], sizeof(expr[0]));
312
                                        memcpy((void*)expr[2], (void*)tmp, sizeof(expr[2]));
313
                                        free(tmp);
314
                                }
315
                        }
145 dmarschall 316
 
189 dmarschall 317
                        PIDISPOSEHANDLE(h);
318
                }
319
                FSClose(r);
320
        }else
321
                *reason = "Could not open the file.";
2 toby 322
 
189 dmarschall 323
        return res;
2 toby 324
}