Subversion Repositories filter_foundry

Rev

Rev 517 | Go to most recent revision | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
184 dmarschall 1
/*
247 daniel-mar 2
    This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
503 daniel-mar 4
    Copyright (C) 2018-2022 Daniel Marschall, ViaThinkSoft
184 dmarschall 5
 
247 daniel-mar 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.
184 dmarschall 10
 
247 daniel-mar 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.
184 dmarschall 15
 
247 daniel-mar 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
184 dmarschall 19
*/
20
 
21
#include <stddef.h>
22
#include <stdint.h>
185 dmarschall 23
#include <assert.h>
515 daniel-mar 24
#include <time.h>
184 dmarschall 25
 
26
#include "ff.h"
27
#include "symtab.h"
28
 
210 daniel-mar 29
#include "scripting.h"
184 dmarschall 30
#include "PIActions.h"
31
#include "PITerminology.h"
32
 
33
#include "compat_string.h"
34
 
207 daniel-mar 35
//#define PRINTABLE_HASH_FF16
212 daniel-mar 36
#define ENABLE_APPLESCRIPT
207 daniel-mar 37
 
184 dmarschall 38
/*
207 daniel-mar 39
Find a printable 4-character key, remembering (see Photoshop API guide):
40
- All IDs starting with an uppercase letter are reserved by Adobe.
41
- All IDs that are all uppercase are reserved by Apple.
42
- All IDs that are all lowercase are reserved by Apple.
43
- This leaves all IDs that begin with a lowercase letter and have at least
44
  one uppercase letter for you and other plug-in developers.
45
Note: It is questionable if "a!!!" or "A!!!" are also reseved by Apple. We don't risk it.
184 dmarschall 46
*/
47
unsigned long printablehash(unsigned long hash) {
268 daniel-mar 48
        #ifdef PRINTABLE_HASH_FF16
49
 
247 daniel-mar 50
        // FilterFoundry version 1.6 hashing by Toby Thain
489 daniel-mar 51
        // Only accepts upper-case at the last character
247 daniel-mar 52
        // 0       = 'a  A'
53
        // 6100899 = 'z~~Z'
489 daniel-mar 54
        unsigned long key = 'a' + (hash % 26);  hash /= 26; // first lower-case
247 daniel-mar 55
        key = (key << 8) | (' ' + (hash % 95)); hash /= 95; // any printable
56
        key = (key << 8) | (' ' + (hash % 95)); hash /= 95; // any printable
489 daniel-mar 57
        return  (key << 8) | ('A' + (hash % 26));           // last upper-case
268 daniel-mar 58
 
59
        #else
60
 
247 daniel-mar 61
        // FilterFoundry version 1.7 hashing by Daniel Marschall
489 daniel-mar 62
        // Accepts upper-case at character 2, 3 or 4
247 daniel-mar 63
        // Spaces are only set the right as padding to make a code shorter
64
        // 0        = 'aA  '
65
        // 13530139 = 'zZZZ'
66
        // The key-space is ~2.22 times larger
67
        long lowlim;
68
        long uplim;
69
        int upperCaseInfo;
70
        int length;
71
        int lastThreeCharInfo;
72
        int firstChar;
73
        unsigned long key;
74
        int found;
75
        int i,j,k;
207 daniel-mar 76
 
247 daniel-mar 77
        uplim = 0;
78
        for (k=1; k<4; k++) {
456 daniel-mar 79
                int mask = 0;
247 daniel-mar 80
                if (k == 1) mask = 1;//0b1;
81
                if (k == 2) mask = 2;//0b11;
82
                if (k == 3) mask = 4;//0b111;
83
                for (i=1; i<=mask; i++) {
84
                        // 'k' characters
85
                        long test = 1;
86
                        for (j=0; j<k; ++j) {
87
                                test *= ((i&(1<<j)) != 0) ? 26 : 94-26;
88
                        }
89
                        uplim += test;
90
                }
91
        }
207 daniel-mar 92
 
247 daniel-mar 93
        lastThreeCharInfo = hash % uplim; hash /= uplim;
94
        firstChar = hash%26; hash /= 26;
207 daniel-mar 95
 
247 daniel-mar 96
        lowlim = 0;
97
        uplim = 0;
98
        found = 0;
99
        length = -1; // avoid compiler warning
100
        upperCaseInfo = -1; // avoid compiler warning
101
        for (k=1; k<4; k++) {
102
                int mask;
103
                if (k == 1) mask = 1;//0b1;
104
                if (k == 2) mask = 2;//0b11;
105
                if (k == 3) mask = 4;//0b111;
106
                if (!found) for (i=1; i<=mask; i++) {
107
                        // 'k' characters
108
                        long test = 1;
109
                        for (j=0; j<k; ++j) {
110
                                test *= ((i&(1<<j)) != 0) ? 26 : 94-26;
111
                        }
112
                        uplim += test;
113
                        if ((lastThreeCharInfo >= lowlim) && (lastThreeCharInfo < uplim)) {
114
                                lastThreeCharInfo -= lowlim;
115
                                found = 1;
116
                                length = k;
117
                                upperCaseInfo = i;
118
                                break;
119
                        }
120
                        lowlim = uplim;
121
                }
122
        }
207 daniel-mar 123
 
247 daniel-mar 124
        key = ('a' + firstChar) << 24; // first char is lower-case
125
        for (i=0; i<length; ++i) {
126
                char res;
127
                if ((upperCaseInfo&(1<<i)) == 0) {
128
                        res = '!' + (lastThreeCharInfo % (94-26));
129
                        if (res >= 'A') res += 26;
130
                        lastThreeCharInfo /= (94-26);
131
                } else {
132
                        res = 'A' + (lastThreeCharInfo % 26);
133
                        lastThreeCharInfo /= 26;
134
                }
135
                key |= res << (8*(i+(4-length-1))); // 2nd, 3rd, 4th char are either upper-case or any printable char
136
        }
137
        if (length == 1) {
138
                key &= 0xFFFF0000;
139
                key |= ' ' << 8;
140
                key |= ' ';
141
        }
142
        if (length == 2) {
143
                key &= 0xFFFFFF00;
144
                key |= ' ';
145
        }
146
        return key;
268 daniel-mar 147
 
148
        #endif
184 dmarschall 149
}
150
 
