Subversion Repositories filter_foundry

Rev

Rev 539 | Rev 546 | 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.net
  4.     Copyright (C) 2018-2023 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. #define BUFSIZE 4L<<10
  37. #define MAXLINE 0x200
  38.  
  39. Boolean readparams_afs_pff(Handle h, TCHAR**reason){
  40.         Boolean res = false;
  41.         char linebuf[MAXLINE + 1] = { 0 };
  42.         char curexpr[MAXEXPR + 1] = { 0 };
  43.         char *p, *dataend, *q;
  44.         char c;
  45.         int linecnt, lineptr, exprcnt;
  46.  
  47.         if (!h) return false;
  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.  
  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)
  63.                                 ++p;
  64.  
  65.                         linebuf[lineptr] = '\0'; /* add terminating NUL to line buffer */
  66.  
  67.                         /* process complete line */
  68.                         if(linecnt==0){
  69.                                 if(strcmp(linebuf,"%RGB-1.0") != 0){
  70.                                         // Note: We don't set *reason, because we cannot be sure if it is a valid file in regards to a different data type
  71.                                         // We only set *Reason, if we are sure that it is an AFS file which is indeed wrong.
  72.                                         break;
  73.                                 }
  74.                         }else if(linecnt<=8){
  75.                                 int v;
  76.                                 v = atoi(linebuf);
  77.                                 if (v < 0) v = 0;
  78.                                 else if (v > 255) v = 255;
  79.                                 slider[linecnt-1] = (uint8_t)v;
  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.                                                 // TODO: isn't the limit 1024?! (because we need to have the NUL too?)
  85.                                                 if (reason) *reason = FF_GetMsg_Cpy(MSG_EXPRESSION1024_FOUND_ID);
  86.                                                 break;
  87.                                         }
  88.                                         q = cat(q,linebuf);
  89.                                 }else{
  90.                                         /* it's an empty line: we've completed the expr string */
  91.                                         if(expr[exprcnt])
  92.                                                 free(expr[exprcnt]);
  93.                                         *q = '\0';
  94.                                         if(!(expr[exprcnt] = my_strdup(curexpr))){
  95.                                                 if (reason) *reason = FF_GetMsg_Cpy(MSG_EXPRESSION_OOM_ID);
  96.                                                 break;
  97.                                         }
  98.  
  99.                                         if(++exprcnt == 4){
  100.                                                 res = true;
  101.                                                 break; /* got everything we want */
  102.                                         }
  103.  
  104.                                         q = curexpr; /* empty current expr, ready for next one */
  105.                                 }
  106.                         }
  107.  
  108.                         ++linecnt;
  109.                         lineptr = 0;
  110.                 }else{
  111.                         /* store character */
  112.                         if(c=='\\'){ /* escape sequence */
  113.                                 if(p < dataend){
  114.                                         c = *p++;
  115.                                         switch(c){
  116.                                         case 'r':
  117.                                                 #if WIN_ENV
  118.                                                 c = CR;
  119.                                                 if (lineptr < MAXLINE)
  120.                                                         linebuf[lineptr++] = c;
  121.                                                 c = LF;
  122.                                                 #else
  123.                                                 c = CR;
  124.                                                 #endif
  125.                                                 break;
  126.                                         case '\\': break;
  127.                                         //default:
  128.                                         //      if(alerts) alertuser((TCHAR*)TEXT("Warning:"),TEXT("Unknown escape sequence in input.")); // TODO (Not so important): TRANSLATE
  129.                                         }
  130.                                 }//else if(alerts) alertuser((TCHAR*)TEXT("Warning:"),TEXT("truncated escape sequence ends input")); // TODO (Not so important): TRANSLATE
  131.                         }
  132.  
  133.                         if(lineptr < MAXLINE)
  134.                                 linebuf[lineptr++] = c;
  135.                 }
  136.         }
  137.  
  138.         PIUNLOCKHANDLE(h);
  139.  
  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(photoshop->szCategory, "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->szTitle, (void*)premiere->szTitle, sizeof(photoshop->szTitle));
  161.         memcpy((void*)photoshop->szCopyright, (void*)premiere->szCopyright, sizeof(photoshop->szCopyright));
  162.         memcpy((void*)photoshop->szAuthor, (void*)premiere->szAuthor, sizeof(photoshop->szAuthor));
  163.         for (i=0;i<4;++i)
  164.                 memcpy((void*)photoshop->szMap[i], (void*)premiere->szMap[i], sizeof(photoshop->szMap[i]));
  165.         for (i=0;i<8;++i)
  166.                 memcpy((void*)photoshop->szCtl[i], (void*)premiere->szCtl[i], sizeof(photoshop->szCtl[i]));
  167.  
  168.         if (premiere->singleExpression) {
  169.                 memcpy((void*)photoshop->szFormula[0], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
  170.                 memcpy((void*)photoshop->szFormula[1], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
  171.                 memcpy((void*)photoshop->szFormula[2], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
  172.                 memcpy((void*)photoshop->szFormula[3], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
  173.         } else {
  174.                 memcpy((void*)photoshop->szFormula[0], (void*)premiere->szFormula[2], sizeof(photoshop->szFormula[2]));
  175.                 memcpy((void*)photoshop->szFormula[1], (void*)premiere->szFormula[1], sizeof(photoshop->szFormula[1]));
  176.                 memcpy((void*)photoshop->szFormula[2], (void*)premiere->szFormula[0], sizeof(photoshop->szFormula[0]));
  177.                 memcpy((void*)photoshop->szFormula[3], (void*)premiere->szFormula[3], sizeof(photoshop->szFormula[3]));
  178.         }
  179. }
  180.  
  181. char* _ffx_read_str(char** q) {
  182.         uint32_t len;
  183.         char* val;
  184.  
  185.         len = *((uint32_t*)*q);
  186.         *q += sizeof(uint32_t);
  187.         val = (char*)malloc((size_t)len + 1);
  188.         if (val != NULL) {
  189.                 memcpy(val, (char*)*q, len);
  190.                 val[len] = '\0';
  191.         }
  192.         *q += len;
  193.         return val;
  194. }
  195.  
  196. Boolean readfile_ffx(StandardFileReply* sfr, TCHAR** reason) {
  197.         Handle h;
  198.         Boolean res = false;
  199.         FILEREF refnum;
  200.         uint32_t len;
  201.         char* val;
  202.         int format_version = -1;
  203.         int i;
  204.  
  205.         UNREFERENCED_PARAMETER(reason);
  206.  
  207.         if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
  208.                 if ((h = readfileintohandle(refnum))) {
  209.                         char* q = (char*)PILOCKHANDLE(h, false);
  210.  
  211.                         len = *((uint32_t*)q);
  212.                         if (len == 6) {
  213.                                 val = _ffx_read_str(&q);
  214.                                 if (strcmp(val, "FFX1.0") == 0) format_version = 10;
  215.                                 else if (strcmp(val, "FFX1.1") == 0) format_version = 11;
  216.                                 else if (strcmp(val, "FFX1.2") == 0) format_version = 12;
  217.                                 free(val);
  218.                                 if (format_version > 0) {
  219.                                         simplewarning_id(MSG_FILTERS_UNLIMITED_WARNING_ID);
  220.  
  221.                                         val = _ffx_read_str(&q);
  222.                                         if (strlen(val) >= sizeof(gdata->parm.szTitle)) {
  223.                                                 val[sizeof(gdata->parm.szTitle) - 1] = '\0';
  224.                                         }
  225.                                         strcpy(gdata->parm.szTitle, val);
  226.                                         free(val);
  227.  
  228.                                         val = _ffx_read_str(&q);
  229.                                         if (strlen(val) >= sizeof(gdata->parm.szCategory)) {
  230.                                                 val[sizeof(gdata->parm.szCategory) - 1] = '\0';
  231.                                         }
  232.                                         strcpy(gdata->parm.szCategory, val);
  233.                                         free(val);
  234.  
  235.                                         val = _ffx_read_str(&q);
  236.                                         if (strlen(val) >= sizeof(gdata->parm.szAuthor)) {
  237.                                                 val[sizeof(gdata->parm.szAuthor) - 1] = '\0';
  238.                                         }
  239.                                         strcpy(gdata->parm.szAuthor, val);
  240.                                         free(val);
  241.  
  242.                                         val = _ffx_read_str(&q);
  243.                                         if (strlen(val) >= sizeof(gdata->parm.szCopyright)) {
  244.                                                 val[sizeof(gdata->parm.szCopyright) - 1] = '\0';
  245.                                         }
  246.                                         strcpy(gdata->parm.szCopyright, val);
  247.                                         free(val);
  248.  
  249.                                         // Channels I, R, G, B, A
  250.                                         for (i = 0; i < 4; i++) {
  251.                                                 val = _ffx_read_str(&q);
  252.                                                 if (i == 0) {
  253.                                                         char* val2 = _ffx_read_str(&q);
  254.                                                         if (strcmp(val, "0") != 0) {
  255.                                                                 // "Intro channel" existing
  256.                                                                 // C++ wrong warning: Using uninitialized memory "val2" (C6001)
  257.                                                                 #pragma warning(suppress : 6001)
  258.                                                                 char* combined = (char*)malloc(strlen(val) + strlen(",") + strlen(val2) + 1/*NUL byte*/);
  259.                                                                 if (combined != NULL) {
  260.                                                                         sprintf(combined, "%s,%s", val, val2);
  261.                                                                         free(val);
  262.                                                                         free(val2);
  263.                                                                         val = combined;
  264.                                                                 }
  265.                                                         }
  266.                                                         else {
  267.                                                                 free(val);
  268.                                                                 val = val2;
  269.                                                         }
  270.                                                 }
  271.                                                 if (strlen(val) >= sizeof(gdata->parm.szFormula[i])) {
  272.                                                         if (i == 0) {
  273.                                                                 simplealert_id(MSG_FORMULA_IR_1023_TRUNCATED_ID);
  274.                                                         }
  275.                                                         else if (i == 1) {
  276.                                                                 simplealert_id(MSG_FORMULA_G_1023_TRUNCATED_ID);
  277.                                                         }
  278.                                                         else if (i == 2) {
  279.                                                                 simplealert_id(MSG_FORMULA_B_1023_TRUNCATED_ID);
  280.                                                         }
  281.                                                         else if (i == 3) {
  282.                                                                 simplealert_id(MSG_FORMULA_A_1023_TRUNCATED_ID);
  283.                                                         }
  284.                                                         // C++ wrong warning: Buffer overflow (C6386)
  285.                                                         #pragma warning(suppress : 6386)
  286.                                                         val[sizeof(gdata->parm.szFormula[i]) - 1] = '\0';
  287.                                                 }
  288.                                                 if (expr[i]) free(expr[i]);
  289.                                                 expr[i] = my_strdup(val);
  290.                                                 strcpy(gdata->parm.szFormula[i], val);
  291.                                                 free(val);
  292.                                         }
  293.  
  294.                                         // Sliders
  295.                                         for (i = 0; i < 8; i++) {
  296.                                                 char* sliderName;
  297.                                                 int v;
  298.                                                 val = _ffx_read_str(&q);
  299.                                                 sliderName = val;
  300.                                                 if (format_version >= 12) {
  301.                                                         // Format FFX1.2 has prefixes {S} = Slider, {C} = Checkbox, none = Slider
  302.                                                         if ((sliderName[0] == '{') && (sliderName[1] == 'S') && (sliderName[2] == '}')) sliderName += 3;
  303.                                                         else if ((sliderName[0] == '{') && (sliderName[1] == 'C') && (sliderName[2] == '}')) sliderName += 3;
  304.                                                 }
  305.                                                 if (strlen(val) >= sizeof(gdata->parm.szCtl[i])) {
  306.                                                         val[sizeof(gdata->parm.szCtl[i]) - 1] = '\0';
  307.                                                 }
  308.                                                 strcpy(gdata->parm.szCtl[i], sliderName);
  309.                                                 free(val);
  310.                                                 gdata->parm.ctl_used[i] = (bool32_t)*((byte*)q);
  311.                                                 q += sizeof(byte);
  312.                                                 gdata->parm.val[i] = *((uint32_t*)q);
  313.                                                 v = *((uint32_t*)q);
  314.                                                 if (v < 0) v = 0;
  315.                                                 else if (v > 255) v = 255;
  316.                                                 slider[i] = (uint8_t)v;
  317.                                                 q += sizeof(uint32_t);
  318.                                         }
  319.  
  320.                                         // Maps (are not part of the format!)
  321.                                         strcpy(gdata->parm.szMap[0], "Map 0:");
  322.                                         strcpy(gdata->parm.szMap[1], "Map 1:");
  323.                                         strcpy(gdata->parm.szMap[2], "Map 2:");
  324.                                         strcpy(gdata->parm.szMap[3], "Map 3:");
  325.  
  326.                                         res = true;
  327.                                 }
  328.                         }
  329.                         PIDISPOSEHANDLE(h);
  330.                 }
  331.                 FSClose(refnum);
  332.         }
  333.  
  334.         if (res) gdata->obfusc = false;
  335.         return res;
  336. }
  337.  
  338. Boolean readfile_8bf(StandardFileReply *sfr, TCHAR**reason){
  339.         unsigned char magic[2];
  340.         FILECOUNT count;
  341.         Handle h;
  342.         Boolean res = false;
  343.         FILEREF refnum;
  344.  
  345.         if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&refnum) == noErr){
  346.                 // check DOS EXE magic number
  347.                 count = 2;
  348.                 if(FSRead(refnum,&count,magic) == noErr /*&& magic[0]=='M' && magic[1]=='Z'*/){
  349.                         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)
  350.                                 if( (h = readfileintohandle(refnum)) ){
  351.                                         long *q = (long*)PILOCKHANDLE(h,false);
  352.  
  353.                                         // look for signature at start of valid PARM resource
  354.                                         // This signature is observed in Filter Factory standalones.
  355.                                         for( count /= 4 ; count >= PARM_SIZE/4 ; --count, ++q )
  356.                                         {
  357.                                                 res = readPARM(&gdata->parm, (Ptr)q);
  358.                                                 if (res) break;
  359.                                         }
  360.  
  361.                                         PIDISPOSEHANDLE(h);
  362.                                 }
  363.                         }
  364.                 } // else no point in proceeding
  365.                 FSClose(refnum);
  366.         }else
  367.                 if (reason) *reason = FF_GetMsg_Cpy(MSG_CANNOT_OPEN_FILE_ID);
  368.  
  369.         if (res) gdata->obfusc = false;
  370.         return res;
  371. }
  372.  
  373. Boolean readPARM(PARM_T* pparm, Ptr p){
  374.         Boolean towin, tomac, fromwin, frommac;
  375.         unsigned int signature = *((unsigned int*)p);
  376.         unsigned int standalone = *((unsigned int*)p+1);
  377.  
  378.         // Find out our OS ("reader") the OS of the plugin ("source")
  379.         #ifdef MAC_ENV
  380.         towin = false;
  381.         tomac = true;
  382.         fromwin = ((EndianS32_LtoN(signature) == PARM_SIZE) ||
  383.                 (EndianS32_LtoN(signature) == PARM_SIZE_PREMIERE) ||
  384.                 (EndianS32_LtoN(signature) == PARM_SIG_MAC)) && EndianS32_LtoN(standalone) == 1;
  385.         frommac = ((signature == PARM_SIZE) ||
  386.                 (signature == PARM_SIZE_PREMIERE) ||
  387.                 (signature == PARM_SIG_MAC)) && standalone == 1;
  388.         #else
  389.         towin = true;
  390.         tomac = false;
  391.         fromwin = ((signature == PARM_SIZE) ||
  392.                 (signature == PARM_SIZE_PREMIERE) ||
  393.                 (signature == PARM_SIG_MAC)) && standalone == 1;
  394.         frommac = ((EndianS32_LtoN(signature) == PARM_SIZE) ||
  395.                 (EndianS32_LtoN(signature) == PARM_SIZE_PREMIERE) ||
  396.                 (EndianS32_LtoN(signature) == PARM_SIG_MAC)) && EndianS32_LtoN(standalone) == 1;
  397.         #endif
  398.  
  399.         // Is it a valid signature?
  400.         if (!fromwin && !frommac) {
  401.                 // No valid signature found
  402.                 return false;
  403.         }
  404.  
  405.         // Does it come from Premiere or Photoshop?
  406.         // Initialize pparm
  407.         if ((signature == PARM_SIZE_PREMIERE) || (EndianS32_LtoN(signature) == PARM_SIZE_PREMIERE)) {
  408.                 // It comes from Premiere. Swap R and B channel and convert to a Photoshop PARM_T
  409.                 convert_premiere_to_photoshop(pparm, (PARM_T_PREMIERE*)p);
  410.         } else {
  411.                 // It is already Photoshop. Just copy to pparm.
  412.                 memcpy(pparm, p, sizeof(PARM_T));
  413.         }
  414.  
  415.         // Do we need to do string conversion?
  416.         if (frommac) {
  417.                 int i;
  418.  
  419.                 /* Mac PARM resource stores Pascal strings - convert to C strings, since this is what we work internally with (regardles of OS) */
  420.                 myp2cstr((unsigned char*)pparm->szCategory);
  421.                 myp2cstr((unsigned char*)pparm->szTitle);
  422.                 myp2cstr((unsigned char*)pparm->szCopyright);
  423.                 myp2cstr((unsigned char*)pparm->szAuthor);
  424.                 for (i = 0; i < 4; ++i)
  425.                         myp2cstr((unsigned char*)pparm->szMap[i]);
  426.                 for (i = 0; i < 8; ++i)
  427.                         myp2cstr((unsigned char*)pparm->szCtl[i]);
  428.         }
  429.  
  430.         // Case #1: Mac is reading Windows (Win16/32/64) plugin
  431.         if (fromwin && tomac) {
  432.                 size_t i;
  433.  
  434.                 // Convert copyright CRLF to CR (actually, just removing LF)
  435.                 char copyrightCRLF[256] = { 0 };
  436.                 char* pCopyright = &copyrightCRLF[0];
  437.                 for (i = 0; i < strlen(pparm->szCopyright); i++) {
  438.                         if (pparm->szCopyright[i] != LF) {
  439.                                 *pCopyright++ = pparm->szCopyright[i];
  440.                         }
  441.                 }
  442.                 *pCopyright++ = '\0';
  443.                 strcpy(pparm->szCopyright, copyrightCRLF);
  444.  
  445.                 // these are the only numeric fields we *have* to swap
  446.                 // all the rest are bool_t flags which (if we're careful) will work in either ordering
  447.                 for (i = 0; i < 8; ++i)
  448.                         pparm->val[i] = EndianS32_LtoN(pparm->val[i]);
  449.         }
  450.  
  451.         // Case #2: Mac is reading Mac (in case the normal resource extraction didn't work)
  452.         // Nothing to do
  453.  
  454.         // 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)
  455.         // Nothing to do
  456.  
  457.         // Case #4: Windows is reading an old FilterFactory Mac file
  458.         // Note: You must read the ".rsrc" resource fork, not the standalone binary!
  459.         if (frommac && towin) {
  460.                 size_t i;
  461.  
  462.                 // Convert CR in the copyright field to CRLF.
  463.                 char copyrightCRLF[256] = { 0 };
  464.                 char* pCopyright = &copyrightCRLF[0];
  465.                 for (i = 0; i < strlen(pparm->szCopyright); i++) {
  466.                         *pCopyright++ = pparm->szCopyright[i];
  467.                         if (pparm->szCopyright[i] == CR) {
  468.                                 *pCopyright++ = LF;
  469.                         }
  470.                 }
  471.                 *pCopyright++ = '\0';
  472.                 strcpy(pparm->szCopyright, copyrightCRLF);
  473.  
  474.                 // these are the only numeric fields we *have* to swap
  475.                 // all the rest are bool_t flags which (if we're careful) will work in either ordering
  476.                 for (i = 0; i < 8; ++i)
  477.                         pparm->val[i] = EndianS32_LtoN(pparm->val[i]);
  478.         }
  479.  
  480.         // Now set the values in pparm into the working variables expr[] and slider[], so that they are visible in the GUI
  481.         {
  482.                 int i;
  483.                 for (i = 0; i < 4; ++i) {
  484.                         if (expr[i]) free(expr[i]);
  485.                         expr[i] = my_strdup(pparm->szFormula[i]);
  486.                 }
  487.  
  488.                 for (i = 0; i < 8; ++i) {
  489.                         slider[i] = (uint8_t)pparm->val[i];
  490.                         /*
  491.                         if (slider[i] > 0xFF) {
  492.                                 // Wrong endianess (e.g. reading a Mac rsrc on Windows)
  493.                                 // Should not happen since we did the stuff above
  494.                                 slider[i] = (uint8_t)EndianS32_LtoN(slider[i]);
  495.                         }
  496.                         */
  497.                 }
  498.         }
  499.  
  500.         return true;
  501. }
  502.  
  503. Handle readfileintohandle(FILEREF r){
  504.         FILEPOS n;
  505.         Handle h;
  506.         Ptr p;
  507.  
  508.         if( GetEOF(r,&n) == noErr && (h = PINEWHANDLE(n)) ){
  509.                 p = PILOCKHANDLE(h,false);
  510.                 if(SetFPos(r,fsFromStart,0) == noErr && FSRead(r,(FILECOUNT*)&n,p) == noErr){
  511.                         PIUNLOCKHANDLE(h);
  512.                         return h;
  513.                 }
  514.                 PIDISPOSEHANDLE(h);
  515.         }
  516.         return NULL;
  517. }
  518.  
  519. Boolean _picoLineContainsKey(char* line, char** content, const char* searchkey/*=NULL*/) {
  520.         size_t i;
  521.         for (i = 0; i < strlen(line); i++) {
  522.                 if (line[i] == '?') break; // avoid that "a?b:c" is detected as key
  523.                 if (line[i] == ':') {
  524.                         // Note: We are ignoring whitespaces, i.e. " A :" != "A:" (TODO: should we change this?)
  525.                         if ((searchkey == NULL) || ((i == strlen(searchkey)) && (memcmp(line, searchkey, i) == 0))) {
  526.                                 i++; // jump over ':' char
  527.                                 //while ((line[i] == ' ') || (line[i] == TAB)) i++; // Trim value left
  528.                                 *content = line + i;
  529.                                 return true;
  530.                         }
  531.                 }
  532.         }
  533.         *content = line;
  534.         return false;
  535. }
  536.  
  537. void _ffdcomp_removebrackets(char* x, char* maxptr) {
  538.         char* closingBracketPos = NULL;
  539.         Boolean openingBracketFound = false;
  540.         if (x[0] == '[') {
  541.                 openingBracketFound = true;
  542.         }
  543.         x[0] = ':';
  544.         x++;
  545.         while (x < maxptr) {
  546.                 if ((!openingBracketFound) && (x[0] == '[')) {
  547.                         openingBracketFound = true;
  548.                         x[0] = ' ';
  549.                 }
  550.                 else if (openingBracketFound) {
  551.                         if (x[0] == ']') {
  552.                                 closingBracketPos = x;
  553.                         }
  554.                         else if ((x[0] == CR) || (x[0] == LF)) {
  555.                                 if (closingBracketPos) closingBracketPos[0] = ' '; // last closing pos before CR/LF
  556.                                 break;
  557.                         }
  558.                 }
  559.                 x++;
  560.         }
  561. }
  562.  
  563. // isFormula=false => outputFile is C string. TXT linebreaks become spaces.
  564. // isFormula=true  => outputFile is C string. TXT line breaks become CRLF line breaks
  565. Boolean _picoReadProperty(char* inputFile, size_t maxInput, const char* property, char* outputFile, size_t maxOutput, Boolean isFormula) {
  566.         size_t i;
  567.         char* outputwork;
  568.         char* sline;
  569.         char* svalue;
  570.         char* inputwork;
  571.         char* inputworkinitial;
  572.         outputwork = outputFile;
  573.         sline = NULL;
  574.         svalue = NULL;
  575.         // Check parameters
  576.         if (maxOutput == 0) return false;
  577.         if (inputFile == NULL) return false;
  578.         // Let input memory be read-only, +1 for terminal zero
  579.         //char* inputwork = inputFile;
  580.         inputwork = (char*)malloc((size_t)maxInput + 1/*NUL byte*/);
  581.         inputworkinitial = inputwork;
  582.         if (inputwork == NULL) return false;
  583.         memcpy(inputwork, inputFile, maxInput);
  584.         inputwork[maxInput] = '\0'; // otherwise strstr() will crash
  585.  
  586.         // Transform "FFDecomp" TXT file into the similar "PluginCommander" TXT file
  587.         if (strstr(inputwork, "Filter Factory Plugin Information:")) {
  588.                 char* x;
  589.                 char* k1;
  590.                 char* k2;
  591.                 // Metadata:
  592.                 x = strstr(inputwork, "CATEGORY:");
  593.                 if (x) memcpy(x, "Category:", strlen("Category:"));
  594.                 x = strstr(inputwork, "TITLE:");
  595.                 if (x) memcpy(x, "Title:", strlen("Title:"));
  596.                 x = strstr(inputwork, "COPYRIGHT:");
  597.                 if (x) memcpy(x, "Copyright:", strlen("Copyright:"));
  598.                 x = strstr(inputwork, "AUTHOR:");
  599.                 if (x) memcpy(x, "Author:", strlen("Author:"));
  600.                 // Controls:
  601.                 for (i = 0; i < 8; i++) {
  602.                         k1 = (char*)malloc(strlen("Control X:") + 1/*NUL byte*/);
  603.                         sprintf(k1, "Control %d:", (int)i);
  604.                         x = strstr(inputwork, k1);
  605.                         if (x) {
  606.                                 k2 = (char*)malloc(strlen("ctl[X]:   ") + 1/*NUL byte*/);
  607.                                 sprintf(k2, "ctl[%d]:   ", (int)i);
  608.                                 memcpy(x, k2, strlen(k2));
  609.                                 x += strlen("ctl[X]");
  610.                                 _ffdcomp_removebrackets(x, inputwork + maxInput - 1);
  611.                                 free(k2);
  612.                         }
  613.                         free(k1);
  614.                 }
  615.                 // Maps:
  616.                 for (i = 0; i < 4; i++) {
  617.                         k1 = (char*)malloc(strlen("Map X:") + 1/*NUL byte*/);
  618.                         sprintf(k1, "Map %d:", (int)i);
  619.                         x = strstr(inputwork, k1);
  620.                         if (x) {
  621.                                 k2 = (char*)malloc(strlen("map[X]:") + 1/*NUL byte*/);
  622.                                 sprintf(k2, "map[%d]:", (int)i);
  623.                                 memcpy(x, k2, strlen(k2));
  624.                                 x += strlen("map[X]");
  625.                                 _ffdcomp_removebrackets(x, inputwork + maxInput - 1);
  626.                                 free(k2);
  627.                         }
  628.                         free(k1);
  629.                 }
  630.                 // Convert all '\r' to '\n' for the next step to be easier
  631.                 for (i = 0; i < maxInput; i++) {
  632.                         if (inputworkinitial[i] == CR) inputworkinitial[i] = LF;
  633.                 }
  634.                 x = strstr(inputwork, "\nR=\n");
  635.                 if (x) memcpy(x, "\nR:\n", strlen("\nR:\n"));
  636.                 x = strstr(inputwork, "\nG=\n");
  637.                 if (x) memcpy(x, "\nG:\n", strlen("\nG:\n"));
  638.                 x = strstr(inputwork, "\nB=\n");
  639.                 if (x) memcpy(x, "\nB:\n", strlen("\nB:\n"));
  640.                 x = strstr(inputwork, "\nA=\n");
  641.                 if (x) memcpy(x, "\nA:\n", strlen("\nA:\n"));
  642.         }
  643.         // Replace all \r and \n with \0, so that we can parse easier
  644.         for (i = 0; i < maxInput; i++) {
  645.                 if (inputworkinitial[i] == CR) inputworkinitial[i] = '\0';
  646.                 else if (inputworkinitial[i] == LF) inputworkinitial[i] = '\0';
  647.         }
  648.  
  649.         // Find line that contains out key
  650.         inputwork = inputworkinitial;
  651.         do {
  652.                 if (inputwork > inputworkinitial + maxInput) {
  653.                         // Key not found. Set output to empty string
  654.                         outputwork[0] = '\0';
  655.                         free(inputworkinitial);
  656.                         return false;
  657.                 }
  658.                 sline = inputwork;
  659.                 inputwork += strlen(sline) + 1;
  660.                 if (inputwork - 1 > inputworkinitial + maxInput) {
  661.                         // Key not found. Set output to empty string
  662.                         // TODO: will that be ever called?
  663.                         outputwork[0] = '\0';
  664.                         free(inputworkinitial);
  665.                         return false;
  666.                 }
  667.         } while (!_picoLineContainsKey(sline, &svalue, property));
  668.  
  669.         // Read line(s) until we find a line with another key, or the line end
  670.         do {
  671.                 while ((svalue[0] == ' ') || (svalue[0] == TAB)) svalue++; // Trim left
  672.                 while ((svalue[strlen(svalue) - 1] == ' ') || (svalue[strlen(svalue) - 1] == TAB)) svalue[strlen(svalue) - 1] = '\0'; // Trim right
  673.  
  674.                 if (strlen(svalue) > 0) {
  675.                         if (outputwork + strlen(svalue) + (isFormula ? 3/*CRLF+NUL*/ : 2/*space+NUL*/) > outputFile + maxOutput) {
  676.                                 size_t remaining = maxOutput - (outputwork - outputFile) - 1;
  677.                                 //printf("BUFFER FULL (remaining = %d)\n", remaining);
  678.                                 memcpy(outputwork, svalue, remaining);
  679.                                 outputwork += remaining;
  680.                                 outputwork[0] = '\0';
  681.                                 free(inputworkinitial);
  682.                                 return true;
  683.                         }
  684.                         else {
  685.                                 memcpy(outputwork, svalue, strlen(svalue));
  686.                                 outputwork += strlen(svalue);
  687.                                 if (isFormula) {
  688.                                         // Formulas: TXT line break stays line break (important if you have comments!)
  689.                                         outputwork[0] = CR;
  690.                                         outputwork[1] = LF;
  691.                                         outputwork += 2;
  692.                                 }
  693.                                 else {
  694.                                         // Everything else: TXT line breaks becomes single whitespace
  695.                                         outputwork[0] = ' ';
  696.                                         outputwork++;
  697.                                 }
  698.                         }
  699.                 }
  700.                 outputwork[0] = '\0';
  701.  
  702.                 // Process next line
  703.                 if (inputwork > inputworkinitial + maxInput) break;
  704.                 sline = inputwork;
  705.                 inputwork += strlen(sline) + 1;
  706.                 if (inputwork - 1 > inputworkinitial + maxInput) break; // TODO: will that be ever called?
  707.         } while (!_picoLineContainsKey(sline, &svalue, NULL));
  708.  
  709.         // Remove trailing whitespace
  710.         if (outputwork > outputFile) {
  711.                 outputwork -= 1;
  712.                 outputwork[0] = '\0';
  713.         }
  714.         free(inputworkinitial);
  715.         return true;
  716. }
  717.  
  718. Boolean readfile_picotxt_or_ffdecomp(StandardFileReply* sfr, TCHAR** reason) {
  719.         extern int ctls[], maps[];
  720.  
  721.         Handle h;
  722.         Boolean res = false;
  723.         FILEREF refnum;
  724.  
  725.         UNREFERENCED_PARAMETER(reason);
  726.  
  727.         if (!fileHasExtension(sfr, TEXT(".txt"))) return false;
  728.  
  729.         if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
  730.                 if ((h = readfileintohandle(refnum))) {
  731.                         FILECOUNT count = (FILECOUNT)PIGETHANDLESIZE(h);
  732.                         char* q = PILOCKHANDLE(h, false);
  733.  
  734.                         char dummy[256];
  735.                         if (_picoReadProperty(q, count, "Title", dummy, sizeof(dummy), false)) {
  736.                                 int i;
  737.  
  738.                                 // Plugin infos
  739.                                 _picoReadProperty(q, count, "Title", gdata->parm.szTitle, sizeof(gdata->parm.szTitle), false);
  740.                                 _picoReadProperty(q, count, "Category", gdata->parm.szCategory, sizeof(gdata->parm.szCategory), false);
  741.                                 _picoReadProperty(q, count, "Author", gdata->parm.szAuthor, sizeof(gdata->parm.szAuthor), false);
  742.                                 _picoReadProperty(q, count, "Copyright", gdata->parm.szCopyright, sizeof(gdata->parm.szCopyright), false);
  743.                                 //_picoReadProperty(q, count, "Filename", gdata->parm.xxx, sizeof(gdata->parm.xxx), false);
  744.  
  745.                                 // Expressions
  746.                                 if (!_picoReadProperty(q, count, "R", gdata->parm.szFormula[0], sizeof(gdata->parm.szFormula[0]), true))
  747.                                         strcpy(gdata->parm.szFormula[0], "r");
  748.                                 if (!_picoReadProperty(q, count, "G", gdata->parm.szFormula[1], sizeof(gdata->parm.szFormula[1]), true))
  749.                                         strcpy(gdata->parm.szFormula[1], "g");
  750.                                 if (!_picoReadProperty(q, count, "B", gdata->parm.szFormula[2], sizeof(gdata->parm.szFormula[2]), true))
  751.                                         strcpy(gdata->parm.szFormula[2], "b");
  752.                                 if (!_picoReadProperty(q, count, "A", gdata->parm.szFormula[3], sizeof(gdata->parm.szFormula[3]), true))
  753.                                         strcpy(gdata->parm.szFormula[3], "a");
  754.                                 for (i = 0; i < 4; i++) {
  755.                                         if (expr[i]) free(expr[i]);
  756.                                         expr[i] = my_strdup(gdata->parm.szFormula[i]);
  757.                                 }
  758.  
  759.                                 for (i = 0; i < 8; i++) {
  760.                                         int v;
  761.                                         char keyname[6/*strlen("ctl[X]")*/ + 1/*strlen("\0")*/], tmp[5];
  762.  
  763.                                         // Slider names
  764.                                         sprintf(keyname, "ctl[%d]", i);
  765.                                         _picoReadProperty(q, count, keyname, gdata->parm.szCtl[i], sizeof(gdata->parm.szCtl[i]), false);
  766.  
  767.                                         // Slider values
  768.                                         sprintf(keyname, "val[%d]", i);
  769.                                         if (!_picoReadProperty(q, count, keyname, tmp, sizeof(tmp), false)) {
  770.                                                 sprintf(keyname, "def[%d]", i);
  771.                                                 if (!_picoReadProperty(q, count, keyname, tmp, sizeof(tmp), false)) {
  772.                                                         strcpy(tmp,"0");
  773.                                                 }
  774.                                         }
  775.                                         v = atoi(tmp);
  776.                                         if (v < 0) v = 0;
  777.                                         else if (v > 255) v = 255;
  778.                                         gdata->parm.val[i] = slider[i] = (uint8_t)v;
  779.                                 }
  780.  
  781.                                 // Map names
  782.                                 for (i = 0; i < 4; i++) {
  783.                                         char keyname[6/*strlen("map[X]")*/ + 1/*strlen("\0")*/];
  784.                                         sprintf(keyname, "map[%d]", i);
  785.                                         _picoReadProperty(q, count, keyname, gdata->parm.szMap[i], sizeof(gdata->parm.szMap[i]), false);
  786.                                 }
  787.  
  788.                                 //These will be set when the expressions are evaluated anyway. So this part is optional:
  789.                                 checksliders(4, ctls, maps);
  790.                                 for (i = 0; i < 8; i++) gdata->parm.ctl_used[i] = ctls[i];
  791.                                 for (i = 0; i < 4; i++) gdata->parm.map_used[i] = maps[i];
  792.  
  793.                                 res = true;
  794.                         }
  795.  
  796.                         PIUNLOCKHANDLE(h);
  797.                         PIDISPOSEHANDLE(h);
  798.                 }
  799.                 FSClose(refnum);
  800.         }
  801.  
  802.         return res;
  803. }
  804.  
  805. Boolean _gufReadProperty(char* fileContents, size_t argMaxInputLength, const char* section, const char* keyname, char* argOutput, size_t argMaxOutLength) {
  806.         size_t iTmp;
  807.         char* tmpFileContents, * tmpSection, * tmpStart, * tmpStart2, * tmpEnd, * tmpKeyname, * tmpStart3, * tmpStart4, * inputwork;
  808.  
  809.         // Check parameters
  810.         if (argMaxOutLength == 0) return false;
  811.         if (fileContents == NULL) return false;
  812.  
  813.         // Handle argMaxInputLength
  814.         //char* inputwork = fileContents;
  815.         inputwork = (char*)malloc((size_t)argMaxInputLength + 1/*NUL byte*/);
  816.         if (inputwork == NULL) return false;
  817.         memcpy(inputwork, fileContents, argMaxInputLength);
  818.         inputwork[argMaxInputLength] = '\0';
  819.  
  820.         // Prepare the input file contents to make it easier parse-able
  821.         iTmp = strlen(inputwork) + strlen("\n\n[");
  822.         tmpFileContents = (char*)malloc(iTmp + 1/*NUL byte*/);
  823.         if (tmpFileContents == NULL) return false;
  824.         sprintf(tmpFileContents, "\n%s\n[", inputwork);
  825.         for (iTmp = 0; iTmp < strlen(tmpFileContents); iTmp++) {
  826.                 if (tmpFileContents[iTmp] == '\r') tmpFileContents[iTmp] = '\n';
  827.         }
  828.  
  829.         // Find the section begin
  830.         iTmp = strlen(section) + strlen("\n[]\n");
  831.         tmpSection = (char*)malloc(iTmp + 1/*NUL byte*/);
  832.         if (tmpSection == NULL) return false;
  833.         sprintf(tmpSection, "\n[%s]\n", section);
  834.         tmpStart = strstr(tmpFileContents, tmpSection);
  835.         if (tmpStart == NULL) return false;
  836.         tmpStart += iTmp;
  837.  
  838.         // Find the end of the section and set a NULL terminator to it
  839.         iTmp = strlen(tmpStart) + strlen("\n");
  840.         tmpStart2 = (char*)malloc(iTmp + 1/*NUL byte*/);
  841.         if (tmpStart2 == NULL) return false;
  842.         sprintf(tmpStart2, "\n%s", tmpStart);
  843.         tmpEnd = strstr(tmpStart2, "\n[");
  844.         if (tmpEnd == NULL) return false;
  845.         tmpEnd[0] = '\0';
  846.  
  847.         // Find the start of the value
  848.         iTmp = strlen(keyname) + strlen("\n=");
  849.         tmpKeyname = (char*)malloc(iTmp + 1/*NUL byte*/);
  850.         if (tmpKeyname == NULL) return false;
  851.         sprintf(tmpKeyname, "\n%s=", keyname);
  852.         tmpStart3 = strstr(tmpStart2, tmpKeyname);
  853.         if (tmpStart3 == NULL) return false;
  854.         tmpStart3 += strlen("\n");
  855.         tmpStart4 = strstr(tmpStart3, "=");
  856.         if (tmpStart4 == NULL) return false;
  857.         tmpStart4 += strlen("=");
  858.  
  859.         // Find the end of the value
  860.         tmpEnd = strstr(tmpStart4, "\n");
  861.         if (tmpEnd == NULL) return false;
  862.         tmpEnd[0] = '\0';
  863.  
  864.         // Copy to output
  865.         if (strlen(tmpStart4) < argMaxOutLength + 1) argMaxOutLength = strlen(tmpStart4) + 1;
  866.         memcpy(argOutput, tmpStart4, argMaxOutLength);
  867.         argOutput[argMaxOutLength - 1] = '\0';
  868.  
  869.         // Free all temporary stuff
  870.         //for (iTmp = 0; iTmp < strlen(tmpFileContents); iTmp++) tmpFileContents[iTmp] = '\0';
  871.         free(tmpFileContents);
  872.         //for (iTmp = 0; iTmp < strlen(tmpSection); iTmp++) tmpSection[iTmp] = '\0';
  873.         free(tmpSection);
  874.         //for (iTmp = 0; iTmp < strlen(tmpKeyname); iTmp++) tmpKeyname[iTmp] = '\0';
  875.         free(tmpKeyname);
  876.         //for (iTmp = 0; iTmp < strlen(tmpStart2); iTmp++) tmpStart2[iTmp] = '\0';
  877.         free(tmpStart2);
  878.  
  879.         // Return success
  880.         return true;
  881. }
  882.  
  883. Boolean readfile_guf(StandardFileReply* sfr, TCHAR** reason) {
  884.         extern int ctls[], maps[];
  885.  
  886.         Handle h;
  887.         Boolean res = false;
  888.         FILEREF refnum;
  889.  
  890.         // TODO: Decode UTF-8 to ANSI (or "?" for unknown characters)
  891.  
  892.         if (!fileHasExtension(sfr, TEXT(".guf"))) return false;
  893.  
  894.         if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
  895.                 if ((h = readfileintohandle(refnum))) {
  896.                         FILECOUNT count = (FILECOUNT)PIGETHANDLESIZE(h);
  897.                         char* q = PILOCKHANDLE(h, false);
  898.  
  899.                         char out[256];
  900.                         if (_gufReadProperty(q, count, "GUF", "Protocol", out, sizeof(out))) {
  901.                                 if (strcmp(out, "1") != 0) {
  902.                                         if (reason) *reason = FF_GetMsg_Cpy(MSG_INCOMPATIBLE_GUF_FILE_ID);
  903.                                         PIUNLOCKHANDLE(h);
  904.                                         PIDISPOSEHANDLE(h);
  905.                                         FSClose(refnum);
  906.                                         return false;
  907.                                 }
  908.                         }
  909.                         else {
  910.                                 if (reason) *reason = FF_GetMsg_Cpy(MSG_INCOMPATIBLE_GUF_FILE_ID);
  911.                                 PIUNLOCKHANDLE(h);
  912.                                 PIDISPOSEHANDLE(h);
  913.                                 FSClose(refnum);
  914.                                 return false;
  915.                         }
  916.                         if (_gufReadProperty(q, count, "Info", "Title", out, sizeof(out))) {
  917.                                 int i;
  918.                                 char tmp[256];
  919.                                 char* tmp2;
  920.  
  921.                                 // Plugin infos
  922.                                 _gufReadProperty(q, count, "Info", "Title", gdata->parm.szTitle, sizeof(gdata->parm.szTitle));
  923.                                 _gufReadProperty(q, count, "Info", "Category", tmp, sizeof(tmp));
  924.                                 tmp2 = strrchr(tmp, '/');
  925.                                 if (tmp2 == NULL) {
  926.                                         strcpy(gdata->parm.szCategory, tmp);
  927.                                 } else {
  928.                                         strcpy(gdata->parm.szCategory, tmp2+1);
  929.                                 }
  930.                                 _gufReadProperty(q, count, "Info", "Author", gdata->parm.szAuthor, sizeof(gdata->parm.szAuthor));
  931.                                 _gufReadProperty(q, count, "Info", "Copyright", gdata->parm.szCopyright, sizeof(gdata->parm.szCopyright));
  932.                                 //_gufReadProperty(q, count, "Filter Factory", "8bf", gdata->parm.xxx, sizeof(gdata->parm.xxx));
  933.  
  934.                                 // Expressions
  935.                                 if (!_gufReadProperty(q, count, "Code", "R", gdata->parm.szFormula[0], sizeof(gdata->parm.szFormula[0])))
  936.                                         strcpy(gdata->parm.szFormula[0], "r");
  937.                                 if (!_gufReadProperty(q, count, "Code", "G", gdata->parm.szFormula[1], sizeof(gdata->parm.szFormula[1])))
  938.                                         strcpy(gdata->parm.szFormula[1], "g");
  939.                                 if (!_gufReadProperty(q, count, "Code", "B", gdata->parm.szFormula[2], sizeof(gdata->parm.szFormula[2])))
  940.                                         strcpy(gdata->parm.szFormula[2], "b");
  941.                                 if (!_gufReadProperty(q, count, "Code", "A", gdata->parm.szFormula[3], sizeof(gdata->parm.szFormula[3])))
  942.                                         strcpy(gdata->parm.szFormula[3], "a");
  943.                                 for (i = 0; i < 4; i++) {
  944.                                         if (expr[i]) free(expr[i]);
  945.                                         expr[i] = my_strdup(gdata->parm.szFormula[i]);
  946.                                 }
  947.  
  948.                                 for (i = 0; i < 8; i++) {
  949.                                         int v;
  950.                                         char keyname[9/*strlen("Control X")*/ + 1/*strlen("\0")*/], tmp[5];
  951.                                         sprintf(keyname, "Control %d", i);
  952.  
  953.                                         // Slider names
  954.                                         _gufReadProperty(q, count, keyname, "Label", gdata->parm.szCtl[i], sizeof(gdata->parm.szCtl[i]));
  955.  
  956.                                         // Slider values
  957.                                         if (!_gufReadProperty(q, count, keyname, "Preset", tmp, sizeof(tmp))) {
  958.                                                 strcpy(tmp, "0");
  959.                                         }
  960.                                         v = atoi(tmp);
  961.                                         if (v < 0) v = 0;
  962.                                         else if (v > 255) v = 255;
  963.                                         gdata->parm.val[i] = slider[i] = (uint8_t)v;
  964.                                 }
  965.  
  966.                                 // Map names
  967.                                 for (i = 0; i < 4; i++) {
  968.                                         char keyname[5/*strlen("Map X")*/ + 1/*strlen("\0")*/];
  969.                                         sprintf(keyname, "Map %d", i);
  970.                                         _gufReadProperty(q, count, keyname, "Label", gdata->parm.szMap[i], sizeof(gdata->parm.szMap[i]));
  971.                                 }
  972.  
  973.                                 //These will be set when the expressions are evaluated anyway. So this part is optional:
  974.                                 checksliders(4, ctls, maps);
  975.                                 for (i = 0; i < 8; i++) gdata->parm.ctl_used[i] = ctls[i];
  976.                                 for (i = 0; i < 4; i++) gdata->parm.map_used[i] = maps[i];
  977.  
  978.                                 res = true;
  979.                         }
  980.  
  981.                         PIUNLOCKHANDLE(h);
  982.                         PIDISPOSEHANDLE(h);
  983.                 }
  984.                 FSClose(refnum);
  985.         }
  986.  
  987.         return res;
  988. }
  989.  
  990. Boolean readfile_afs_pff(StandardFileReply *sfr, TCHAR**reason){
  991.         FILEREF r;
  992.         Handle h;
  993.         Boolean res = false;
  994.  
  995.         if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&r) == noErr){
  996.                 if( (h = readfileintohandle(r)) ){
  997.                         if( (res = readparams_afs_pff(h,reason)) ) {
  998.                                 gdata->standalone = false; // so metadata fields will default, if user chooses Make...
  999.  
  1000.                                 if (fileHasExtension(sfr, TEXT(".pff"))) {
  1001.                                         // If it is a Premiere settings file, we need to swap the channels red and blue
  1002.                                         // We just swap the pointers!
  1003.                                         char* tmp;
  1004.                                         tmp = expr[0];
  1005.                                         expr[0] = expr[2];
  1006.                                         expr[2] = tmp;
  1007.                                 }
  1008.                         }
  1009.  
  1010.                         PIDISPOSEHANDLE(h);
  1011.                 }
  1012.                 FSClose(r);
  1013.         }
  1014.         else
  1015.                 if (reason) *reason = FF_GetMsg_Cpy(MSG_CANNOT_OPEN_FILE_ID);
  1016.  
  1017.         return res;
  1018. }
  1019.