Subversion Repositories filter_foundry

Rev

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