Subversion Repositories filter_foundry

Rev

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
}