Subversion Repositories filter_foundry

Rev

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