Subversion Repositories filter_foundry

Rev

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