238 daniel-mar 151
size_t roundToNext4(size_t x) {
247 daniel-mar 152
        int pad = 4 - (x % 4);
153
        if (pad == 0) pad = 4;
154
        return x + pad;
184 dmarschall 155
}
156
 
515 daniel-mar 157
size_t fixpipl(PIPropertyList *pipl, size_t origsize, char* title, char* component, char* category, long *event_id) {
247 daniel-mar 158
        PIProperty *prop;
159
        char *p;
160
        struct hstm_data {
161
                /* this structure must be 14+1 bytes long, to match PiPL structure */
162
                long version; /* = 0 */
163
                long class_id;
164
                long event_id;
165
                short aete_resid;
166
                char scope[1];
167
        };
168
        struct hstm_data *hstm;
169
        int scopelen;
170
        unsigned long hash;
171
        size_t realLength;
172
        size_t roundedLength;
515 daniel-mar 173
        unsigned long componentVersion;
174
        time_t curTime;
517 daniel-mar 175
        char szScope[0x300], szOID[0x50];
184 dmarschall 176
 
517 daniel-mar 177
        pipl->count += 5; // 5 more keys in PiPL: catg, name, cmpt, hstm, ObId
184 dmarschall 178
 
247 daniel-mar 179
        p = (char*)pipl + origsize;
180
        prop = (PIProperty*)p;
184 dmarschall 181
 
526 daniel-mar 182
        /* Important note about propertyLength:
503 daniel-mar 183
 
184
                In regards propertyLength, Adobe writes in SPPiPL.h:
185
                "Number of characters in the data array. Rounded to a multiple of 4."
186
 
187
                On the other hand, the 1997 PICA documentation(page 23) and
188
                1996 "Cross-Application Plug-in Development Resource Guide" describes :
189
                "[propertyLength] contains the length of the propertyData field. It does not include any padding bytes after
190
                propertyData to achieve four byte alignment.This field may be zero."
191
 
192
                I think this is not correct, since even official plugins of Adobe(e.g. "3D Transform.8bf") and cnvtpipl
193
                are rounding the length to a multiple of 4 (actually, rounding to the next possible multiple 4,
194
                so that padding is always guaranteed).
195
                Photoshop (tested with Photoshop 7) will crash if the propertyLength follows the definition of PICA.
196
        */
197
 
515 daniel-mar 198
        /* add Category property key */
199
 
200
        prop->vendorID = kPhotoshopSignature;
201
        prop->propertyKey = PICategoryProperty;
202
        prop->propertyID = 0;
203
        prop->propertyLength = (SPInt32)roundToNext4(strlen(category) + 1);
204
        memset(prop->propertyData, 0x00, prop->propertyLength); // fill padding with 00h bytes (cosmetics)
205
        myc2pstrcpy((StringPtr)prop->propertyData, category);
206
        p += offsetof(PIProperty, propertyData) + prop->propertyLength; // skip past new property record, and any padding
207
        prop = (PIProperty*)p;
208
 
247 daniel-mar 209
        /* add Title/Name property key */
184 dmarschall 210
 
247 daniel-mar 211
        prop->vendorID = kPhotoshopSignature;
212
        prop->propertyKey = PINameProperty;
213
        prop->propertyID = 0;
393 daniel-mar 214
        prop->propertyLength = (SPInt32)roundToNext4(strlen(title) + 1);
247 daniel-mar 215
        memset(prop->propertyData, 0x00, prop->propertyLength); // fill padding with 00h bytes (cosmetics)
393 daniel-mar 216
        myc2pstrcpy((StringPtr)prop->propertyData, title);
515 daniel-mar 217
        p += offsetof(PIProperty, propertyData) + prop->propertyLength; // skip past new property record, and any padding
247 daniel-mar 218
        prop = (PIProperty*)p;
184 dmarschall 219
 
515 daniel-mar 220
        /* add Component property key */
184 dmarschall 221
 
247 daniel-mar 222
        prop->vendorID = kPhotoshopSignature;
515 daniel-mar 223
        prop->propertyKey = PIComponentProperty;
247 daniel-mar 224
        prop->propertyID = 0;
515 daniel-mar 225
        time(&curTime);
516 daniel-mar 226
        componentVersion = (unsigned long)(curTime - (time_t)946681200)/*01.Jan.2000 00:00:00*/;
515 daniel-mar 227
        prop->propertyLength = (SPInt32)roundToNext4(strlen(component) + 1 + sizeof(componentVersion));
247 daniel-mar 228
        memset(prop->propertyData, 0x00, prop->propertyLength); // fill padding with 00h bytes (cosmetics)
515 daniel-mar 229
        memcpy(prop->propertyData, &componentVersion, sizeof(componentVersion));
230
        strcpy((char*)(prop->propertyData+sizeof(componentVersion)), component);
231
        p += offsetof(PIProperty, propertyData) + prop->propertyLength; // skip past new property record, and any padding
247 daniel-mar 232
        prop = (PIProperty*)p;
184 dmarschall 233
 
517 daniel-mar 234
        /* add OID property key */
235
 
236
        sprintf(szScope, "%s %s", category, component);
237
        hash = djb2(szScope);
238
        // max 47 chars ("1.3.6.1.4.1.37476.2.72.1.4294967295.4294967295\0")
239
        sprintf(szOID, "1.3.6.1.4.1.37476.2.72.1.%lu.%lu", hash, componentVersion);
240
 
241
        prop->vendorID = kViaThinkSoftSignature;
242
        prop->propertyKey = PIOIDProperty;
243
        prop->propertyID = 0;
244
        prop->propertyLength = (SPInt32)roundToNext4(strlen(szOID) + 1);
245
        memset(prop->propertyData, 0x00, prop->propertyLength); // fill padding with 00h bytes (cosmetics)
246
        strcpy((char*)prop->propertyData, szOID);
247
        p += offsetof(PIProperty, propertyData) + prop->propertyLength; // skip past new property record, and any padding
248
        prop = (PIProperty*)p;
249
 
247 daniel-mar 250
        /* add HasTerminology property key */
184 dmarschall 251
 
247 daniel-mar 252
        hstm = (struct hstm_data*)prop->propertyData;
212 daniel-mar 253
 
247 daniel-mar 254
        #ifdef ENABLE_APPLESCRIPT
255
        // If the uniqueString/scope is set, the plugin will only communicate with Photoshop.
256
        // Otherwise it can be accessed with AppleScript, but the AETE keys need to be unique then.
257
        // This is achieved with getAeteKey().
258
        scopelen = 0;
259
        hstm->scope[0] = '\0';
260
        #else
261
        // Construct scope string by concatenating Category and Title - hopefully unique!
262
        // Note: In doresources() we malloc'ed 300h additional bytes,
263
        // and in the build dialog, title and category are size-limited,
264
        // so we can write here without malloc.
424 daniel-mar 265
        scopelen = strlen(&szScope);
266
        memcpy(&hstm->scope, &szScope, scopelen);
247 daniel-mar 267
        #endif
184 dmarschall 268
 
247 daniel-mar 269
        /* make up a new event ID for this aete, based on printable base-95 hash of scope */
270
        *event_id = printablehash(hash); /* this is used by aete_generate() later... */
184 dmarschall 271
 
247 daniel-mar 272
        prop->vendorID = kPhotoshopSignature;
273
        prop->propertyKey = PIHasTerminologyProperty;
274
        prop->propertyID = 0;
184 dmarschall 275
 
247 daniel-mar 276
        realLength = offsetof(struct hstm_data, scope) + scopelen + 1/*null-term*/;
277
        roundedLength = roundToNext4(realLength);
278
        prop->propertyLength = (SPInt32)roundedLength;
279
        memset(prop->propertyData + realLength, 0x00, roundedLength - realLength); // fill padding with 00h bytes (cosmetics)
218 daniel-mar 280
 
247 daniel-mar 281
        hstm->version = 0;
282
        hstm->class_id = plugInClassID;
283
        hstm->event_id = *event_id;
284
        hstm->aete_resid = AETE_ID;
184 dmarschall 285
 
247 daniel-mar 286
        p += offsetof(PIProperty, propertyData) + prop->propertyLength;
184 dmarschall 287
 
247 daniel-mar 288
        return p - (char*)pipl;  // figure how many bytes were added
184 dmarschall 289
}
290
 
