Subversion Repositories filter_foundry

Rev

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

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