Subversion Repositories filter_foundry

Rev

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

Rev Author Line No. Line
259 daniel-mar 1
/*
2
    This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
4
    Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
5
 
6
    This program is free software; you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation; either version 2 of the License, or
9
    (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with this program; if not, write to the Free Software
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
*/
20
 
21
#include <plstringfuncs.h>
22
#include <ASRegistry.h>
23
#include <ctype.h>
24
 
25
#include "ff.h"
26
 
27
#include "file_compat.h"
28
 
29
// MoreFiles headers
30
#include "FileCopy.h"
31
#include "MoreFilesExtras.h"
32
 
33
// prototype for a function included in Carbon's stdlib and declared in /usr/include/string.h
34
// but missing from MPW Universal header string.h
35
#ifndef _STRING_H_
268 daniel-mar 36
        char *strnstr(const char *, const char *, size_t);
259 daniel-mar 37
#endif
38
 
39
static OSErr doresources(FSSpec *srcplug, FSSpec *rsrccopy){
40
        short srcrn,dstrn;
41
        Handle hpipl,h;
42
        long origsize,newsize,parm_type,parm_id;
43
        OSErr e = noErr;
511 daniel-mar 44
        Str255 title, category;
259 daniel-mar 45
        long event_id;
46
 
268 daniel-mar 47
        #ifdef MACMACHO
259 daniel-mar 48
        FSRef inref,outref;
49
        // work with resources in data fork
50
        if( !(e = FSpMakeFSRef(srcplug,&inref))
51
         && !(e = FSOpenResourceFile(&inref,0/*forkNameLength*/,NULL/*forkName*/,fsRdPerm,&srcrn))
52
         && ((e = FSpMakeFSRef(rsrccopy,&outref))
53
                 || (e = FSOpenResourceFile(&outref,0/*forkNameLength*/,NULL/*forkName*/,fsWrPerm,&dstrn))) )
54
                CloseResFile(srcrn);
268 daniel-mar 55
        #else
259 daniel-mar 56
        // ordinary resource fork files
57
        srcrn = FSpOpenResFile(srcplug,fsRdPerm);
58
        if(srcrn != -1){
59
                dstrn = FSpOpenResFile(rsrccopy,fsWrPerm);
60
                if(dstrn == -1){
61
                        e = ResError();
62
                        CloseResFile(srcrn);
63
                }
64
        }else e = ResError();
268 daniel-mar 65
        #endif
259 daniel-mar 66
 
67
        if(!e){
68
                /* create a new PiPL resource for the standalone plugin,
69
                   with updated title and category strings */
70
 
373 daniel-mar 71
                if( (hpipl = Get1Resource('tpLT',16000))
259 daniel-mar 72
                 && (h = Get1Resource('PiPL',16000)) )
73
                {
74
                        RemoveResource(h);
75
 
76
                        DetachResource(hpipl);
77
 
393 daniel-mar 78
                        myc2pstrcpy(title,gdata->parm.szTitle);
259 daniel-mar 79
                        if(gdata->parm.popDialog)
80
                                PLstrcat(title,"\pÉ");
511 daniel-mar 81
 
82
                        myc2pstrcpy(category,gdata->parm.szCategory);
259 daniel-mar 83
 
84
                        origsize = GetHandleSize(hpipl);
85
                        SetHandleSize(hpipl,origsize+0x300); /* some slop for fixup to work with */
86
                        HLock(hpipl);
515 daniel-mar 87
                        newsize = fixpipl((PIPropertyList*) *hpipl,origsize,title,gdata->parm.szCategory,category,&event_id);
259 daniel-mar 88
                        HUnlock(hpipl);
89
                        SetHandleSize(hpipl,newsize);
90
 
91
                        AddResource(hpipl,'PiPL',16000,"\p");
92
 
393 daniel-mar 93
                        /* convert C strings to Pascal strings */
94
                        PARM_T pascal_parm = (PARM_T)malloc(sizeof(PARM_T));
95
                        memcpy(pascal_parm, gdata->parm, sizeof(PARM_T));
96
                        myc2pstr(pascal_parm->szCategory);
97
                        myc2pstr(pascal_parm->szTitle);
98
                        myc2pstr(pascal_parm->szCopyright);
99
                        myc2pstr(pascal_parm->szAuthor);
100
                        for (i = 0; i < 4; ++i)
101
                                myc2pstr(pascal_parm->szMap[i]);
102
                        for (i = 0; i < 8; ++i)
103
                                myc2pstr(pascal_parm->szCtl[i]);
104
 
259 daniel-mar 105
                        if( !(e = ResError()) ){
106
                                /* do a similar trick with the terminology resource,
107
                                   so the scripting system can distinguish the standalone plugin */
108
 
109
                                if( (h = Get1Resource(typeAETE,AETE_ID)) ){
110
                                        SetHandleSize(h,4096);
111
                                        HLock(h);
393 daniel-mar 112
                                        newsize = aete_generate((unsigned char*)*h, &pascal_parm, event_id);
259 daniel-mar 113
                                        HUnlock(h);
114
                                        SetHandleSize(h,newsize);
115
 
116
                                        ChangedResource(h);
117
 
118
                                        if( !(e = ResError()) ){
119
                                                /* add PARM resource */
393 daniel-mar 120
                                                if( !(e = PtrToHand(&pascal_parm,&h,sizeof(PARM_T))) ){
259 daniel-mar 121
                                                        if(gdata->obfusc){
122
                                                                HLock(h);
292 daniel-mar 123
                                                                obfusc((PARM_T*)*h);
259 daniel-mar 124
                                                                HUnlock(h);
375 daniel-mar 125
                                                                parm_type = OBFUSCDATA_TYPE_NEW;
126
                                                                parm_id = OBFUSCDATA_ID_NEW;
259 daniel-mar 127
                                                        }else{
375 daniel-mar 128
                                                                parm_type = PARM_TYPE;
129
                                                                parm_id = PARM_ID_NEW;
259 daniel-mar 130
                                                        }
131
                                                        AddResource(h,parm_type,parm_id,"\p");
132
                                                }
133
                                        }
134
                                }
135
 
136
                        }
137
 
138
                }
139
                if(!e)
140
                        e = ResError();
141
 
142
                CloseResFile(dstrn);
143
                CloseResFile(srcrn);
144
        }
145
 
146
        return e;
147
}
148
 