187 dmarschall 291
void _aete_write_byte(void** aeteptr, uint8_t val) {
247 daniel-mar 292
        uint8_t* tmp = *((uint8_t**)aeteptr);
293
        *tmp = val;
294
        *aeteptr = (void*)((unsigned char*)tmp + 1);
187 dmarschall 295
}
296
#define AETE_WRITE_BYTE(i) _aete_write_byte(&aeteptr, (i));
184 dmarschall 297
 
187 dmarschall 298
void _aete_write_word(void** aeteptr, uint16_t val) {
247 daniel-mar 299
        uint16_t* tmp = *((uint16_t**)aeteptr);
300
        *tmp = val;
301
        *aeteptr = (void*)((unsigned char*)tmp + 2);
187 dmarschall 302
}
303
#define AETE_WRITE_WORD(i) _aete_write_word(&aeteptr, (i));
304
 
305
void _aete_write_dword(void** aeteptr, uint32_t val) {
247 daniel-mar 306
        uint32_t* tmp = *((uint32_t**)aeteptr);
307
        *tmp = val;
308
        *aeteptr = (void*)((unsigned char*)tmp + 4);
187 dmarschall 309
}
310
#define AETE_WRITE_DWORD(i) _aete_write_dword(&aeteptr, (i));
311
 
