Subversion Repositories filter_foundry

Rev

Rev 98 | Rev 101 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

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