393 daniel-mar 149
static int copyletters(char *dst,char* src){
259 daniel-mar 150
        int i, n;
151
 
393 daniel-mar 152
        for(i=0; i<strlen(src); ++i) {
153
                if(isalpha(src[i])){
154
                        *dst++ = src[i];
259 daniel-mar 155
                        ++n;
156
                }
393 daniel-mar 157
        }
158
 
259 daniel-mar 159
        return n;
160
}
161
 
162
// Info.plist in new standalone copy needs to be edited -
163
// at least the CFBundleIdentifier property must be unique
164
 
165
static OSErr copyplist(FSSpec *fss, short dstvol, long dstdir){
166
        static char *key = "com.telegraphics.FilterFoundry";
167
        static unsigned char *fname="\pInfo.plist";
168
        char *buf,*save,*p;
169
        short rn,dstrn,i,n,m;
170
        FILEPOS eof;
171
        FILECOUNT count;
172
        OSErr e;
173
 
174
        if( !(e = HCreate(dstvol,dstdir,fname,'pled','TEXT')) ){
175
                if( !(e = HOpenDF(dstvol,dstdir,fname,fsWrPerm,&dstrn)) ){
176
                        if( !(e = FSpOpenDF(fss,fsRdPerm,&rn)) ){
177
                                if( !(e = GetEOF(rn,&eof)) && (buf = malloc(eof+1024)) ){
178
                                        if( !(e = FSRead(rn,&eof,buf)) ){
179
                                                buf[eof] = 0;
180
                                                if( (p = strnstr(buf,key,eof)) && (save = malloc(eof-(p-buf)+1)) ){
181
                                                        p += strlen(key);
182
                                                        // store text after matched string
183
                                                        strcpy(save,p);
184
 
185
                                                        *p++ = '.';
393 daniel-mar 186
                                                        n = copyletters(p,gdata->parm.szCategory);
259 daniel-mar 187
                                                        p += n;
188
                                                        if(n) *p++ = '.';
393 daniel-mar 189
                                                        m = copyletters(p,gdata->parm.szTitle);
259 daniel-mar 190
                                                        p += m;
191
                                                        if(!m){
192
                                                                // generate a random ASCII identifier
193
                                                                srand(TICKCOUNT());
194
                                                                for(i = 8; i--;)
195
                                                                        *p++ = 'a' + (rand() % 26);
196
                                                        }
197
                                                        strcpy(p,save);
198
 
199
                                                        count = strlen(buf);
200
                                                        e = FSWrite(dstrn,&count,buf);
201
 
202
                                                        free(save);
203
                                                }else e = paramErr; // not found?? shouldn't happen
204
                                        }
205
                                        free(buf);
206
                                }
207
                                FSClose(rn);
208
                        }
209
                        FSClose(dstrn);
210
                }
211
                if(e) HDelete(dstvol,dstdir,fname);
212
        }
213
        return e;
214
}
215
 
216
static OSErr make_bundle(StandardFileReply *sfr, short plugvol,
217
                                                 long plugdir, StringPtr plugname, char *reason)