229 daniel-mar 312
void _aete_write_c2pstr(void** aeteptr, char* str) {
247 daniel-mar 313
        char* tmp;
187 dmarschall 314
 
247 daniel-mar 315
        assert(strlen(str) <= 255);
187 dmarschall 316
 
247 daniel-mar 317
        _aete_write_byte(aeteptr, (uint8_t)strlen(str));
187 dmarschall 318
 
247 daniel-mar 319
        tmp = *((char**)aeteptr);
320
        strcpy(tmp, str);
321
        *aeteptr = (void*)((unsigned char*)tmp + strlen(str));
187 dmarschall 322
}
498 daniel-mar 323
#define AETE_WRITE_C2PSTR(s) _aete_write_c2pstr(&aeteptr, (char*)(s));
268 daniel-mar 324
 
229 daniel-mar 325
void _aete_write_p2pstr(void** aeteptr, char* str) {
312 daniel-mar 326
        char* tmp;
187 dmarschall 327
 
312 daniel-mar 328
        if (strlen(str) == 0) {
329
                _aete_write_byte(aeteptr, 0);
330
        } else {
331
                tmp = *((char**)aeteptr);
332
                strcpy(tmp, str);
333
                *aeteptr = (void*)((unsigned char*)tmp + strlen(str));
334
        }
229 daniel-mar 335
}
336
#define AETE_WRITE_P2PSTR(s) _aete_write_p2pstr(&aeteptr, (s));
337
 
