Subversion Repositories filter_foundry

Rev

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

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