218
{
219
        short dstvol = sfr->sfFile.vRefNum;
220
        long bundledir,contentsdir,macosdir,rsrcdir;
221
        DInfo fndrInfo;
222
        OSErr e;
223
        FSSpec fss,macosfss,rsrcfss,rsrccopyfss;
224
        char *why;
225
 
226
        if( !(e = FSpDirCreate(&sfr->sfFile,sfr->sfScript,&bundledir)) ){
227
                if(!(e = FSpGetDInfo(&sfr->sfFile,&fndrInfo)) ){
228
                        fndrInfo.frFlags |= kHasBundle;
229
                        FSpSetDInfo(&sfr->sfFile,&fndrInfo);
230
                }
231
                if( !(e = DirCreate(dstvol,bundledir,"\pContents",&contentsdir)) ){
232
                        if( !(e = DirCreate(dstvol,contentsdir,"\pMacOS",&macosdir)) ){
233
                                if( !(e = DirCreate(dstvol,contentsdir,"\pResources",&rsrcdir)) ){
234
                                        /* copy the Info.plist file, resource file, and executable */
235
                                        if( !(e = FSMakeFSSpec(plugvol,plugdir,"\p::MacOS:FilterFoundry",&macosfss))
236
                                         && !(e = FileCopy(macosfss.vRefNum,macosfss.parID,macosfss.name, dstvol,macosdir,NULL, NULL,NULL,0,false)) )
237
                                        {
238
                                                /* add PARM resources to each binary, and edit PiPLs */
239
                                                if( !(e = FSMakeFSSpec(plugvol,plugdir,"\p::Resources:FilterFoundry.rsrc",&rsrcfss))
240
                                                 && !(e = FileCopy(rsrcfss.vRefNum,rsrcfss.parID,rsrcfss.name, dstvol,rsrcdir,NULL, NULL,NULL,0,false))
241
                                                 && !(e = FSMakeFSSpec(dstvol,rsrcdir,"\pFilterFoundry.rsrc",&rsrccopyfss)) )
242
                                                {
243
                                                        if( !(e = doresources(&rsrcfss, &rsrccopyfss))
244
                                                         && !(e = FSMakeFSSpec(plugvol,plugdir,"\p::Info.plist",&fss)) )
245
                                                        {
246
                                                                e = copyplist(&fss,dstvol,contentsdir);
247
                                                                if(e){
248
                                                                        FSpDelete(&rsrccopyfss);
249
                                                                        why = "Can't copy Info.plist file.";
250
                                                                }
251
                                                        }else why = "Can't copy resources.";
252
                                                        if(e) HDelete(dstvol,macosdir,"\pFilterFoundry");
253
                                                }else why = "Can't copy FilterFoundry.rsrc file.";
254
                                                if(e) HDelete(dstvol,rsrcdir,plugname);
255
                                        }else why = "Can't copy FilterFoundry executable.";
256
                                        if(e) HDelete(dstvol,contentsdir,"\pResources");
257
                                }else why = "Can't create bundle Contents/Resources directory.";
258
                                if(e) HDelete(dstvol,contentsdir,"\pMacOS");
259
                        }else why = "Can't create bundle Contents/MacOS directory.";
260
                        if(e) HDelete(dstvol,bundledir,"\pContents");
261
                }else why = "Can't create bundle Contents directory.";
262
                if(e) FSpDelete(&sfr->sfFile);
263
        }else why = "Can't create new bundle directory.";
264
 
265
        if(e)
266
                sprintf(reason, "%s (%d)", why, e);
267
        else
268
                reason[0] = 0;
269
 
270
        return e;
271
}
272
 
273
static OSErr make_singlefile(StandardFileReply *sfr, short plugvol, long plugdir, StringPtr plugname){
274
        OSErr e;
275
        FSSpec origfss;
276
 
277
        e = FSpDelete(&sfr->sfFile);
278
        if(e && e != fnfErr){
279
                alertuser(_strdup("Can't replace the existing file. Try a different name or location."),_strdup(""));
280
                return userCanceledErr;
281
        }
282
 
283
        if( !(e = FileCopy(plugvol,plugdir,plugname, sfr->sfFile.vRefNum,sfr->sfFile.parID,NULL, sfr->sfFile.name,NULL,0,false))
284
         && !(e = FSMakeFSSpec(plugvol,plugdir,plugname,&origfss)) )
285
                /* add PARM resources, and edit PiPL */
286
                e = doresources(&origfss, &sfr->sfFile);
287
 
288
        return e;
289
}
290
 
291
OSErr make_standalone(StandardFileReply *sfr){
292
        OSErr e;
293
        short plugvol;
294
        long plugdir;
295
        Str255 plugname;
296
        char reason[0x100] = {0};
297
 
298
        if(!(e = GetFileLocation(CurResFile(),&plugvol,&plugdir,plugname))){
268 daniel-mar 299
                #ifdef MACMACHO
259 daniel-mar 300
                e = make_bundle(sfr,plugvol,plugdir,plugname,reason);
268 daniel-mar 301
                #else
259 daniel-mar 302
                e = make_singlefile(sfr,plugvol,plugdir,plugname);
268 daniel-mar 303
                #endif
259 daniel-mar 304
        }
305
 
306
        if(e && e != userCanceledErr) {
307
                alertuser(_strdup("Could not create standalone plugin."),reason);
308
        } else {
309
                showmessage(_strdup("Filter was sucessfully created"));
310
        }
311
 
312
        return e;
313
}