Subversion Repositories filter_foundry

Rev

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