Subversion Repositories filter_foundry

Rev

Rev 184 | Rev 186 | 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
 
185 dmarschall 125
#define AETE_WRITE_BYTE(i) *((uint8_t*)aeteptr) = (i); (byte*)aeteptr += 1
126
#define AETE_WRITE_WORD(i) *((uint16_t*)aeteptr) = (i); (byte*)aeteptr += 2
127
#define AETE_WRITE_DWORD(i) *((uint32_t*)aeteptr) = (i); (byte*)aeteptr += 4
128
#define AETE_WRITE_STR(s) assert(strlen((s))<=255); AETE_WRITE_BYTE((uint8_t)strlen((s))); strcpy((char*)aeteptr, (s)); (byte*)aeteptr += strlen((s))
184 dmarschall 129
#ifdef MAC_ENV
130
#define AETE_ALIGN_WORD() (byte*)aeteptr += (intptr_t)aeteptr & 1
131
#else
132
#define AETE_ALIGN_WORD() /*nothing*/
133
#endif
134
 
185 dmarschall 135
void* _aete_property(void* aeteptr, PARM_T *pparm, int ctlidx, int mapidx, OSType key) {
136
        char tmp[256];
137
 
138
        if (pparm->ctl_used[ctlidx] || pparm->map_used[mapidx]) {
139
                if (pparm->map_used[mapidx]) {
140
                        if (ctlidx & 1) {
141
                                sprintf(tmp, "... %s", (char*)pparm->map[mapidx]);
142
                        } else {
143
                                sprintf(tmp, "%s ...", (char*)pparm->map[mapidx]);
144
                        }
145
                        AETE_WRITE_STR(tmp);
146
                } else {
147
                        AETE_WRITE_STR((char*)pparm->ctl[ctlidx]);
148
                }
149
                AETE_ALIGN_WORD();
150
                AETE_WRITE_DWORD(key);
151
                AETE_WRITE_DWORD(typeSInt32);
152
                AETE_WRITE_STR("");
153
                AETE_ALIGN_WORD();
154
                AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
155
        }
156
 
157
        return aeteptr;
158
}
159
 
