Subversion Repositories filter_foundry

Rev

Rev 388 | Rev 390 | 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_afs_pff(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. 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(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, char** 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.         if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
  206.                 if ((h = readfileintohandle(refnum))) {
  207.                         char* q = (char*)PILOCKHANDLE(h, false);
  208.  
  209.                         len = *((uint32_t*)q);
  210.                         if (len == 6) {
  211.                                 val = _ffx_read_str(&q);
  212.                                 if (strcmp(val, "FFX1.0") == 0) format_version = 10;
  213.                                 else if (strcmp(val, "FFX1.1") == 0) format_version = 11;
  214.                                 else if (strcmp(val, "FFX1.2") == 0) format_version = 12;
  215.                                 free(val);
  216.                                 if (format_version > 0) {
  217.                                         simplewarning(_strdup("Attention! You are loading a \"Filters Unlimited\" file. Please note that Filter Foundry only implements the basic Filter Factory functions. Therefore, most \"Filters Unlimited\" filters won't work with Filter Foundry."));
  218.  
  219.                                         val = _ffx_read_str(&q);
  220.                                         myc2pstrcpy(gdata->parm.title, val);
  221.                                         free(val);
  222.  
  223.                                         val = _ffx_read_str(&q);
  224.                                         myc2pstrcpy(gdata->parm.category, val);
  225.                                         free(val);
  226.  
  227.                                         val = _ffx_read_str(&q);
  228.                                         myc2pstrcpy(gdata->parm.author, val);
  229.                                         free(val);
  230.  
  231.                                         val = _ffx_read_str(&q);
  232.                                         myc2pstrcpy(gdata->parm.copyright, val);
  233.                                         free(val);
  234.  
  235.                                         // Channels I, R, G, B, A
  236.                                         for (i = 0; i < 4; i++) {
  237.                                                 val = _ffx_read_str(&q);
  238.                                                 if (i == 0) {
  239.                                                         char* val2 = _ffx_read_str(&q);
  240.                                                         if (strcmp(val, "0") != 0) {
  241.                                                                 // "Intro channel" existing
  242.                                                                 // C++ wrong warning: Using uninitialized memory "val2" (C6001)
  243.                                                                 #pragma warning(suppress : 6001)
  244.                                                                 char* combined = (char*)malloc(strlen(val) + strlen(",") + strlen(val2) + 1);
  245.                                                                 if (combined != NULL) {
  246.                                                                         sprintf(combined, "%s,%s", val, val2);
  247.                                                                         free(val);
  248.                                                                         free(val2);
  249.                                                                         val = combined;
  250.                                                                 }
  251.                                                         }
  252.                                                         else {
  253.                                                                 free(val);
  254.                                                                 val = val2;
  255.                                                         }
  256.                                                 }
  257.                                                 if (strlen(val) >= sizeof(gdata->parm.formula[i])) {
  258.                                                         if (i == 0) {
  259.                                                                 simplealert(_strdup("Attention! The formula for channel I/R was too long (longer than 1023 characters) and was truncated."));
  260.                                                         }
  261.                                                         else if (i == 1) {
  262.                                                                 simplealert(_strdup("Attention! The formula for channel G was too long (longer than 1023 characters) and was truncated."));
  263.                                                         }
  264.                                                         else if (i == 2) {
  265.                                                                 simplealert(_strdup("Attention! The formula for channel B was too long (longer than 1023 characters) and was truncated."));
  266.                                                         }
  267.                                                         else if (i == 3) {
  268.                                                                 simplealert(_strdup("Attention! The formula for channel A was too long (longer than 1023 characters) and was truncated."));
  269.                                                         }
  270.                                                         // C++ wrong warning: Buffer overflow (C6386)
  271.                                                         #pragma warning(suppress : 6386)
  272.                                                         val[sizeof(gdata->parm.formula[i]) - 1] = '\0';
  273.                                                 }
  274.                                                 expr[i] = my_strdup(val);
  275.                                                 strcpy((char*)gdata->parm.formula[i], val); // Attention! This is not a Pascal string!
  276.                                                 free(val);
  277.                                         }
  278.  
  279.                                         // Sliders
  280.                                         for (i = 0; i < 8; i++) {
  281.                                                 char* sliderName;
  282.                                                 val = _ffx_read_str(&q);
  283.                                                 sliderName = val;
  284.                                                 if (format_version >= 12) {
  285.                                                         // Format FFX1.2 has prefixes {S} = Slider, {C} = Checkbox, none = Slider
  286.                                                         if ((sliderName[0] == '{') && (sliderName[1] == 'S') && (sliderName[2] == '}')) sliderName += 3;
  287.                                                         else if ((sliderName[0] == '{') && (sliderName[1] == 'C') && (sliderName[2] == '}')) sliderName += 3;
  288.                                                 }
  289.                                                 myc2pstrcpy(gdata->parm.ctl[i], sliderName);
  290.                                                 free(val);
  291.                                                 gdata->parm.ctl_used[i] = (bool32_t)*((byte*)q);
  292.                                                 q += sizeof(byte);
  293.                                                 gdata->parm.val[i] = *((uint32_t*)q);
  294.                                                 slider[i] = *((uint32_t*)q);
  295.                                                 q += sizeof(uint32_t);
  296.                                         }
  297.  
  298.                                         res = true;
  299.                                 }
  300.                         }
  301.                         PIDISPOSEHANDLE(h);
  302.                 }
  303.                 FSClose(refnum);
  304.         }
  305.  
  306.         if (res) gdata->obfusc = false;
  307.         return res;
  308. }
  309.  
  310. Boolean readfile_8bf(StandardFileReply *sfr,char **reason){
  311.         unsigned char magic[2];
  312.         FILECOUNT count;
  313.         Handle h;
  314.         Boolean res = false;
  315.         FILEREF refnum;
  316.  
  317.         if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&refnum) == noErr){
  318.                 // check DOS EXE magic number
  319.                 count = 2;
  320.                 if(FSRead(refnum,&count,magic) == noErr /*&& magic[0]=='M' && magic[1]=='Z'*/){
  321.                         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)
  322.                                 if( (h = readfileintohandle(refnum)) ){
  323.                                         long *q = (long*)PILOCKHANDLE(h,false);
  324.  
  325.                                         // look for signature at start of valid PARM resource
  326.                                         // This signature is observed in Filter Factory standalones.
  327.                                         for( count /= 4 ; count >= PARM_SIZE/4 ; --count, ++q )
  328.                                         {
  329.  
  330.                                                 #ifdef MAC_ENV
  331.                                                 // Case #1: Mac is reading Windows (Win16/32/64) plugin
  332.                                                 if( ((EndianS32_LtoN(q[0]) == PARM_SIZE) ||
  333.                                                      (EndianS32_LtoN(q[0]) == PARM_SIZE_PREMIERE) ||
  334.                                                      (EndianS32_LtoN(q[0]) == PARM_SIG_MAC)) && EndianS32_LtoN(q[1]) == 1
  335.                                                         && (res = readPARM((char*)q, &gdata->parm, reason, 1 /*Windows format resource*/)) )
  336.                                                 {
  337.                                                         // these are the only numeric fields we *have* to swap
  338.                                                         // all the rest are flags which (if we're careful) will work in either ordering
  339.                                                         for(i = 0; i < 8; ++i)
  340.                                                                 slider[i] = EndianS32_LtoN(slider[i]);
  341.                                                 }
  342.                                                 #else
  343.                                                 // 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)
  344.                                                 if( ((q[0] == PARM_SIZE) ||
  345.                                                      (q[0] == PARM_SIZE_PREMIERE) ||
  346.                                                      (q[0] == PARM_SIG_MAC)) && q[1] == 1
  347.                                                         && (res = readPARM((char*)q, &gdata->parm, reason, 1/*fromwin*/)))
  348.                                                 {
  349.                                                 }
  350.  
  351.                                                 // Case #3: Windows is reading an old FilterFactory Mac file
  352.                                                 // Note: You must read the ".rsrc" resource fork, not the standalone binary!
  353.                                                 else if( ((EndianS32_LtoN(q[0]) == PARM_SIZE) ||
  354.                                                      (EndianS32_LtoN(q[0]) == PARM_SIZE_PREMIERE) ||
  355.                                                      (EndianS32_LtoN(q[0]) == PARM_SIG_MAC)) && EndianS32_LtoN(q[1]) == 1
  356.                                                         && (res = readPARM((char*)q, &gdata->parm, reason, 0 /*Strings are already PStrings*/)) )
  357.                                                 {
  358.                                                         // Note: slider[i] = EndianS32_LtoN(slider[i]); will be done in readPARM()
  359.                                                         // All the rest are flags which (if we're careful) will work in either ordering
  360.  
  361.                                                         // Convert CR in the copyright field to CRLF.
  362.                                                         int i, j;
  363.                                                         for (i = 1; i < gdata->parm.copyright[0]; i++) {
  364.                                                                 if (gdata->parm.copyright[i] == CR) {
  365.                                                                         for (j = gdata->parm.copyright[0]; j>i; j--) {
  366.                                                                                 gdata->parm.copyright[j+1] = gdata->parm.copyright[j];
  367.                                                                         }
  368.                                                                         gdata->parm.copyright[0]++;
  369.                                                                         gdata->parm.copyright[i+1] = LF;
  370.                                                                 }
  371.                                                         }
  372.                                                 }
  373.                                                 #endif
  374.  
  375.                                                 if (res) break;
  376.                                         }
  377.  
  378.                                         PIDISPOSEHANDLE(h);
  379.                                 }
  380.                         }
  381.                 } // else no point in proceeding
  382.                 FSClose(refnum);
  383.         }else
  384.                 *reason = _strdup("Could not open file.");
  385.  
  386.         if (res) gdata->obfusc = false;
  387.         return res;
  388. }
  389.  
  390. Boolean readPARM(Ptr p,PARM_T *pparm,char **reasonstr,int fromwin){
  391.         int i;
  392.  
  393.         if (*((unsigned int*)p) == PARM_SIZE_PREMIERE) {
  394.                 convert_premiere_to_photoshop(pparm, (PARM_T_PREMIERE*)p);
  395.         } else {
  396.                 // Assume it is Photoshop. Signature either PARM_SIZE (0x2068) or 0x1C68
  397.                 memcpy(pparm,p,sizeof(PARM_T));
  398.         }
  399.  
  400.         if(fromwin){
  401.                 /* Windows PARM resource stores C strings - convert to Pascal strings  */
  402.                 myc2pstr((char*)pparm->category);
  403.                 myc2pstr((char*)pparm->title);
  404.                 myc2pstr((char*)pparm->copyright);
  405.                 myc2pstr((char*)pparm->author);
  406.                 for(i = 0; i < 4; ++i)
  407.                         myc2pstr((char*)pparm->map[i]);
  408.                 for(i = 0; i < 8; ++i)
  409.                         myc2pstr((char*)pparm->ctl[i]);
  410.         }
  411.  
  412.         for(i = 0; i < 4; ++i){
  413.                 if(expr[i]) free(expr[i]);
  414.                 expr[i] = my_strdup((char*)pparm->formula[i]);
  415.         }
  416.  
  417.         for (i = 0; i < 8; ++i) {
  418.                 if (pparm->val[i] > 0xFF) {
  419.                         // Wrong endianess (e.g. reading a Mac rsrc on Windows)
  420.                         slider[i] = (uint8_t)EndianS32_LtoN(pparm->val[i]);
  421.                 }
  422.                 else {
  423.                         slider[i] = (uint8_t)pparm->val[i];
  424.                 }
  425.         }
  426.  
  427.         return true;
  428. }
  429.  
  430. Handle readfileintohandle(FILEREF r){
  431.         FILEPOS n;
  432.         Handle h;
  433.         Ptr p;
  434.  
  435.         if( GetEOF(r,&n) == noErr && (h = PINEWHANDLE(n)) ){
  436.                 p = PILOCKHANDLE(h,false);
  437.                 if(SetFPos(r,fsFromStart,0) == noErr && FSRead(r,(FILECOUNT*)&n,p) == noErr){
  438.                         PIUNLOCKHANDLE(h);
  439.                         return h;
  440.                 }
  441.                 PIDISPOSEHANDLE(h);
  442.         }
  443.         return NULL;
  444. }
  445.  
  446. Boolean _picoLineContainsKey(char* line, char** content, const char* searchkey/*=NULL*/) {
  447.         size_t i;
  448.         for (i = 0; i < strlen(line); i++) {
  449.                 if (line[i] == '?') break; // avoid that "a?b:c" is detected as key
  450.                 if (line[i] == ':') {
  451.                         // Note: We are ignoring whitespaces, i.e. " A :" != "A:" (TODO: should we change this?)
  452.                         if ((searchkey == NULL) || ((i == strlen(searchkey)) && (memcmp(line, searchkey, i) == 0))) {
  453.                                 i++; // jump over ':' char
  454.                                 //while ((line[i] == ' ') || (line[i] == TAB)) i++; // Trim value left
  455.                                 *content = line + i;
  456.                                 return true;
  457.                         }
  458.                 }
  459.         }
  460.         *content = line;
  461.         return false;
  462. }
  463.  
  464. void _ffdcomp_removebrackets(char* x, char* maxptr) {
  465.         char* closingBracketPos = NULL;
  466.         Boolean openingBracketFound = false;
  467.         if (x[0] == '[') {
  468.                 openingBracketFound = true;
  469.         }
  470.         x[0] = ':';
  471.         x++;
  472.         while (x < maxptr) {
  473.                 if ((!openingBracketFound) && (x[0] == '[')) {
  474.                         openingBracketFound = true;
  475.                         x[0] = ' ';
  476.                 }
  477.                 else if (openingBracketFound) {
  478.                         if (x[0] == ']') {
  479.                                 closingBracketPos = x;
  480.                         }
  481.                         else if ((x[0] == CR) || (x[0] == LF)) {
  482.                                 if (closingBracketPos) closingBracketPos[0] = ' '; // last closing pos before CR/LF
  483.                                 break;
  484.                         }
  485.                 }
  486.                 x++;
  487.         }
  488. }
  489.  
  490. // isFormula=false => outputFile is Pascal string. TXT linebreaks become spaces.
  491. // isFormula=true  => outputFile is C string. TXT line breaks become CRLF line breaks
  492. Boolean _picoReadProperty(char* inputFile, int maxInput, const char* property, char* outputFile, size_t maxOutput, Boolean isFormula) {
  493.         int i;
  494.         char* outputwork;
  495.         char* sline;
  496.         char* svalue;
  497.         char* inputwork;
  498.         char* inputworkinitial;
  499.         outputwork = outputFile;
  500.         sline = NULL;
  501.         svalue = NULL;
  502.         // Check parameters
  503.         if (maxOutput == 0) return false;
  504.         if (inputFile == 0) return false;
  505.         // Let input memory be read-only, +1 for terminal zero
  506.         //char* inputwork = inputFile;
  507.         inputwork = (char*)malloc(maxInput + 1);
  508.         inputworkinitial = inputwork;
  509.         if (inputwork == 0) return false;
  510.         memcpy(inputwork, inputFile, maxInput);
  511.         inputwork[maxInput] = 0; // otherwise strstr() will crash
  512.  
  513.         // Transform "FFDecomp" TXT file into the similar "PluginCommander" TXT file
  514.         if (strstr(inputwork, "Filter Factory Plugin Information:")) {
  515.                 char* x;
  516.                 char* k1;
  517.                 char* k2;
  518.                 // Metadata:
  519.                 x = strstr(inputwork, "CATEGORY:");
  520.                 if (x) memcpy(x, "Category:", strlen("Category:"));
  521.                 x = strstr(inputwork, "TITLE:");
  522.                 if (x) memcpy(x, "Title:", strlen("Title:"));
  523.                 x = strstr(inputwork, "COPYRIGHT:");
  524.                 if (x) memcpy(x, "Copyright:", strlen("Copyright:"));
  525.                 x = strstr(inputwork, "AUTHOR:");
  526.                 if (x) memcpy(x, "Author:", strlen("Author:"));
  527.                 // Controls:
  528.                 for (i = 0; i < 8; i++) {
  529.                         k1 = (char*)malloc(strlen("Control X:") + 1);
  530.                         sprintf(k1, "Control %d:", i);
  531.                         x = strstr(inputwork, k1);
  532.                         if (x) {
  533.                                 k2 = (char*)malloc(strlen("ctl[X]:   ") + 1);
  534.                                 sprintf(k2, "ctl[%d]:   ", i);
  535.                                 memcpy(x, k2, strlen(k2));
  536.                                 x += strlen("ctl[X]");
  537.                                 _ffdcomp_removebrackets(x, inputwork + maxInput - 1);
  538.                                 free(k2);
  539.                         }
  540.                         free(k1);
  541.                 }
  542.                 // Maps:
  543.                 for (i = 0; i < 4; i++) {
  544.                         k1 = (char*)malloc(strlen("Map X:") + 1);
  545.                         sprintf(k1, "Map %d:", i);
  546.                         x = strstr(inputwork, k1);
  547.                         if (x) {
  548.                                 k2 = (char*)malloc(strlen("map[X]:") + 1);
  549.                                 sprintf(k2, "map[%d]:", i);
  550.                                 memcpy(x, k2, strlen(k2));
  551.                                 x += strlen("map[X]");
  552.                                 _ffdcomp_removebrackets(x, inputwork + maxInput - 1);
  553.                                 free(k2);
  554.                         }
  555.                         free(k1);
  556.                 }
  557.                 // Convert all '\r' to '\n' for the next step to be easier
  558.                 for (i = 0; i < maxInput; i++) {
  559.                         if (inputworkinitial[i] == CR) inputworkinitial[i] = LF;
  560.                 }
  561.                 x = strstr(inputwork, "\nR=\n");
  562.                 if (x) memcpy(x, "\nR:\n", strlen("\nR:\n"));
  563.                 x = strstr(inputwork, "\nG=\n");
  564.                 if (x) memcpy(x, "\nG:\n", strlen("\nG:\n"));
  565.                 x = strstr(inputwork, "\nB=\n");
  566.                 if (x) memcpy(x, "\nB:\n", strlen("\nB:\n"));
  567.                 x = strstr(inputwork, "\nA=\n");
  568.                 if (x) memcpy(x, "\nA:\n", strlen("\nA:\n"));
  569.         }
  570.         // Replace all \r and \n with \0, so that we can parse easier
  571.         for (i = 0; i < maxInput; i++) {
  572.                 if (inputworkinitial[i] == 0) break;
  573.                 if (inputworkinitial[i] == CR) inputworkinitial[i] = 0;
  574.                 if (inputworkinitial[i] == LF) inputworkinitial[i] = 0;
  575.         }
  576.  
  577.         // Find line that contains out key
  578.         inputwork = inputworkinitial;
  579.         do {
  580.                 if (inputwork > inputworkinitial + maxInput) {
  581.                         // Key not found. Set output to empty string
  582.                         outputwork[0] = 0;
  583.                         free(inputworkinitial);
  584.                         if (!isFormula) myc2pstr(outputFile);
  585.                         return false;
  586.                 }
  587.                 sline = inputwork;
  588.                 inputwork += strlen(sline) + 1;
  589.                 if (inputwork - 1 > inputworkinitial + maxInput) {
  590.                         // Key not found. Set output to empty string
  591.                         // TODO: will that be ever called?
  592.                         outputwork[0] = 0;
  593.                         free(inputworkinitial);
  594.                         if (!isFormula) myc2pstr(outputFile);
  595.                         return false;
  596.                 }
  597.         } while (!_picoLineContainsKey(sline, &svalue, property));
  598.  
  599.         // Read line(s) until we find a line with another key, or the line end
  600.         do {
  601.                 while ((svalue[0] == ' ') || (svalue[0] == TAB)) svalue++; // Trim left
  602.                 while ((svalue[strlen(svalue) - 1] == ' ') || (svalue[strlen(svalue) - 1] == TAB)) svalue[strlen(svalue) - 1] = 0; // Trim right
  603.  
  604.                 if (strlen(svalue) > 0) {
  605.                         if (outputwork + strlen(svalue) + (isFormula ? 3 : 2) > outputFile + maxOutput) {
  606.                                 int remaining = maxOutput - (outputwork - outputFile) - 1;
  607.                                 //printf("BUFFER FULL (remaining = %d)\n", remaining);
  608.                                 memcpy(outputwork, svalue, remaining);
  609.                                 outputwork += remaining;
  610.                                 outputwork[0] = 0;
  611.                                 free(inputworkinitial);
  612.                                 if (!isFormula) myc2pstr(outputFile);
  613.                                 return true;
  614.                         }
  615.                         else {
  616.                                 memcpy(outputwork, svalue, strlen(svalue));
  617.                                 outputwork += strlen(svalue);
  618.                                 if (isFormula) {
  619.                                         // Formulas: TXT line break stays line break (important if you have comments!)
  620.                                         outputwork[0] = CR;
  621.                                         outputwork[1] = LF;
  622.                                         outputwork += 2;
  623.                                 }
  624.                                 else {
  625.                                         // Everything else: TXT line breaks becomes single whitespace
  626.                                         outputwork[0] = ' ';
  627.                                         outputwork++;
  628.                                 }
  629.                         }
  630.                 }
  631.                 outputwork[0] = 0;
  632.  
  633.                 // Process next line
  634.                 if (inputwork > inputworkinitial + maxInput) break;
  635.                 sline = inputwork;
  636.                 inputwork += strlen(sline) + 1;
  637.                 if (inputwork - 1 > inputworkinitial + maxInput) break; // TODO: will that be ever called?
  638.         } while (!_picoLineContainsKey(sline, &svalue, NULL));
  639.  
  640.         // Remove trailing whitespace
  641.         if (outputwork > outputFile) {
  642.                 outputwork -= 1;
  643.                 outputwork[0] = 0;
  644.         }
  645.         free(inputworkinitial);
  646.         if (!isFormula) myc2pstr(outputFile);
  647.         return true;
  648. }
  649.  
  650. Boolean readfile_picotxt(StandardFileReply* sfr, char** reason) {
  651.         extern int ctls[], maps[];
  652.  
  653.         Handle h;
  654.         Boolean res = false;
  655.         FILEREF refnum;
  656.  
  657.         if (!fileHasExtension(sfr, ".txt")) return false;
  658.  
  659.         if (FSpOpenDF(&sfr->sfFile, fsRdPerm, &refnum) == noErr) {
  660.                 if ((h = readfileintohandle(refnum))) {
  661.                         FILECOUNT count = PIGETHANDLESIZE(h);
  662.                         char* q = PILOCKHANDLE(h, false);
  663.  
  664.                         char out[256];
  665.                         if (_picoReadProperty(q, count, "Title", out, sizeof(out), false)) {
  666.                                 int i;
  667.  
  668.                                 // Plugin infos
  669.                                 _picoReadProperty(q, count, "Title", (char*)gdata->parm.title, sizeof(gdata->parm.title)-1, false);
  670.                                 _picoReadProperty(q, count, "Category", (char*)gdata->parm.category, sizeof(gdata->parm.category)-1, false);
  671.                                 _picoReadProperty(q, count, "Author", (char*)gdata->parm.author, sizeof(gdata->parm.author)-1, false);
  672.                                 _picoReadProperty(q, count, "Copyright", (char*)gdata->parm.copyright, sizeof(gdata->parm.copyright)-1, false);
  673.                                 //_picoReadProperty(q, count, "Filename", (char*)gdata->parm.xxx, sizeof(gdata->parm.xxx), false);
  674.  
  675.                                 // Expressions
  676.                                 if (!_picoReadProperty(q, count, "R", (char*)gdata->parm.formula[0], sizeof(gdata->parm.formula[0]), true))
  677.                                         strcpy((char*)gdata->parm.formula[0], "r");
  678.                                 if (!_picoReadProperty(q, count, "G", (char*)gdata->parm.formula[1], sizeof(gdata->parm.formula[1]), true))
  679.                                         strcpy((char*)gdata->parm.formula[1], "g");
  680.                                 if (!_picoReadProperty(q, count, "B", (char*)gdata->parm.formula[2], sizeof(gdata->parm.formula[2]), true))
  681.                                         strcpy((char*)gdata->parm.formula[2], "b");
  682.                                 if (!_picoReadProperty(q, count, "A", (char*)gdata->parm.formula[3], sizeof(gdata->parm.formula[3]), true))
  683.                                         strcpy((char*)gdata->parm.formula[3], "a");
  684.                                 for (i = 0; i < 4; i++) {
  685.                                         if (expr[i]) free(expr[i]);
  686.                                         expr[i] = my_strdup((char*)gdata->parm.formula[i]);
  687.                                 }
  688.  
  689.                                 // Slider names
  690.                                 for (i = 0; i < 8; i++) {
  691.                                         char keyname[7];
  692.                                         sprintf(keyname, "ctl[%d]", i);
  693.                                         _picoReadProperty(q, count, keyname, (char*)gdata->parm.ctl[i], sizeof(gdata->parm.ctl[i]), false);
  694.                                 }
  695.  
  696.                                 // Slider values
  697.                                 for (i = 0; i < 8; i++) {
  698.                                         char keyname[7], tmp[5];
  699.                                         sprintf(keyname, "val[%d]", i);
  700.                                         if (!_picoReadProperty(q, count, keyname, tmp, sizeof(tmp), false)) {
  701.                                                 sprintf(keyname, "def[%d]", i);
  702.                                                 if (!_picoReadProperty(q, count, keyname, tmp, sizeof(tmp), false)) {
  703.                                                         tmp[0] = 1;
  704.                                                         tmp[1] = '0';
  705.                                                         tmp[2] = 0;
  706.                                                 }
  707.                                         }
  708.                                         myp2cstr((unsigned char*)tmp);
  709.                                         gdata->parm.val[i] = slider[i] = atoi(tmp);
  710.                                 }
  711.  
  712.                                 // Map names
  713.                                 for (i = 0; i < 4; i++) {
  714.                                         char keyname[7];
  715.                                         sprintf(keyname, "map[%d]", i);
  716.                                         _picoReadProperty(q, count, keyname, (char*)gdata->parm.map[i], sizeof(gdata->parm.map[i]), false);
  717.                                 }
  718.  
  719.                                 //These will be set when the expressions are evaluated anyway. So this part is optional:
  720.                                 checksliders(4, ctls, maps);
  721.                                 for (i = 0; i < 8; i++) gdata->parm.ctl_used[i] = ctls[i];
  722.                                 for (i = 0; i < 4; i++) gdata->parm.map_used[i] = maps[i];
  723.  
  724.                                 res = true;
  725.                         }
  726.  
  727.                         PIUNLOCKHANDLE(h);
  728.                         PIDISPOSEHANDLE(h);
  729.                 }
  730.                 FSClose(refnum);
  731.         }
  732.  
  733.         return res;
  734. }
  735.  
  736. Boolean readfile_afs_pff(StandardFileReply *sfr,char **reason){
  737.         FILEREF r;
  738.         Handle h;
  739.         Boolean res = false;
  740.  
  741.         if(FSpOpenDF(&sfr->sfFile,fsRdPerm,&r) == noErr){
  742.                 if( (h = readfileintohandle(r)) ){
  743.                         if( (res = readparams_afs_pff(h,true,reason)) ) {
  744.                                 gdata->standalone = false; // so metadata fields will default, if user chooses Make...
  745.  
  746.                                 if (fileHasExtension(sfr, ".pff")) {
  747.                                         // If it is a Premiere settings file, we need to swap the channels red and blue
  748.                                         // We just swap the pointers!
  749.                                         char* tmp;
  750.                                         tmp = expr[0];
  751.                                         expr[0] = expr[2];
  752.                                         expr[2] = tmp;
  753.                                 }
  754.                         }
  755.  
  756.                         PIDISPOSEHANDLE(h);
  757.                 }
  758.                 FSClose(r);
  759.         }else
  760.                 *reason = _strdup("Could not open the file.");
  761.  
  762.         return res;
  763. }
  764.