Subversion Repositories filter_foundry

Rev

Rev 511 | Rev 516 | Go to most recent revision | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

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