160
size_t aete_generate(void* aeteptr, PARM_T *pparm) {
184 dmarschall 161
        int numprops;
162
        void *beginptr = aeteptr;
163
 
164
        // Attention!
185 dmarschall 165
        // - On some systems (e.g. ARM based CPUs) this will cause an unaligned memory access exception.
184 dmarschall 166
        //   For X86, memory access just becomes slower.
167
        // - If you change something here, please also change it in PiPL.rc (Windows) and scripting.r (Mac OS)
168
 
169
        // Note:
170
        // - The 'aete' resource for Mac OS has word alignments after strings (but not if the next element is also a string)
171
        //   see https://developer.apple.com/library/archive/documentation/mac/pdf/Interapplication_Communication/AE_Term_Resources.pdf page 8-9
172
 
173
#ifdef WIN_ENV
174
        AETE_WRITE_WORD(0x0001); /* Reserved (for Photoshop) */
175
#endif
176
        AETE_WRITE_BYTE(0x01); /* aete version */
177
        AETE_WRITE_BYTE(0x00); /* aete version */
178
        AETE_WRITE_WORD(english); /* language specifiers */
179
        AETE_WRITE_WORD(roman);
180
        AETE_WRITE_WORD(1); /* 1 suite */
181
        {
182
                AETE_WRITE_STR(/*"Telegraphics"*/(char*)pparm->author); /* vendor suite name */
185 dmarschall 183
                AETE_WRITE_STR(""); /* optional description */
184 dmarschall 184
                AETE_ALIGN_WORD();
185
                AETE_WRITE_DWORD(plugInSuiteID); /* suite ID */
186
                AETE_WRITE_WORD(1); /* suite code, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */
187
                AETE_WRITE_WORD(1); /* suite level, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */
188
                AETE_WRITE_WORD(1); /* 1 event (structure for filters) */
189
                {
185 dmarschall 190
                        AETE_WRITE_STR(/*"FilterFoundry"*/(char*)pparm->title); /* event name */
184 dmarschall 191
                        AETE_WRITE_STR(""); /* event description */
192
                        AETE_ALIGN_WORD();
193
                        AETE_WRITE_DWORD(plugInClassID); /* event class */
194
                        AETE_WRITE_DWORD(/*plugInEventID*/event_id); /* event ID */
195
                        /* NO_REPLY: */
196
                        AETE_WRITE_DWORD(noReply); /* noReply='null' */
197
                        AETE_WRITE_STR(""); /* reply description */
198
                        AETE_ALIGN_WORD();
199
                        AETE_WRITE_WORD(0);
200
                        /* IMAGE_DIRECT_PARAM: */
185 dmarschall 201
                        AETE_WRITE_DWORD(typeImageReference); /* typeImageReference='#ImR' */
184 dmarschall 202
                        AETE_WRITE_STR(""); /* direct parm description */
203
                        AETE_ALIGN_WORD();
204
                        AETE_WRITE_WORD(0xB000);
205
 
206
                        numprops = 0;
207
                        if (pparm->ctl_used[0] || pparm->map_used[0]) numprops++;
208
                        if (pparm->ctl_used[1] || pparm->map_used[0]) numprops++;
209
                        if (pparm->ctl_used[2] || pparm->map_used[1]) numprops++;
210
                        if (pparm->ctl_used[3] || pparm->map_used[1]) numprops++;
211
                        if (pparm->ctl_used[4] || pparm->map_used[2]) numprops++;
212
                        if (pparm->ctl_used[5] || pparm->map_used[2]) numprops++;
213
                        if (pparm->ctl_used[6] || pparm->map_used[3]) numprops++;
214
                        if (pparm->ctl_used[7] || pparm->map_used[3]) numprops++;
215
                        AETE_WRITE_WORD(numprops);
216
                        {
217
                                // Standalone filters don't need RGBA expressions
218
                                /*
219
                                AETE_WRITE_STR("R");
220
                                AETE_ALIGN_WORD();
221
                                AETE_WRITE_DWORD(PARAM_R_KEY);
222
                                AETE_WRITE_DWORD(typeText);
223
                                AETE_WRITE_STR("R channel expression");
224
                                AETE_ALIGN_WORD();
225
                                AETE_WRITE_WORD(0x8000);
226
 
227
                                AETE_WRITE_STR("G");
228
                                AETE_ALIGN_WORD();
229
                                AETE_WRITE_DWORD(PARAM_G_KEY);
230
                                AETE_WRITE_DWORD(typeText);
231
                                AETE_WRITE_STR("G channel expression");
232
                                AETE_ALIGN_WORD();
233
                                AETE_WRITE_WORD(0x8000);
234
 
235
                                AETE_WRITE_STR("B");
236
                                AETE_ALIGN_WORD();
237
                                AETE_WRITE_DWORD(PARAM_B_KEY);
238
                                AETE_WRITE_DWORD(typeText);
239
                                AETE_WRITE_STR("B channel expression");
240
                                AETE_ALIGN_WORD();
241
                                AETE_WRITE_WORD(0x8000);
242
 
243
                                AETE_WRITE_STR("A");
244
                                AETE_ALIGN_WORD();
245
                                AETE_WRITE_DWORD(PARAM_A_KEY);
246
                                AETE_WRITE_DWORD(typeText);
247
                                AETE_WRITE_STR("A channel expression");
248
                                AETE_ALIGN_WORD();
249
                                AETE_WRITE_WORD(0x8000);
250
                                */
251
 
185 dmarschall 252
                                aeteptr = _aete_property(aeteptr, pparm, 0, 0, PARAM_CTL0_KEY);
253
                                aeteptr = _aete_property(aeteptr, pparm, 1, 0, PARAM_CTL1_KEY);
254
                                aeteptr = _aete_property(aeteptr, pparm, 2, 1, PARAM_CTL2_KEY);
255
                                aeteptr = _aete_property(aeteptr, pparm, 3, 1, PARAM_CTL3_KEY);
256
                                aeteptr = _aete_property(aeteptr, pparm, 4, 2, PARAM_CTL4_KEY);
257
                                aeteptr = _aete_property(aeteptr, pparm, 5, 2, PARAM_CTL5_KEY);
258
                                aeteptr = _aete_property(aeteptr, pparm, 6, 3, PARAM_CTL6_KEY);
259
                                aeteptr = _aete_property(aeteptr, pparm, 7, 3, PARAM_CTL7_KEY);
184 dmarschall 260
                        }
261
                }
262
 
263
                /* non-filter plug-in class here */
264
                AETE_WRITE_WORD(0); /* 0 classes */
265
                {}
266
                AETE_WRITE_WORD(0); /* 0 comparison ops (not supported) */
267
                {}
268
                AETE_WRITE_WORD(0); /* 0 enumerations */
269
                {}
270
        }
185 dmarschall 271
        AETE_WRITE_DWORD(0); /* padding (FIXME: do we need that? Adobe's Windows filters don't) */
184 dmarschall 272
 
273
        return (byte*)aeteptr - (byte*)beginptr; // length of stuff written
274
}
275
 
276
void obfusc(unsigned char *pparm, size_t size) {
185 dmarschall 277
        size_t i;
184 dmarschall 278
        unsigned char *p;
279
        uint32_t x32;
280
 
281
        x32 = 0x95D4A68F; // Hardcoded seed
282
        for (i = size, p = pparm; i--;) {
283
                // https://de.wikipedia.org/wiki/Xorshift
284
                *p++ ^= (x32 ^= (x32 ^= (x32 ^= x32 << 13) >> 17) << 5);
285
        }
286
}