Subversion Repositories filter_foundry

Rev

Rev 555 | 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 "version.h"
  24. #include "time.h"
  25. #include "file_compat.h"
  26. #include "sprintf_tiny.h"
  27.  
  28. #define CHOPLINES 63
  29.  
  30. OSErr putstr(Handle h,char *s);
  31.  
  32. OSErr putstr(Handle h,char *s){
  33.         Ptr p;
  34.         OSErr e;
  35.         size_t size, n;
  36.  
  37.         if (!h) return nilHandleErr;
  38.  
  39.         size = PIGETHANDLESIZE(h);
  40.         n = strlen(s);
  41.  
  42.         if(!(e = PISETHANDLESIZE(h,(int32)(size+n)))){
  43.                 p = PILOCKHANDLE(h,false);
  44.                 memcpy(p+size,s,n);
  45.                 PIUNLOCKHANDLE(h);
  46.         }
  47.         return e;
  48. }
  49.  
  50. OSErr saveparams_afs_pff(Handle h, Boolean premiereOrder){
  51.         char outbuf[CHOPLINES * 2 + 2] = "";
  52.         char *q, * p, * r, * start;
  53.         size_t n, chunk, j;
  54.         int i, k;
  55.         OSErr e;
  56.         size_t est;
  57.         static char afs_sig[] = "%RGB-1.0\r";
  58.  
  59.         if (!h) return nilHandleErr;
  60.  
  61.         est = strlen(gdata->parm.szFormula[0]) + strlen(gdata->parm.szFormula[1]) + strlen(gdata->parm.szFormula[2]) + strlen(gdata->parm.szFormula[3]);
  62.         // do not be tempted to combine into one expression: 'est' is referenced below
  63.         est += strlen(afs_sig) + est/CHOPLINES + 4 + 8*6 + 64 /*slop*/ ;
  64.  
  65.         PIUNLOCKHANDLE(h); // should not be necessary
  66.         if( !(e = PISETHANDLESIZE(h,(int32)(est))) && (p = start = PILOCKHANDLE(h,false)) ){
  67.                 // build one long string in AFS format
  68.                 p = cat(p,afs_sig); // first the header signature
  69.  
  70.                 /* then slider values, one per line */
  71.                 for( i=0 ; i<8 ; ++i )
  72.                         p += sprintf(p, "%d\r", gdata->parm.val[i]);
  73.  
  74.                 /* expressions, broken into lines no longer than CHOPLINES characters */
  75.                 for( k=0 ; k<4 ; ++k ){
  76.                         i = k;
  77.                         if (premiereOrder) {
  78.                                 // Premiere has the order BGRA, while Photoshop (and our internal order) is RGBA
  79.                                 if (k == 0) i = 2;
  80.                                 else if (k == 2) i = 0;
  81.                         }
  82.                         if ((r = gdata->parm.szFormula[i])) {
  83.                                 chunk = 0; // to avoid that compiler complains
  84.                                 for (n = strlen(r); n; n -= chunk) {
  85.                                         chunk = n > (int)CHOPLINES ? (int)CHOPLINES : n;
  86.                                         for (j = chunk, q = outbuf; j--; )
  87.                                                 if (*r == CR) {
  88.                                                         *q++ = '\\';
  89.                                                         *q++ = 'r';
  90.                                                         ++r;
  91.                                                 }
  92.                                                 else if (*r == LF) {
  93.  
  94.                                                         // This can only happen with Windows or Linux.
  95.                                                         // Native Linux is not supported, and Windows always combines LF with CR. So we can ignore LF.
  96.                                                         ++r;
  97.                                                 }
  98.                                                 else
  99.                                                         *q++ = *r++;
  100.                                         *q++ = CR;
  101.                                         *q = 0;
  102.                                         p = cat(p, outbuf);
  103.                                 }
  104.                         }
  105.                         else
  106.                                 p = cat(p,(char*)("(null expr)\r")); // this shouldn't happen
  107.                         *p++ = CR;
  108.                 }
  109.  
  110. //              *p = 0; dbg(start);
  111.  
  112.                 PIUNLOCKHANDLE(h);
  113.                 e = PISETHANDLESIZE(h,(int32)(p - start)); // could ignore this error, maybe
  114.         }
  115.  
  116.         return e;
  117. }
  118.  
  119. OSErr saveparams_picotxt(Handle h) {
  120.         char * p, *start;
  121.         int i;
  122.         OSErr e;
  123.         size_t est;
  124.  
  125.         if (!h) return nilHandleErr;
  126.  
  127.         est = strlen(gdata->parm.szFormula[0]) + strlen(gdata->parm.szFormula[1]) + strlen(gdata->parm.szFormula[2]) + strlen(gdata->parm.szFormula[3]);
  128.         // do not be tempted to combine into one expression: 'est' is referenced below
  129.         est += 16000;
  130.  
  131.         PIUNLOCKHANDLE(h); // should not be necessary
  132.         if (!(e = PISETHANDLESIZE(h, (int32)(est))) && (p = start = PILOCKHANDLE(h, false))) {
  133.                 checksliders(4);
  134.  
  135.                 // Metadata
  136.                 p += sprintf(p, "Category: %s\r\n", gdata->parm.szCategory);
  137.                 p += sprintf(p, "Title: %s\r\n", gdata->parm.szTitle);
  138.                 p += sprintf(p, "Copyright: %s\r\n", gdata->parm.szCopyright);
  139.                 p += sprintf(p, "Author: %s\r\n", gdata->parm.szAuthor);
  140.                 p += sprintf(p, "Filename: %s\r\n", "Untitled.8bf"); // TODO: get .txt filename and change .txt to .8bf
  141.                 p += sprintf(p, "\r\n");
  142.                 p += sprintf(p, "R: %s\r\n", gdata->parm.szFormula[0]);
  143.                 p += sprintf(p, "\r\n");
  144.                 p += sprintf(p, "G: %s\r\n", gdata->parm.szFormula[1]);
  145.                 p += sprintf(p, "\r\n");
  146.                 p += sprintf(p, "B: %s\r\n", gdata->parm.szFormula[2]);
  147.                 p += sprintf(p, "\r\n");
  148.                 p += sprintf(p, "A: %s\r\n", gdata->parm.szFormula[3]);
  149.                 p += sprintf(p, "\r\n");
  150.                 for (i = 0; i < 8; i++) {
  151.                         if (gdata->parm.ctl_used[i]) {
  152.                                 p += sprintf(p, "ctl[%d]: %s\r\n", i, gdata->parm.szCtl[i]);
  153.                         }
  154.                 }
  155.                 for (i = 0; i < 4; i++) {
  156.                         if (gdata->parm.map_used[i]) {
  157.                                 p += sprintf(p, "map[%d]: %s\r\n", i, gdata->parm.szMap[i]);
  158.                         }
  159.                 }
  160.                 p += sprintf(p, "\r\n");
  161.                 for (i = 0; i < 8; i++) {
  162.                         if (gdata->parm.ctl_used[i]) {
  163.                                 p += sprintf(p, "val[%d]: %d\r\n", i, gdata->parm.val[i]);
  164.                         }
  165.                 }
  166.                 /*
  167.                 p += sprintf(p, "\r\n");
  168.                 for (i = 0; i < 8; i++) {
  169.                         if (gdata->parm.ctl_used[i]) {
  170.                                 p += sprintf(p, "def[%d]: %d\r\n", i, gdata->parm.val[i]);
  171.                         }
  172.                 }
  173.                 */
  174.  
  175.                 PIUNLOCKHANDLE(h);
  176.                 e = PISETHANDLESIZE(h, (int32)(p - start)); // could ignore this error, maybe
  177.         }
  178.  
  179.         return e;
  180. }
  181.  
  182. OSErr saveparams_guf(Handle h) {
  183.         char* p, * start;
  184.         int i;
  185.         OSErr e;
  186.         size_t est;
  187.  
  188.         if (!h) return nilHandleErr;
  189.  
  190.         est = strlen(gdata->parm.szFormula[0]) + strlen(gdata->parm.szFormula[1]) + strlen(gdata->parm.szFormula[2]) + strlen(gdata->parm.szFormula[3]);
  191.         // do not be tempted to combine into one expression: 'est' is referenced below
  192.         est += 16000;
  193.  
  194.         // TODO: Encode the file in UTF-8! (German Umlauts, etc.)
  195.  
  196.         PIUNLOCKHANDLE(h); // should not be necessary
  197.         if (!(e = PISETHANDLESIZE(h, (int32)(est))) && (p = start = PILOCKHANDLE(h, false))) {
  198.                 char strBuildDate[11/*strlen("0000-00-00") + 1*/];
  199.                 time_t iBuildDate = time(0);
  200.                 strftime(strBuildDate, 11, "%Y-%m-%d", localtime(&iBuildDate));
  201.  
  202.                 checksliders(4);
  203.  
  204.                 // Metadata
  205.                 p += sprintf(p, "# Created with Filter Foundry %s\r\n", VERSION_STR);
  206.                 p += sprintf(p, "\r\n");
  207.                 p += sprintf(p, "[GUF]\r\n");
  208.                 p += sprintf(p, "Protocol=1\r\n");
  209.                 p += sprintf(p, "\r\n");
  210.                 p += sprintf(p, "[Info]\r\n");
  211.                 p += sprintf(p, "Category=<Image>/Filter Factory/%s\r\n", gdata->parm.szCategory);
  212.                 p += sprintf(p, "Title=%s\r\n", gdata->parm.szTitle);
  213.                 p += sprintf(p, "Copyright=%s\r\n", gdata->parm.szCopyright);
  214.                 p += sprintf(p, "Author=%s\r\n", gdata->parm.szAuthor);
  215.                 p += sprintf(p, "\r\n");
  216.                 p += sprintf(p, "[Version]\r\n");
  217.                 p += sprintf(p, "Major=1\r\n");
  218.                 p += sprintf(p, "Minor=0\r\n");
  219.                 p += sprintf(p, "Micro=0\r\n");
  220.                 p += sprintf(p, "\r\n");
  221.                 p += sprintf(p, "[Filter Factory]\r\n");
  222.                 p += sprintf(p, "8bf=%s\r\n", "Untitled.8bf"); // TODO: get .guf filename and change .guf to .8bf
  223.                 p += sprintf(p, "\r\n");
  224.                 p += sprintf(p, "[Gimp]\r\n");
  225.                 p += sprintf(p, "Registered=false\r\n");
  226.                 p += sprintf(p, "Description=%s\r\n", gdata->parm.szTitle);
  227.                 p += sprintf(p, "EdgeMode=2\r\n");
  228.                 p += sprintf(p, "Date=%s\r\n", strBuildDate);
  229.                 p += sprintf(p, "\r\n");
  230.  
  231.                 for (i = 0; i < 8; i++) {
  232.                         p += sprintf(p, "[Control %d]\r\n", i);
  233.                         p += sprintf(p, "Enabled=%s\r\n", gdata->parm.ctl_used[i] ? "true" : "false");
  234.                         p += sprintf(p, "Label=%s\r\n", gdata->parm.szCtl[i]);
  235.                         p += sprintf(p, "Preset=%d\r\n", gdata->parm.val[i]);
  236.                         p += sprintf(p, "Step=1\r\n");
  237.                         p += sprintf(p, "\r\n");
  238.                 }
  239.                 for (i = 0; i < 4; i++) {
  240.                         p += sprintf(p, "[Map %d]\r\n", i);
  241.                         p += sprintf(p, "Enabled=%s\r\n", gdata->parm.map_used[i] ? "true" : "false");
  242.                         p += sprintf(p, "Label=%s\r\n", gdata->parm.szMap[i]);
  243.                         p += sprintf(p, "\r\n");
  244.                 }
  245.        
  246.                 p += sprintf(p, "[Code]\r\n");
  247.                 p += sprintf(p, "R=%s\r\n", gdata->parm.szFormula[0]);
  248.                 p += sprintf(p, "G=%s\r\n", gdata->parm.szFormula[1]);
  249.                 p += sprintf(p, "B=%s\r\n", gdata->parm.szFormula[2]);
  250.                 p += sprintf(p, "A=%s\r\n", gdata->parm.szFormula[3]);
  251.  
  252.                 PIUNLOCKHANDLE(h);
  253.                 e = PISETHANDLESIZE(h, (int32)(p - start)); // could ignore this error, maybe
  254.         }
  255.  
  256.         return e;
  257. }
  258.  
  259. OSErr savehandleintofile(Handle h,FILEREF r){
  260.         Ptr p;
  261.         FILECOUNT n;
  262.         OSErr e;
  263.  
  264.         if (!h) return nilHandleErr;
  265.         p = PILOCKHANDLE(h,false);
  266.         n = (FILECOUNT)PIGETHANDLESIZE(h);
  267.         e = FSWrite(r,&n,p);
  268.         PIUNLOCKHANDLE(h);
  269.         return e;
  270. }
  271.  
  272. FFSavingResult savefile_afs_pff_picotxt_guf(StandardFileReply *sfr){
  273.         FILEREF r;
  274.         Handle h;
  275.         Boolean bres = false;
  276.         FFSavingResult res = SAVING_OK;
  277.  
  278.         FSpDelete(&sfr->sfFile);
  279.         if (FSpCreate(&sfr->sfFile, SIG_SIMPLETEXT, TEXT_FILETYPE, sfr->sfScript) == noErr) {
  280.                 if (FSpOpenDF(&sfr->sfFile, fsWrPerm, &r) == noErr) {
  281.  
  282.                         if (fileHasExtension(sfr, TEXT(".txt"))) {
  283.                                 // PluginCommander .txt
  284.                                 if ((h = PINEWHANDLE(1))) { // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that.
  285.                                         bres = !(saveparams_picotxt(h) || savehandleintofile(h, r));
  286.                                         if (!bres) res = MSG_ERROR_GENERATING_DATA_ID;
  287.                                         PIDISPOSEHANDLE(h);
  288.                                 }
  289.                                 else res = MSG_OUT_OF_MEMORY_ID;
  290.                         }
  291.                         else if (fileHasExtension(sfr, TEXT(".guf"))) {
  292.                                 // GIMP UserFilter file
  293.                                 if ((h = PINEWHANDLE(1))) { // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that.
  294.                                         bres = !(saveparams_guf(h) || savehandleintofile(h, r));
  295.                                         if (!bres) res = MSG_ERROR_GENERATING_DATA_ID;
  296.                                         PIDISPOSEHANDLE(h);
  297.                                 }
  298.                                 else res = MSG_OUT_OF_MEMORY_ID;
  299.                         }
  300.                         else if ((fileHasExtension(sfr, TEXT(".afs"))) || (fileHasExtension(sfr, TEXT(".pff")))) {
  301.                                 if ((h = PINEWHANDLE(1))) { // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that.
  302.                                         bres = !(saveparams_afs_pff(h, fileHasExtension(sfr, TEXT(".pff"))) || savehandleintofile(h, r));
  303.                                         if (!bres) res = MSG_ERROR_GENERATING_DATA_ID;
  304.                                         PIDISPOSEHANDLE(h);
  305.                                 }
  306.                                 else res = MSG_OUT_OF_MEMORY_ID;
  307.                         }
  308.                         else {
  309.                                 res = MSG_UNSUPPORTED_FILE_FORMAT_ID;
  310.                         }
  311.  
  312.                         FSClose(r);
  313.                 }
  314.                 else res = MSG_CANNOT_OPEN_FILE_ID;
  315.         }
  316.         else res = MSG_CANNOT_CREATE_FILE_ID;
  317.  
  318.         return res;
  319. }
  320.