Rev 541 | Rev 555 | Go to most recent revision | 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 | |||
389 | daniel-mar | 50 | OSErr saveparams_afs_pff(Handle h){ |
505 | daniel-mar | 51 | char outbuf[CHOPLINES * 2 + 2] = ""; |
52 | char *q, * p, * r, * start; |
||
259 | daniel-mar | 53 | size_t n, chunk, j; |
54 | int i; |
||
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 */ |
||
75 | for( i=0 ; i<4 ; ++i ){ |
||
550 | daniel-mar | 76 | if ((r = gdata->parm.szFormula[i])) { |
505 | daniel-mar | 77 | chunk = 0; // to avoid that compiler complains |
78 | for (n = strlen(r); n; n -= chunk) { |
||
79 | chunk = n > (int)CHOPLINES ? (int)CHOPLINES : n; |
||
80 | for (j = chunk, q = outbuf; j--; ) |
||
81 | if (*r == CR) { |
||
259 | daniel-mar | 82 | *q++ = '\\'; |
83 | *q++ = 'r'; |
||
84 | ++r; |
||
505 | daniel-mar | 85 | } |
86 | else if (*r == LF) { |
||
393 | daniel-mar | 87 | |
259 | daniel-mar | 88 | // This can only happen with Windows or Linux. |
369 | daniel-mar | 89 | // Native Linux is not supported, and Windows always combines LF with CR. So we can ignore LF. |
259 | daniel-mar | 90 | ++r; |
505 | daniel-mar | 91 | } |
92 | else |
||
259 | daniel-mar | 93 | *q++ = *r++; |
387 | daniel-mar | 94 | *q++ = CR; |
259 | daniel-mar | 95 | *q = 0; |
505 | daniel-mar | 96 | p = cat(p, outbuf); |
259 | daniel-mar | 97 | } |
505 | daniel-mar | 98 | } |
259 | daniel-mar | 99 | else |
498 | daniel-mar | 100 | p = cat(p,(char*)("(null expr)\r")); // this shouldn't happen |
387 | daniel-mar | 101 | *p++ = CR; |
259 | daniel-mar | 102 | } |
103 | |||
104 | // *p = 0; dbg(start); |
||
105 | |||
106 | PIUNLOCKHANDLE(h); |
||
107 | e = PISETHANDLESIZE(h,(int32)(p - start)); // could ignore this error, maybe |
||
108 | } |
||
109 | |||
110 | return e; |
||
111 | } |
||
112 | |||
550 | daniel-mar | 113 | OSErr saveparams_picotxt(Handle h) { |
389 | daniel-mar | 114 | char * p, *start; |
115 | int i; |
||
116 | OSErr e; |
||
117 | size_t est; |
||
118 | |||
482 | daniel-mar | 119 | if (!h) return nilHandleErr; |
389 | daniel-mar | 120 | |
550 | daniel-mar | 121 | est = strlen(gdata->parm.szFormula[0]) + strlen(gdata->parm.szFormula[1]) + strlen(gdata->parm.szFormula[2]) + strlen(gdata->parm.szFormula[3]); |
389 | daniel-mar | 122 | // do not be tempted to combine into one expression: 'est' is referenced below |
123 | est += 16000; |
||
124 | |||
125 | PIUNLOCKHANDLE(h); // should not be necessary |
||
126 | if (!(e = PISETHANDLESIZE(h, (int32)(est))) && (p = start = PILOCKHANDLE(h, false))) { |
||
550 | daniel-mar | 127 | checksliders(4); |
389 | daniel-mar | 128 | |
129 | // Metadata |
||
550 | daniel-mar | 130 | p += sprintf(p, "Category: %s\r\n", gdata->parm.szCategory); |
131 | p += sprintf(p, "Title: %s\r\n", gdata->parm.szTitle); |
||
132 | p += sprintf(p, "Copyright: %s\r\n", gdata->parm.szCopyright); |
||
133 | p += sprintf(p, "Author: %s\r\n", gdata->parm.szAuthor); |
||
134 | p += sprintf(p, "Filename: %s\r\n", "Untitled.8bf"); // TODO: get .txt filename and change .txt to .8bf |
||
389 | daniel-mar | 135 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 136 | p += sprintf(p, "R: %s\r\n", gdata->parm.szFormula[0]); |
389 | daniel-mar | 137 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 138 | p += sprintf(p, "G: %s\r\n", gdata->parm.szFormula[1]); |
389 | daniel-mar | 139 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 140 | p += sprintf(p, "B: %s\r\n", gdata->parm.szFormula[2]); |
389 | daniel-mar | 141 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 142 | p += sprintf(p, "A: %s\r\n", gdata->parm.szFormula[3]); |
389 | daniel-mar | 143 | p += sprintf(p, "\r\n"); |
550 | daniel-mar | 144 | for (i = 0; i < 8; i++) { |
145 | if (gdata->parm.ctl_used[i]) { |
||
146 | p += sprintf(p, "ctl[%d]: %s\r\n", i, gdata->parm.szCtl[i]); |
||
389 | daniel-mar | 147 | } |
550 | daniel-mar | 148 | } |
149 | for (i = 0; i < 4; i++) { |
||
150 | if (gdata->parm.map_used[i]) { |
||
151 | p += sprintf(p, "map[%d]: %s\r\n", i, gdata->parm.szMap[i]); |
||
389 | daniel-mar | 152 | } |
550 | daniel-mar | 153 | } |
154 | p += sprintf(p, "\r\n"); |
||
155 | for (i = 0; i < 8; i++) { |
||
156 | if (gdata->parm.ctl_used[i]) { |
||
157 | p += sprintf(p, "val[%d]: %d\r\n", i, gdata->parm.val[i]); |
||
389 | daniel-mar | 158 | } |
159 | } |
||
550 | daniel-mar | 160 | /* |
161 | p += sprintf(p, "\r\n"); |
||
162 | for (i = 0; i < 8; i++) { |
||
163 | if (gdata->parm.ctl_used[i]) { |
||
164 | p += sprintf(p, "def[%d]: %d\r\n", i, gdata->parm.val[i]); |
||
389 | daniel-mar | 165 | } |
166 | } |
||
550 | daniel-mar | 167 | */ |
389 | daniel-mar | 168 | |
169 | PIUNLOCKHANDLE(h); |
||
170 | e = PISETHANDLESIZE(h, (int32)(p - start)); // could ignore this error, maybe |
||
171 | } |
||
172 | |||
173 | return e; |
||
174 | } |
||
175 | |||
550 | daniel-mar | 176 | OSErr saveparams_guf(Handle h) { |
539 | daniel-mar | 177 | char* p, * start; |
178 | int i; |
||
179 | OSErr e; |
||
180 | size_t est; |
||
181 | |||
182 | if (!h) return nilHandleErr; |
||
183 | |||
550 | daniel-mar | 184 | est = strlen(gdata->parm.szFormula[0]) + strlen(gdata->parm.szFormula[1]) + strlen(gdata->parm.szFormula[2]) + strlen(gdata->parm.szFormula[3]); |
539 | daniel-mar | 185 | // do not be tempted to combine into one expression: 'est' is referenced below |
186 | est += 16000; |
||
187 | |||
188 | // TODO: Encode the file in UTF-8! (German Umlauts, etc.) |
||
189 | |||
190 | PIUNLOCKHANDLE(h); // should not be necessary |
||
191 | if (!(e = PISETHANDLESIZE(h, (int32)(est))) && (p = start = PILOCKHANDLE(h, false))) { |
||
192 | char strBuildDate[11/*strlen("0000-00-00") + 1*/]; |
||
193 | time_t iBuildDate = time(0); |
||
541 | daniel-mar | 194 | strftime(strBuildDate, 11, "%Y-%m-%d", localtime(&iBuildDate)); |
539 | daniel-mar | 195 | |
550 | daniel-mar | 196 | checksliders(4); |
539 | daniel-mar | 197 | |
198 | // Metadata |
||
199 | p += sprintf(p, "# Created with Filter Foundry %s\r\n", VERSION_STR); |
||
200 | p += sprintf(p, "\r\n"); |
||
201 | p += sprintf(p, "[GUF]\r\n"); |
||
202 | p += sprintf(p, "Protocol=1\r\n"); |
||
203 | p += sprintf(p, "\r\n"); |
||
204 | p += sprintf(p, "[Info]\r\n"); |
||
550 | daniel-mar | 205 | p += sprintf(p, "Category=<Image>/Filter Factory/%s\r\n", gdata->parm.szCategory); |
206 | p += sprintf(p, "Title=%s\r\n", gdata->parm.szTitle); |
||
207 | p += sprintf(p, "Copyright=%s\r\n", gdata->parm.szCopyright); |
||
208 | p += sprintf(p, "Author=%s\r\n", gdata->parm.szAuthor); |
||
539 | daniel-mar | 209 | p += sprintf(p, "\r\n"); |
210 | p += sprintf(p, "[Version]\r\n"); |
||
211 | p += sprintf(p, "Major=1\r\n"); |
||
212 | p += sprintf(p, "Minor=0\r\n"); |
||
213 | p += sprintf(p, "Micro=0\r\n"); |
||
214 | p += sprintf(p, "\r\n"); |
||
215 | p += sprintf(p, "[Filter Factory]\r\n"); |
||
550 | daniel-mar | 216 | p += sprintf(p, "8bf=%s\r\n", "Untitled.8bf"); // TODO: get .guf filename and change .guf to .8bf |
539 | daniel-mar | 217 | p += sprintf(p, "\r\n"); |
218 | p += sprintf(p, "[Gimp]\r\n"); |
||
219 | p += sprintf(p, "Registered=false\r\n"); |
||
550 | daniel-mar | 220 | p += sprintf(p, "Description=%s\r\n", gdata->parm.szTitle); |
539 | daniel-mar | 221 | p += sprintf(p, "EdgeMode=2\r\n"); |
222 | p += sprintf(p, "Date=%s\r\n", strBuildDate); |
||
223 | p += sprintf(p, "\r\n"); |
||
224 | |||
550 | daniel-mar | 225 | for (i = 0; i < 8; i++) { |
226 | p += sprintf(p, "[Control %d]\r\n", i); |
||
227 | p += sprintf(p, "Enabled=%s\r\n", gdata->parm.ctl_used[i] ? "true" : "false"); |
||
228 | p += sprintf(p, "Label=%s\r\n", gdata->parm.szCtl[i]); |
||
229 | p += sprintf(p, "Preset=%d\r\n", gdata->parm.val[i]); |
||
230 | p += sprintf(p, "Step=1\r\n"); |
||
231 | p += sprintf(p, "\r\n"); |
||
539 | daniel-mar | 232 | } |
550 | daniel-mar | 233 | for (i = 0; i < 4; i++) { |
234 | p += sprintf(p, "[Map %d]\r\n", i); |
||
235 | p += sprintf(p, "Enabled=%s\r\n", gdata->parm.map_used[i] ? "true" : "false"); |
||
236 | p += sprintf(p, "Label=%s\r\n", gdata->parm.szMap[i]); |
||
237 | p += sprintf(p, "\r\n"); |
||
539 | daniel-mar | 238 | } |
239 | |||
240 | p += sprintf(p, "[Code]\r\n"); |
||
550 | daniel-mar | 241 | p += sprintf(p, "R=%s\r\n", gdata->parm.szFormula[0]); |
242 | p += sprintf(p, "G=%s\r\n", gdata->parm.szFormula[1]); |
||
243 | p += sprintf(p, "B=%s\r\n", gdata->parm.szFormula[2]); |
||
244 | p += sprintf(p, "A=%s\r\n", gdata->parm.szFormula[3]); |
||
539 | daniel-mar | 245 | |
246 | PIUNLOCKHANDLE(h); |
||
247 | e = PISETHANDLESIZE(h, (int32)(p - start)); // could ignore this error, maybe |
||
248 | } |
||
249 | |||
250 | return e; |
||
537 | daniel-mar | 251 | } |
252 | |||
259 | daniel-mar | 253 | OSErr savehandleintofile(Handle h,FILEREF r){ |
482 | daniel-mar | 254 | Ptr p; |
505 | daniel-mar | 255 | FILECOUNT n; |
482 | daniel-mar | 256 | OSErr e; |
257 | |||
258 | if (!h) return nilHandleErr; |
||
259 | p = PILOCKHANDLE(h,false); |
||
505 | daniel-mar | 260 | n = (FILECOUNT)PIGETHANDLESIZE(h); |
482 | daniel-mar | 261 | e = FSWrite(r,&n,p); |
259 | daniel-mar | 262 | PIUNLOCKHANDLE(h); |
263 | return e; |
||
264 | } |
||
265 | |||
537 | daniel-mar | 266 | Boolean savefile_afs_pff_picotxt_guf(StandardFileReply *sfr){ |
259 | daniel-mar | 267 | FILEREF r; |
268 | Handle h; |
||
269 | Boolean res = false; |
||
498 | daniel-mar | 270 | TCHAR* reasonstr = NULL; |
259 | daniel-mar | 271 | |
272 | FSpDelete(&sfr->sfFile); |
||
273 | if(FSpCreate(&sfr->sfFile,SIG_SIMPLETEXT,TEXT_FILETYPE,sfr->sfScript) == noErr) |
||
274 | if(FSpOpenDF(&sfr->sfFile,fsWrPerm,&r) == noErr){ |
||
275 | |||
444 | daniel-mar | 276 | if (fileHasExtension(sfr, TEXT(".txt"))) { |
389 | daniel-mar | 277 | // PluginCommander .txt |
278 | if ((h = PINEWHANDLE(1))) { // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that. |
||
550 | daniel-mar | 279 | res = !(saveparams_picotxt(h) || savehandleintofile(h, r)); |
389 | daniel-mar | 280 | PIDISPOSEHANDLE(h); |
281 | } |
||
369 | daniel-mar | 282 | } |
283 | |||
537 | daniel-mar | 284 | if (fileHasExtension(sfr, TEXT(".guf"))) { |
285 | // GIMP UserFilter file |
||
286 | if ((h = PINEWHANDLE(1))) { // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that. |
||
550 | daniel-mar | 287 | res = !(saveparams_guf(h) || savehandleintofile(h, r)); |
537 | daniel-mar | 288 | PIDISPOSEHANDLE(h); |
289 | } |
||
290 | } |
||
291 | |||
444 | daniel-mar | 292 | if ((fileHasExtension(sfr, TEXT(".afs"))) || (fileHasExtension(sfr, TEXT(".pff")))) { |
293 | if (fileHasExtension(sfr, TEXT(".pff"))) { |
||
389 | daniel-mar | 294 | // If it is a Premiere settings file, we need to swap the channels red and blue |
295 | // We just swap the pointers! |
||
550 | daniel-mar | 296 | char tmp[MAXEXPR]; |
297 | strcpy(tmp, gdata->parm.szFormula[0]); |
||
298 | strcpy(gdata->parm.szFormula[0], gdata->parm.szFormula[2]); |
||
299 | strcpy(gdata->parm.szFormula[2], tmp); |
||
389 | daniel-mar | 300 | } |
259 | daniel-mar | 301 | |
389 | daniel-mar | 302 | if ((h = PINEWHANDLE(1))) { // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that. |
303 | res = !(saveparams_afs_pff(h) || savehandleintofile(h, r)); |
||
304 | PIDISPOSEHANDLE(h); |
||
305 | } |
||
306 | |||
444 | daniel-mar | 307 | if (fileHasExtension(sfr, TEXT(".pff"))) { |
389 | daniel-mar | 308 | // Swap back so that the other program stuff will work normally again |
550 | daniel-mar | 309 | char tmp[MAXEXPR]; |
310 | strcpy(tmp, gdata->parm.szFormula[0]); |
||
311 | strcpy(gdata->parm.szFormula[0], gdata->parm.szFormula[2]); |
||
312 | strcpy(gdata->parm.szFormula[2], tmp); |
||
389 | daniel-mar | 313 | } |
369 | daniel-mar | 314 | } |
315 | |||
259 | daniel-mar | 316 | FSClose(r); |
498 | daniel-mar | 317 | }else reasonstr = FF_GetMsg_Cpy(MSG_CANNOT_OPEN_FILE_ID); |
318 | else reasonstr = FF_GetMsg_Cpy(MSG_CANNOT_CREATE_FILE_ID); |
||
259 | daniel-mar | 319 | |
444 | daniel-mar | 320 | if (!res) { |
492 | daniel-mar | 321 | alertuser_id(MSG_CANNOT_SAVE_SETTINGS_ID, reasonstr); |
444 | daniel-mar | 322 | } |
259 | daniel-mar | 323 | |
498 | daniel-mar | 324 | if (reasonstr) FF_GetMsg_Free(reasonstr); |
325 | |||
259 | daniel-mar | 326 | return res; |
327 | } |