Rev 178 | Rev 185 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed
Rev | Author | Line No. | Line |
---|---|---|---|
184 | dmarschall | 1 | /* |
2 | This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop |
||
3 | Copyright (C) 2003-2019 Toby Thain, toby@telegraphics.com.au |
||
4 | |||
5 | This program is free software; you can redistribute it and/or modify |
||
6 | it under the terms of the GNU General Public License as published by |
||
7 | the Free Software Foundation; either version 2 of the License, or |
||
8 | (at your option) any later version. |
||
9 | |||
10 | This program is distributed in the hope that it will be useful, |
||
11 | but WITHOUT ANY WARRANTY; without even the implied warranty of |
||
12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
||
13 | GNU General Public License for more details. |
||
14 | |||
15 | You should have received a copy of the GNU General Public License |
||
16 | along with this program; if not, write to the Free Software |
||
17 | Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA |
||
18 | */ |
||
19 | |||
20 | #include <stddef.h> |
||
21 | #include <stdint.h> |
||
22 | |||
23 | #include "ff.h" |
||
24 | #include "symtab.h" |
||
25 | |||
26 | #include "PIActions.h" |
||
27 | #include "PITerminology.h" |
||
28 | |||
29 | #include "compat_string.h" |
||
30 | |||
31 | long event_id; |
||
32 | |||
33 | /* |
||
34 | Find a printable 4-character key, remembering (see PS API guide): |
||
35 | All IDs starting with an uppercase letter are reserved by Adobe. |
||
36 | All IDs that are all uppercase are reserved by Apple. |
||
37 | All IDs that are all lowercase are reserved by Apple. |
||
38 | This leaves all IDs that begin with a lowercase letter and have at least |
||
39 | one uppercase letter for you and other plug-in developers. |
||
40 | */ |
||
41 | unsigned long printablehash(unsigned long hash) { |
||
42 | unsigned long key = 'a' + (hash % 26); hash /= 26; // first lower case |
||
43 | key = (key << 8) | (' ' + (hash % 95)); hash /= 95; // any printable |
||
44 | key = (key << 8) | (' ' + (hash % 95)); hash /= 95; // any printable |
||
45 | return (key << 8) | ('A' + (hash % 26)); // last upper case |
||
46 | } |
||
47 | |||
48 | long roundToNext4(long x) { |
||
49 | int pad = 4 - (x % 4); |
||
50 | if (pad == 0) pad = 4; |
||
51 | return x + pad; |
||
52 | } |
||
53 | |||
54 | long fixpipl(PIPropertyList *pipl, long origsize, StringPtr title) { |
||
55 | PIProperty *prop; |
||
56 | char *p; |
||
57 | struct hstm_data { |
||
58 | /* this structure must be 14+1 bytes long, to match PiPL structure */ |
||
59 | long version; /* = 0 */ |
||
60 | long class_id; |
||
61 | long event_id; |
||
62 | short aete_resid; |
||
63 | char scope[1]; |
||
64 | }; |
||
65 | struct hstm_data *hstm; |
||
66 | int scopelen; |
||
67 | unsigned long hash; |
||
68 | |||
69 | pipl->count += 3; // 3 more keys in PiPL: name, catg, hstm |
||
70 | |||
71 | p = (char*)pipl + origsize; |
||
72 | prop = (PIProperty*)p; |
||
73 | |||
74 | /* add Title/Name property key */ |
||
75 | |||
76 | prop->vendorID = kPhotoshopSignature; |
||
77 | prop->propertyKey = PINameProperty; |
||
78 | prop->propertyID = 0; |
||
79 | prop->propertyLength = roundToNext4(title[0] + 1); |
||
80 | PLstrcpy((StringPtr)prop->propertyData, title); |
||
81 | |||
82 | // skip past new property record, and any padding |
||
83 | p += offsetof(PIProperty, propertyData) + prop->propertyLength; |
||
84 | prop = (PIProperty*)p; |
||
85 | |||
86 | /* add Category property key */ |
||
87 | |||
88 | prop->vendorID = kPhotoshopSignature; |
||
89 | prop->propertyKey = PICategoryProperty; |
||
90 | prop->propertyID = 0; |
||
91 | prop->propertyLength = roundToNext4(gdata->parm.category[0] + 1); |
||
92 | PLstrcpy((StringPtr)prop->propertyData, gdata->parm.category); |
||
93 | |||
94 | p += offsetof(PIProperty, propertyData) + prop->propertyLength; |
||
95 | prop = (PIProperty*)p; |
||
96 | |||
97 | /* add HasTerminology property key */ |
||
98 | |||
99 | /* construct scope string by concatenating Category and Title - hopefully unique! */ |
||
100 | hstm = (struct hstm_data*)prop->propertyData; |
||
101 | scopelen = sprintf(hstm->scope, "%s %s", |
||
102 | INPLACEP2CSTR(gdata->parm.category), |
||
103 | INPLACEP2CSTR(title)); |
||
104 | |||
105 | /* make up a new event ID for this aete, based on printable base-95 hash of scope */ |
||
106 | hash = djb2(hstm->scope); |
||
107 | event_id = printablehash(hash); /* this is used by fixaete() later... */ |
||
108 | |||
109 | prop->vendorID = kPhotoshopSignature; |
||
110 | prop->propertyKey = PIHasTerminologyProperty; |
||
111 | prop->propertyID = 0; |
||
112 | prop->propertyLength = roundToNext4(offsetof(struct hstm_data, scope) + scopelen); |
||
113 | |||
114 | hstm->version = 0; |
||
115 | hstm->class_id = plugInClassID; |
||
116 | hstm->event_id = event_id; |
||
117 | hstm->aete_resid = AETE_ID; |
||
118 | |||
119 | p += offsetof(PIProperty, propertyData) + prop->propertyLength; |
||
120 | |||
121 | return p - (char*)pipl; // figure how many bytes were added |
||
122 | } |
||
123 | |||
124 | #define AETE_WRITE_BYTE(i) *((int8_t*)aeteptr) = (i); (byte*)aeteptr += 1 |
||
125 | #define AETE_WRITE_WORD(i) *((int16_t*)aeteptr) = (i); (byte*)aeteptr += 2 |
||
126 | #define AETE_WRITE_DWORD(i) *((int32_t*)aeteptr) = (i); (byte*)aeteptr += 4 |
||
127 | #define AETE_WRITE_STR(s) *((int8_t*)aeteptr) = strlen(s); (byte*)aeteptr += 1; strcpy((char*)aeteptr, s); (byte*)aeteptr += strlen(s) |
||
128 | #ifdef MAC_ENV |
||
129 | #define AETE_ALIGN_WORD() (byte*)aeteptr += (intptr_t)aeteptr & 1 |
||
130 | #else |
||
131 | #define AETE_ALIGN_WORD() /*nothing*/ |
||
132 | #endif |
||
133 | |||
134 | long aete_generate(void* aeteptr, PARM_T *pparm) { |
||
135 | int numprops; |
||
136 | void *beginptr = aeteptr; |
||
137 | |||
138 | // Attention! |
||
139 | // - On some systems (ARM) this will cause unaligned memory access exception. |
||
140 | // For X86, memory access just becomes slower. |
||
141 | // - If you change something here, please also change it in PiPL.rc (Windows) and scripting.r (Mac OS) |
||
142 | |||
143 | // Note: |
||
144 | // - The 'aete' resource for Mac OS has word alignments after strings (but not if the next element is also a string) |
||
145 | // see https://developer.apple.com/library/archive/documentation/mac/pdf/Interapplication_Communication/AE_Term_Resources.pdf page 8-9 |
||
146 | |||
147 | #ifdef WIN_ENV |
||
148 | AETE_WRITE_WORD(0x0001); /* Reserved (for Photoshop) */ |
||
149 | #endif |
||
150 | AETE_WRITE_BYTE(0x01); /* aete version */ |
||
151 | AETE_WRITE_BYTE(0x00); /* aete version */ |
||
152 | AETE_WRITE_WORD(english); /* language specifiers */ |
||
153 | AETE_WRITE_WORD(roman); |
||
154 | AETE_WRITE_WORD(1); /* 1 suite */ |
||
155 | { |
||
156 | AETE_WRITE_STR(/*"Telegraphics"*/(char*)pparm->author); /* vendor suite name */ |
||
157 | AETE_WRITE_STR(/*""*/(char*)pparm->title); /* optional description */ |
||
158 | AETE_ALIGN_WORD(); |
||
159 | AETE_WRITE_DWORD(plugInSuiteID); /* suite ID */ |
||
160 | AETE_WRITE_WORD(1); /* suite code, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */ |
||
161 | AETE_WRITE_WORD(1); /* suite level, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */ |
||
162 | AETE_WRITE_WORD(1); /* 1 event (structure for filters) */ |
||
163 | { |
||
164 | AETE_WRITE_STR("FilterFoundry"); /* event name */ |
||
165 | AETE_WRITE_STR(""); /* event description */ |
||
166 | AETE_ALIGN_WORD(); |
||
167 | AETE_WRITE_DWORD(plugInClassID); /* event class */ |
||
168 | AETE_WRITE_DWORD(/*plugInEventID*/event_id); /* event ID */ |
||
169 | /* NO_REPLY: */ |
||
170 | AETE_WRITE_DWORD(noReply); /* noReply='null' */ |
||
171 | AETE_WRITE_STR(""); /* reply description */ |
||
172 | AETE_ALIGN_WORD(); |
||
173 | AETE_WRITE_WORD(0); |
||
174 | /* IMAGE_DIRECT_PARAM: */ |
||
175 | AETE_WRITE_DWORD(typeImageReference); /* '#ImR' */ |
||
176 | AETE_WRITE_STR(""); /* direct parm description */ |
||
177 | AETE_ALIGN_WORD(); |
||
178 | AETE_WRITE_WORD(0xB000); |
||
179 | |||
180 | numprops = 0; |
||
181 | if (pparm->ctl_used[0] || pparm->map_used[0]) numprops++; |
||
182 | if (pparm->ctl_used[1] || pparm->map_used[0]) numprops++; |
||
183 | if (pparm->ctl_used[2] || pparm->map_used[1]) numprops++; |
||
184 | if (pparm->ctl_used[3] || pparm->map_used[1]) numprops++; |
||
185 | if (pparm->ctl_used[4] || pparm->map_used[2]) numprops++; |
||
186 | if (pparm->ctl_used[5] || pparm->map_used[2]) numprops++; |
||
187 | if (pparm->ctl_used[6] || pparm->map_used[3]) numprops++; |
||
188 | if (pparm->ctl_used[7] || pparm->map_used[3]) numprops++; |
||
189 | AETE_WRITE_WORD(numprops); |
||
190 | { |
||
191 | // Standalone filters don't need RGBA expressions |
||
192 | /* |
||
193 | AETE_WRITE_STR("R"); |
||
194 | AETE_ALIGN_WORD(); |
||
195 | AETE_WRITE_DWORD(PARAM_R_KEY); |
||
196 | AETE_WRITE_DWORD(typeText); |
||
197 | AETE_WRITE_STR("R channel expression"); |
||
198 | AETE_ALIGN_WORD(); |
||
199 | AETE_WRITE_WORD(0x8000); |
||
200 | |||
201 | AETE_WRITE_STR("G"); |
||
202 | AETE_ALIGN_WORD(); |
||
203 | AETE_WRITE_DWORD(PARAM_G_KEY); |
||
204 | AETE_WRITE_DWORD(typeText); |
||
205 | AETE_WRITE_STR("G channel expression"); |
||
206 | AETE_ALIGN_WORD(); |
||
207 | AETE_WRITE_WORD(0x8000); |
||
208 | |||
209 | AETE_WRITE_STR("B"); |
||
210 | AETE_ALIGN_WORD(); |
||
211 | AETE_WRITE_DWORD(PARAM_B_KEY); |
||
212 | AETE_WRITE_DWORD(typeText); |
||
213 | AETE_WRITE_STR("B channel expression"); |
||
214 | AETE_ALIGN_WORD(); |
||
215 | AETE_WRITE_WORD(0x8000); |
||
216 | |||
217 | AETE_WRITE_STR("A"); |
||
218 | AETE_ALIGN_WORD(); |
||
219 | AETE_WRITE_DWORD(PARAM_A_KEY); |
||
220 | AETE_WRITE_DWORD(typeText); |
||
221 | AETE_WRITE_STR("A channel expression"); |
||
222 | AETE_ALIGN_WORD(); |
||
223 | AETE_WRITE_WORD(0x8000); |
||
224 | */ |
||
225 | |||
226 | if (pparm->ctl_used[0] || pparm->map_used[0]) { |
||
227 | AETE_WRITE_STR(/*"ctl0"*/pparm->map_used[0] ? (char*)pparm->map[0] : (char*)pparm->ctl[0]); |
||
228 | AETE_ALIGN_WORD(); |
||
229 | AETE_WRITE_DWORD(PARAM_CTL0_KEY); |
||
230 | AETE_WRITE_DWORD(typeSInt32); |
||
231 | AETE_WRITE_STR("ctl(0) setting"); |
||
232 | AETE_ALIGN_WORD(); |
||
233 | AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */ |
||
234 | } |
||
235 | |||
236 | if (pparm->ctl_used[1] || pparm->map_used[0]) { |
||
237 | AETE_WRITE_STR(/*"ctl1"*/pparm->map_used[0] ? (char*)pparm->map[0] : (char*)pparm->ctl[1]); |
||
238 | AETE_ALIGN_WORD(); |
||
239 | AETE_WRITE_DWORD(PARAM_CTL1_KEY); |
||
240 | AETE_WRITE_DWORD(typeSInt32); |
||
241 | AETE_WRITE_STR("ctl(1) setting"); |
||
242 | AETE_ALIGN_WORD(); |
||
243 | AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */ |
||
244 | } |
||
245 | |||
246 | if (pparm->ctl_used[2] || pparm->map_used[1]) { |
||
247 | AETE_WRITE_STR(/*"ctl2"*/pparm->map_used[1] ? (char*)pparm->map[1] : (char*)pparm->ctl[2]); |
||
248 | AETE_ALIGN_WORD(); |
||
249 | AETE_WRITE_DWORD(PARAM_CTL2_KEY); |
||
250 | AETE_WRITE_DWORD(typeSInt32); |
||
251 | AETE_WRITE_STR("ctl(2) setting"); |
||
252 | AETE_ALIGN_WORD(); |
||
253 | AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */ |
||
254 | } |
||
255 | |||
256 | if (pparm->ctl_used[3] || pparm->map_used[1]) { |
||
257 | AETE_WRITE_STR(/*"ctl3"*/pparm->map_used[1] ? (char*)pparm->map[1] : (char*)pparm->ctl[3]); |
||
258 | AETE_ALIGN_WORD(); |
||
259 | AETE_WRITE_DWORD(PARAM_CTL3_KEY); |
||
260 | AETE_WRITE_DWORD(typeSInt32); |
||
261 | AETE_WRITE_STR("ctl(3) setting"); |
||
262 | AETE_ALIGN_WORD(); |
||
263 | AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */ |
||
264 | } |
||
265 | |||
266 | if (pparm->ctl_used[4] || pparm->map_used[2]) { |
||
267 | AETE_WRITE_STR(/*"ctl4"*/pparm->map_used[2] ? (char*)pparm->map[2] : (char*)pparm->ctl[4]); |
||
268 | AETE_ALIGN_WORD(); |
||
269 | AETE_WRITE_DWORD(PARAM_CTL4_KEY); |
||
270 | AETE_WRITE_DWORD(typeSInt32); |
||
271 | AETE_WRITE_STR("ctl(4) setting"); |
||
272 | AETE_ALIGN_WORD(); |
||
273 | AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */ |
||
274 | } |
||
275 | |||
276 | if (pparm->ctl_used[5] || pparm->map_used[2]) { |
||
277 | AETE_WRITE_STR(/*"ctl5"*/pparm->map_used[2] ? (char*)pparm->map[2] : (char*)pparm->ctl[5]); |
||
278 | AETE_ALIGN_WORD(); |
||
279 | AETE_WRITE_DWORD(PARAM_CTL5_KEY); |
||
280 | AETE_WRITE_DWORD(typeSInt32); |
||
281 | AETE_WRITE_STR("ctl(5) setting"); |
||
282 | AETE_ALIGN_WORD(); |
||
283 | AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */ |
||
284 | } |
||
285 | |||
286 | if (pparm->ctl_used[6] || pparm->map_used[3]) { |
||
287 | AETE_WRITE_STR(/*"ctl6"*/pparm->map_used[3] ? (char*)pparm->map[3] : (char*)pparm->ctl[6]); |
||
288 | AETE_ALIGN_WORD(); |
||
289 | AETE_WRITE_DWORD(PARAM_CTL6_KEY); |
||
290 | AETE_WRITE_DWORD(typeSInt32); |
||
291 | AETE_WRITE_STR("ctl(6) setting"); |
||
292 | AETE_ALIGN_WORD(); |
||
293 | AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */ |
||
294 | } |
||
295 | |||
296 | if (pparm->ctl_used[7] || pparm->map_used[3]) { |
||
297 | AETE_WRITE_STR(/*"ctl7"*/pparm->map_used[3] ? (char*)pparm->map[3] : (char*)pparm->ctl[7]); |
||
298 | AETE_ALIGN_WORD(); |
||
299 | AETE_WRITE_DWORD(PARAM_CTL7_KEY); |
||
300 | AETE_WRITE_DWORD(typeSInt32); |
||
301 | AETE_WRITE_STR("ctl(7) setting"); |
||
302 | AETE_ALIGN_WORD(); |
||
303 | AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */ |
||
304 | } |
||
305 | } |
||
306 | } |
||
307 | |||
308 | /* non-filter plug-in class here */ |
||
309 | AETE_WRITE_WORD(0); /* 0 classes */ |
||
310 | {} |
||
311 | AETE_WRITE_WORD(0); /* 0 comparison ops (not supported) */ |
||
312 | {} |
||
313 | AETE_WRITE_WORD(0); /* 0 enumerations */ |
||
314 | {} |
||
315 | } |
||
316 | AETE_WRITE_DWORD(0); /* padding */ |
||
317 | |||
318 | return (byte*)aeteptr - (byte*)beginptr; // length of stuff written |
||
319 | } |
||
320 | |||
321 | void obfusc(unsigned char *pparm, size_t size) { |
||
322 | int i; |
||
323 | unsigned char *p; |
||
324 | uint32_t x32; |
||
325 | |||
326 | x32 = 0x95D4A68F; // Hardcoded seed |
||
327 | for (i = size, p = pparm; i--;) { |
||
328 | // https://de.wikipedia.org/wiki/Xorshift |
||
329 | *p++ ^= (x32 ^= (x32 ^= (x32 ^= x32 << 13) >> 17) << 5); |
||
330 | } |
||
331 | } |