Rev 555 | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
259 | daniel-mar | 1 | /* |
2 | This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop |
||
536 | daniel-mar | 3 | Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.net |
541 | daniel-mar | 4 | Copyright (C) 2018-2023 Daniel Marschall, ViaThinkSoft |
259 | daniel-mar | 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 | |||
539 | daniel-mar | 23 | #include "version.h" |
24 | #include "time.h" |
||
259 | daniel-mar | 25 | #include "file_compat.h" |
26 | #include "sprintf_tiny.h" |
||
27 | |||
518 | daniel-mar | 28 | #define CHOPLINES 63 |
259 | daniel-mar | 29 | |
30 | OSErr putstr(Handle h,char *s); |
||
31 | |||
32 | OSErr putstr(Handle h,char *s){ |
||
33 | Ptr p; |
||
34 | OSErr e; |
||
482 | daniel-mar | 35 | size_t size, n; |
259 | daniel-mar | 36 | |
482 | daniel-mar | 37 | if (!h) return nilHandleErr; |
38 | |||
39 | size = PIGETHANDLESIZE(h); |
||
40 | n = strlen(s); |
||
41 | |||
259 | daniel-mar | 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 | |||
555 | daniel-mar | 50 | OSErr saveparams_afs_pff(Handle h, Boolean premiereOrder){ |
505 | daniel-mar | 51 | char outbuf[CHOPLINES * 2 + 2] = ""; |
52 | char *q, * p, * r, * start; |
||
259 | daniel-mar | 53 | size_t n, chunk, j; |
555 | daniel-mar | 54 | int i, k; |
259 | daniel-mar | 55 | OSErr e; |
56 | size_t est; |
||
57 | static char afs_sig[] = "%RGB-1.0\r"; |
||
58 | |||
482 | daniel-mar | 59 | if (!h) return nilHandleErr; |
259 | daniel-mar | 60 | |
550 | daniel-mar | 61 | est = strlen(gdata->parm.szFormula[0]) + strlen(gdata->parm.szFormula[1]) + strlen(gdata->parm.szFormula[2]) + strlen(gdata->parm.szFormula[3]); |
259 | daniel-mar | 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 ) |
||
550 | daniel-mar | 72 | p += sprintf(p, "%d\r", gdata->parm.val[i]); |
259 | daniel-mar | 73 | |
74 | /* expressions, broken into lines no longer than CHOPLINES characters */ |
||
555 | daniel-mar | 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 | } |
||
550 | daniel-mar | 82 | if ((r = gdata->parm.szFormula[i])) { |
505 | daniel-mar | 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) { |
||
259 | daniel-mar | 88 | *q++ = '\\'; |
89 | *q++ = 'r'; |
||
90 | ++r; |
||
505 | daniel-mar | 91 | } |
92 | else if (*r == LF) { |
||
393 | daniel-mar | 93 | |
259 | daniel-mar | 94 | // This can only happen with Windows or Linux. |
369 | daniel-mar | 95 | // Native Linux is not supported, and Windows always combines LF with CR. So we can ignore LF. |
259 | daniel-mar | 96 | ++r; |
505 | daniel-mar | 97 | } |
98 | else |
||
259 | daniel-mar | 99 | *q++ = *r++; |
387 | daniel-mar | 100 | *q++ = CR; |
259 | daniel-mar | 101 | *q = 0; |
505 | daniel-mar | 102 | p = cat(p, outbuf); |
259 | daniel-mar | 103 | } |
505 | daniel-mar | 104 | } |
259 | daniel-mar | 105 | else |
498 | daniel-mar | 106 | p = cat(p,(char*)("(null expr)\r")); // this shouldn't happen |
387 | daniel-mar | 107 | *p++ = CR; |
259 | daniel-mar | 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 | |||
550 | daniel-mar | 119 | OSErr saveparams_picotxt(Handle h) { |
389 | daniel-mar | 120 | char * p, *start; |
121 | int i; |
||
122 | OSErr e; |
||
123 | size_t est; |
||
124 | |||
482 | daniel-mar | 125 | if (!h) return nilHandleErr; |
389 | daniel-mar | 126 | |
550 | daniel-mar | 127 | est = strlen(gdata->parm.szFormula[0]) + strlen(gdata->parm.szFormula[1]) + strlen(gdata->parm.szFormula[2]) + strlen(gdata->parm.szFormula[3]); |
389 | daniel-mar | 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))) { |
||
550 | daniel-mar | 133 | checksliders(4); |
389 | daniel-mar | 134 | |
135 | // Metadata |
||
550 | daniel-mar | 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 |
||
389 | daniel-mar | 141 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 142 | p += sprintf(p, "R: %s\r\n", gdata->parm.szFormula[0]); |
389 | daniel-mar | 143 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 144 | p += sprintf(p, "G: %s\r\n", gdata->parm.szFormula[1]); |
389 | daniel-mar | 145 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 146 | p += sprintf(p, "B: %s\r\n", gdata->parm.szFormula[2]); |
389 | daniel-mar | 147 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 148 | p += sprintf(p, "A: %s\r\n", gdata->parm.szFormula[3]); |
389 | daniel-mar | 149 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 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]); |
||
389 | daniel-mar | 153 | } |
550 | daniel-mar | 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]); |
||
389 | daniel-mar | 158 | } |
550 | daniel-mar | 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]); |
||
389 | daniel-mar | 164 | } |
165 | } |
||
550 | daniel-mar | 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]); |
||
389 | daniel-mar | 171 | } |
172 | } |
||
550 | daniel-mar | 173 | */ |
389 | daniel-mar | 174 | |
175 | PIUNLOCKHANDLE(h); |
||
176 | e = PISETHANDLESIZE(h, (int32)(p - start)); // could ignore this error, maybe |
||
177 | } |
||
178 | |||
179 | return e; |
||
180 | } |
||
181 | |||
550 | daniel-mar | 182 | OSErr saveparams_guf(Handle h) { |
539 | daniel-mar | 183 | char* p, * start; |
184 | int i; |
||
185 | OSErr e; |
||
186 | size_t est; |
||
187 | |||
188 | if (!h) return nilHandleErr; |
||
189 | |||
550 | daniel-mar | 190 | est = strlen(gdata->parm.szFormula[0]) + strlen(gdata->parm.szFormula[1]) + strlen(gdata->parm.szFormula[2]) + strlen(gdata->parm.szFormula[3]); |
539 | daniel-mar | 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); |
||
541 | daniel-mar | 200 | strftime(strBuildDate, 11, "%Y-%m-%d", localtime(&iBuildDate)); |
539 | daniel-mar | 201 | |
550 | daniel-mar | 202 | checksliders(4); |
539 | daniel-mar | 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"); |
||
550 | daniel-mar | 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); |
||
539 | daniel-mar | 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"); |
||
550 | daniel-mar | 222 | p += sprintf(p, "8bf=%s\r\n", "Untitled.8bf"); // TODO: get .guf filename and change .guf to .8bf |
539 | daniel-mar | 223 | p += sprintf(p, "\r\n"); |
224 | p += sprintf(p, "[Gimp]\r\n"); |
||
225 | p += sprintf(p, "Registered=false\r\n"); |
||
550 | daniel-mar | 226 | p += sprintf(p, "Description=%s\r\n", gdata->parm.szTitle); |
539 | daniel-mar | 227 | p += sprintf(p, "EdgeMode=2\r\n"); |
228 | p += sprintf(p, "Date=%s\r\n", strBuildDate); |
||
229 | p += sprintf(p, "\r\n"); |
||
230 | |||
550 | daniel-mar | 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"); |
||
539 | daniel-mar | 238 | } |
550 | daniel-mar | 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"); |
||
539 | daniel-mar | 244 | } |
245 | |||
246 | p += sprintf(p, "[Code]\r\n"); |
||
550 | daniel-mar | 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]); |
||
539 | daniel-mar | 251 | |
252 | PIUNLOCKHANDLE(h); |
||
253 | e = PISETHANDLESIZE(h, (int32)(p - start)); // could ignore this error, maybe |
||
254 | } |
||
255 | |||
256 | return e; |
||
537 | daniel-mar | 257 | } |
258 | |||
259 | daniel-mar | 259 | OSErr savehandleintofile(Handle h,FILEREF r){ |
482 | daniel-mar | 260 | Ptr p; |
505 | daniel-mar | 261 | FILECOUNT n; |
482 | daniel-mar | 262 | OSErr e; |
263 | |||
264 | if (!h) return nilHandleErr; |
||
265 | p = PILOCKHANDLE(h,false); |
||
505 | daniel-mar | 266 | n = (FILECOUNT)PIGETHANDLESIZE(h); |
482 | daniel-mar | 267 | e = FSWrite(r,&n,p); |
259 | daniel-mar | 268 | PIUNLOCKHANDLE(h); |
269 | return e; |
||
270 | } |
||
271 | |||
555 | daniel-mar | 272 | FFSavingResult savefile_afs_pff_picotxt_guf(StandardFileReply *sfr){ |
259 | daniel-mar | 273 | FILEREF r; |
274 | Handle h; |
||
555 | daniel-mar | 275 | Boolean bres = false; |
557 | daniel-mar | 276 | FFSavingResult res = SAVING_OK; |
259 | daniel-mar | 277 | |
278 | FSpDelete(&sfr->sfFile); |
||
555 | daniel-mar | 279 | if (FSpCreate(&sfr->sfFile, SIG_SIMPLETEXT, TEXT_FILETYPE, sfr->sfScript) == noErr) { |
280 | if (FSpOpenDF(&sfr->sfFile, fsWrPerm, &r) == noErr) { |
||
259 | daniel-mar | 281 | |
444 | daniel-mar | 282 | if (fileHasExtension(sfr, TEXT(".txt"))) { |
389 | daniel-mar | 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. |
||
555 | daniel-mar | 285 | bres = !(saveparams_picotxt(h) || savehandleintofile(h, r)); |
286 | if (!bres) res = MSG_ERROR_GENERATING_DATA_ID; |
||
389 | daniel-mar | 287 | PIDISPOSEHANDLE(h); |
288 | } |
||
555 | daniel-mar | 289 | else res = MSG_OUT_OF_MEMORY_ID; |
369 | daniel-mar | 290 | } |
555 | daniel-mar | 291 | else if (fileHasExtension(sfr, TEXT(".guf"))) { |
537 | daniel-mar | 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. |
||
555 | daniel-mar | 294 | bres = !(saveparams_guf(h) || savehandleintofile(h, r)); |
295 | if (!bres) res = MSG_ERROR_GENERATING_DATA_ID; |
||
537 | daniel-mar | 296 | PIDISPOSEHANDLE(h); |
297 | } |
||
555 | daniel-mar | 298 | else res = MSG_OUT_OF_MEMORY_ID; |
537 | daniel-mar | 299 | } |
555 | daniel-mar | 300 | else if ((fileHasExtension(sfr, TEXT(".afs"))) || (fileHasExtension(sfr, TEXT(".pff")))) { |
389 | daniel-mar | 301 | if ((h = PINEWHANDLE(1))) { // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that. |
555 | daniel-mar | 302 | bres = !(saveparams_afs_pff(h, fileHasExtension(sfr, TEXT(".pff"))) || savehandleintofile(h, r)); |
303 | if (!bres) res = MSG_ERROR_GENERATING_DATA_ID; |
||
389 | daniel-mar | 304 | PIDISPOSEHANDLE(h); |
305 | } |
||
555 | daniel-mar | 306 | else res = MSG_OUT_OF_MEMORY_ID; |
369 | daniel-mar | 307 | } |
555 | daniel-mar | 308 | else { |
309 | res = MSG_UNSUPPORTED_FILE_FORMAT_ID; |
||
310 | } |
||
369 | daniel-mar | 311 | |
259 | daniel-mar | 312 | FSClose(r); |
555 | daniel-mar | 313 | } |
314 | else res = MSG_CANNOT_OPEN_FILE_ID; |
||
444 | daniel-mar | 315 | } |
555 | daniel-mar | 316 | else res = MSG_CANNOT_CREATE_FILE_ID; |
259 | daniel-mar | 317 | |
318 | return res; |
||
319 | } |