187 dmarschall 338
void _aete_align_word(void** aeteptr) {
247 daniel-mar 339
        #ifdef MAC_ENV
340
        unsigned char* tmp = *((unsigned char**)aeteptr);
341
        tmp += (intptr_t)tmp & 1;
342
        *aeteptr = (void*)tmp;
433 daniel-mar 343
        #else
344
        UNREFERENCED_PARAMETER(aeteptr);
247 daniel-mar 345
        #endif
187 dmarschall 346
}
347
#define AETE_ALIGN_WORD() _aete_align_word(&aeteptr);
348
 
185 dmarschall 349
void* _aete_property(void* aeteptr, PARM_T *pparm, int ctlidx, int mapidx, OSType key) {
247 daniel-mar 350
        char tmp[256];
185 dmarschall 351
 
247 daniel-mar 352
        if (pparm->ctl_used[ctlidx] || pparm->map_used[mapidx]) {
353
                if (pparm->map_used[mapidx]) {
354
                        if (ctlidx & 1) {
393 daniel-mar 355
                                sprintf(tmp, "... %s", pparm->szMap[mapidx]);
247 daniel-mar 356
                        } else {
393 daniel-mar 357
                                sprintf(tmp, "%s ...", pparm->szMap[mapidx]);
247 daniel-mar 358
                        }
359
                        AETE_WRITE_C2PSTR(tmp);
360
                } else {
393 daniel-mar 361
                        AETE_WRITE_C2PSTR(pparm->szCtl[ctlidx]);
247 daniel-mar 362
                }
363
                AETE_ALIGN_WORD();
364
                AETE_WRITE_DWORD(key);
365
                AETE_WRITE_DWORD(typeSInt32);
498 daniel-mar 366
                AETE_WRITE_C2PSTR("");
247 daniel-mar 367
                AETE_ALIGN_WORD();
368
                AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
369
        }
185 dmarschall 370
 
247 daniel-mar 371
        return aeteptr;
185 dmarschall 372
}
373
 
208 daniel-mar 374
size_t aete_generate(void* aeteptr, PARM_T *pparm, long event_id) {
247 daniel-mar 375
        int numprops;
376
        void *beginptr = aeteptr;
228 daniel-mar 377
 
247 daniel-mar 378
        // Attention!
379
        // - On some systems (e.g. ARM based CPUs) this will cause an unaligned memory access exception.
380
        //   For X86, memory access just becomes slower.
346 daniel-mar 381
        // - If you change something here, please also change it in scripting.rc (Windows) and scripting.r (Mac OS)
184 dmarschall 382
 
247 daniel-mar 383
        // Note:
384
        // - The 'aete' resource for Mac OS has word alignments after strings (but not if the next element is also a string)
385
        //   see https://developer.apple.com/library/archive/documentation/mac/pdf/Interapplication_Communication/AE_Term_Resources.pdf page 8-9
184 dmarschall 386
 
268 daniel-mar 387
        #ifdef WIN_ENV
247 daniel-mar 388
        AETE_WRITE_WORD(0x0001); /* Reserved (for Photoshop) */
268 daniel-mar 389
        #endif
390
 
247 daniel-mar 391
        AETE_WRITE_BYTE(0x01); /* aete version */
392
        AETE_WRITE_BYTE(0x00); /* aete version */
393
        AETE_WRITE_WORD(english); /* language specifiers */
394
        AETE_WRITE_WORD(roman);
395
        AETE_WRITE_WORD(1); /* 1 suite */
396
        {
393 daniel-mar 397
                AETE_WRITE_C2PSTR(pparm->szAuthor); /* vendor suite name */
498 daniel-mar 398
                AETE_WRITE_C2PSTR(""); /* optional description */
247 daniel-mar 399
                AETE_ALIGN_WORD();
400
                AETE_WRITE_DWORD(plugInSuiteID); /* suite ID */
401
                AETE_WRITE_WORD(1); /* suite code, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */
402
                AETE_WRITE_WORD(1); /* suite level, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */
403
                AETE_WRITE_WORD(1); /* 1 event (structure for filters) */
404
                {
393 daniel-mar 405
                        AETE_WRITE_C2PSTR(pparm->szTitle); /* event name */
498 daniel-mar 406
                        AETE_WRITE_C2PSTR(""); /* event description */
247 daniel-mar 407
                        AETE_ALIGN_WORD();
408
                        AETE_WRITE_DWORD(plugInClassID); /* event class */
409
                        AETE_WRITE_DWORD(/*plugInEventID*/event_id); /* event ID */
410
                        /* NO_REPLY: */
411
                        AETE_WRITE_DWORD(noReply); /* noReply='null' */
498 daniel-mar 412
                        AETE_WRITE_C2PSTR(""); /* reply description */
247 daniel-mar 413
                        AETE_ALIGN_WORD();
414
                        AETE_WRITE_WORD(0);
415
                        /* IMAGE_DIRECT_PARAM: */
416
                        AETE_WRITE_DWORD(typeImageReference); /* typeImageReference='#ImR' */
498 daniel-mar 417
                        AETE_WRITE_C2PSTR(""); /* direct parm description */
247 daniel-mar 418
                        AETE_ALIGN_WORD();
419
                        AETE_WRITE_WORD(0xB000);
184 dmarschall 420
 
247 daniel-mar 421
                        numprops = 0;
422
                        if (pparm->ctl_used[0] || pparm->map_used[0]) numprops++;
423
                        if (pparm->ctl_used[1] || pparm->map_used[0]) numprops++;
424
                        if (pparm->ctl_used[2] || pparm->map_used[1]) numprops++;
425
                        if (pparm->ctl_used[3] || pparm->map_used[1]) numprops++;
426
                        if (pparm->ctl_used[4] || pparm->map_used[2]) numprops++;
427
                        if (pparm->ctl_used[5] || pparm->map_used[2]) numprops++;
428
                        if (pparm->ctl_used[6] || pparm->map_used[3]) numprops++;
429
                        if (pparm->ctl_used[7] || pparm->map_used[3]) numprops++;
430
                        AETE_WRITE_WORD(numprops);
431
                        {
432
                                // Standalone filters don't need RGBA expressions
433
                                /*
498 daniel-mar 434
                                AETE_WRITE_C2PSTR("R");
247 daniel-mar 435
                                AETE_ALIGN_WORD();
436
                                AETE_WRITE_DWORD(PARAM_R_KEY);
437
                                AETE_WRITE_DWORD(typeText);
498 daniel-mar 438
                                AETE_WRITE_C2PSTR("R channel expression");
247 daniel-mar 439
                                AETE_ALIGN_WORD();
440
                                AETE_WRITE_WORD(0x8000);
184 dmarschall 441
 
498 daniel-mar 442
                                AETE_WRITE_C2PSTR("G");
247 daniel-mar 443
                                AETE_ALIGN_WORD();
444
                                AETE_WRITE_DWORD(PARAM_G_KEY);
445
                                AETE_WRITE_DWORD(typeText);
498 daniel-mar 446
                                AETE_WRITE_C2PSTR("G channel expression");
247 daniel-mar 447
                                AETE_ALIGN_WORD();
448
                                AETE_WRITE_WORD(0x8000);
184 dmarschall 449
 
498 daniel-mar 450
                                AETE_WRITE_C2PSTR("B");
247 daniel-mar 451
                                AETE_ALIGN_WORD();
452
                                AETE_WRITE_DWORD(PARAM_B_KEY);
453
                                AETE_WRITE_DWORD(typeText);
498 daniel-mar 454
                                AETE_WRITE_C2PSTR("B channel expression");
247 daniel-mar 455
                                AETE_ALIGN_WORD();
456
                                AETE_WRITE_WORD(0x8000);
184 dmarschall 457
 
498 daniel-mar 458
                                AETE_WRITE_C2PSTR("A");
247 daniel-mar 459
                                AETE_ALIGN_WORD();
460
                                AETE_WRITE_DWORD(PARAM_A_KEY);
461
                                AETE_WRITE_DWORD(typeText);
498 daniel-mar 462
                                AETE_WRITE_C2PSTR("A channel expression");
247 daniel-mar 463
                                AETE_ALIGN_WORD();
464
                                AETE_WRITE_WORD(0x8000);
465
                                */
184 dmarschall 466
 
247 daniel-mar 467
                                aeteptr = _aete_property(aeteptr, pparm, 0, 0, getAeteKey('0', pparm));
468
                                aeteptr = _aete_property(aeteptr, pparm, 1, 0, getAeteKey('1', pparm));
469
                                aeteptr = _aete_property(aeteptr, pparm, 2, 1, getAeteKey('2', pparm));
470
                                aeteptr = _aete_property(aeteptr, pparm, 3, 1, getAeteKey('3', pparm));
471
                                aeteptr = _aete_property(aeteptr, pparm, 4, 2, getAeteKey('4', pparm));
472
                                aeteptr = _aete_property(aeteptr, pparm, 5, 2, getAeteKey('5', pparm));
473
                                aeteptr = _aete_property(aeteptr, pparm, 6, 3, getAeteKey('6', pparm));
474
                                aeteptr = _aete_property(aeteptr, pparm, 7, 3, getAeteKey('7', pparm));
475
                        }
476
                }
184 dmarschall 477
 
247 daniel-mar 478
                /* non-filter plug-in class here */
479
                AETE_WRITE_WORD(0); /* 0 classes */
480
                {}
481
                AETE_WRITE_WORD(0); /* 0 comparison ops (not supported) */
482
                {}
483
                AETE_WRITE_WORD(0); /* 0 enumerations */
484
                {}
485
        }
486
        AETE_WRITE_DWORD(0); /* padding (FIXME: do we need that? Adobe's Windows filters don't) */
184 dmarschall 487
 
247 daniel-mar 488
        return (unsigned char*)aeteptr - (unsigned char*)beginptr; // length of stuff written
184 dmarschall 489
}