Subversion Repositories filter_foundry

Rev

Rev 276 | Rev 312 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  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
  5.  
  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.
  10.  
  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.
  15.  
  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
  19. */
  20.  
  21. #include <stddef.h>
  22. #include <stdint.h>
  23. #include <assert.h>
  24. #include <time.h>
  25.  
  26. #include "ff.h"
  27. #include "symtab.h"
  28.  
  29. #include "scripting.h"
  30. #include "PIActions.h"
  31. #include "PITerminology.h"
  32.  
  33. #include "compat_string.h"
  34.  
  35. //#define PRINTABLE_HASH_FF16
  36. #define ENABLE_APPLESCRIPT
  37.  
  38. const volatile uint32_t cObfuscV4Seed = 0x52830517; // this value will be manipulated during the building of each individual filter (see make_win.c)
  39.  
  40. /*
  41. Find a printable 4-character key, remembering (see Photoshop API guide):
  42. - All IDs starting with an uppercase letter are reserved by Adobe.
  43. - All IDs that are all uppercase are reserved by Apple.
  44. - All IDs that are all lowercase are reserved by Apple.
  45. - This leaves all IDs that begin with a lowercase letter and have at least
  46.   one uppercase letter for you and other plug-in developers.
  47. Note: It is questionable if "a!!!" or "A!!!" are also reseved by Apple. We don't risk it.
  48. */
  49. unsigned long printablehash(unsigned long hash) {
  50.         #ifdef PRINTABLE_HASH_FF16
  51.  
  52.         // FilterFoundry version 1.6 hashing by Toby Thain
  53.         // Only accepts upper case at the last character
  54.         // 0       = 'a  A'
  55.         // 6100899 = 'z~~Z'
  56.         unsigned long key = 'a' + (hash % 26);  hash /= 26; // first lower case
  57.         key = (key << 8) | (' ' + (hash % 95)); hash /= 95; // any printable
  58.         key = (key << 8) | (' ' + (hash % 95)); hash /= 95; // any printable
  59.         return  (key << 8) | ('A' + (hash % 26));           // last upper case
  60.  
  61.         #else
  62.  
  63.         // FilterFoundry version 1.7 hashing by Daniel Marschall
  64.         // Accepts upper case at character 2, 3 or 4
  65.         // Spaces are only set the right as padding to make a code shorter
  66.         // 0        = 'aA  '
  67.         // 13530139 = 'zZZZ'
  68.         // The key-space is ~2.22 times larger
  69.         long lowlim;
  70.         long uplim;
  71.         int upperCaseInfo;
  72.         int length;
  73.         int lastThreeCharInfo;
  74.         int firstChar;
  75.         unsigned long key;
  76.         int found;
  77.         int i,j,k;
  78.  
  79.         uplim = 0;
  80.         for (k=1; k<4; k++) {
  81.                 int mask;
  82.                 if (k == 1) mask = 1;//0b1;
  83.                 if (k == 2) mask = 2;//0b11;
  84.                 if (k == 3) mask = 4;//0b111;
  85.                 for (i=1; i<=mask; i++) {
  86.                         // 'k' characters
  87.                         long test = 1;
  88.                         for (j=0; j<k; ++j) {
  89.                                 test *= ((i&(1<<j)) != 0) ? 26 : 94-26;
  90.                         }
  91.                         uplim += test;
  92.                 }
  93.         }
  94.  
  95.         lastThreeCharInfo = hash % uplim; hash /= uplim;
  96.         firstChar = hash%26; hash /= 26;
  97.  
  98.         lowlim = 0;
  99.         uplim = 0;
  100.         found = 0;
  101.         length = -1; // avoid compiler warning
  102.         upperCaseInfo = -1; // avoid compiler warning
  103.         for (k=1; k<4; k++) {
  104.                 int mask;
  105.                 if (k == 1) mask = 1;//0b1;
  106.                 if (k == 2) mask = 2;//0b11;
  107.                 if (k == 3) mask = 4;//0b111;
  108.                 if (!found) for (i=1; i<=mask; i++) {
  109.                         // 'k' characters
  110.                         long test = 1;
  111.                         for (j=0; j<k; ++j) {
  112.                                 test *= ((i&(1<<j)) != 0) ? 26 : 94-26;
  113.                         }
  114.                         uplim += test;
  115.                         if ((lastThreeCharInfo >= lowlim) && (lastThreeCharInfo < uplim)) {
  116.                                 lastThreeCharInfo -= lowlim;
  117.                                 found = 1;
  118.                                 length = k;
  119.                                 upperCaseInfo = i;
  120.                                 break;
  121.                         }
  122.                         lowlim = uplim;
  123.                 }
  124.         }
  125.  
  126.         key = ('a' + firstChar) << 24; // first char is lower-case
  127.         for (i=0; i<length; ++i) {
  128.                 char res;
  129.                 if ((upperCaseInfo&(1<<i)) == 0) {
  130.                         res = '!' + (lastThreeCharInfo % (94-26));
  131.                         if (res >= 'A') res += 26;
  132.                         lastThreeCharInfo /= (94-26);
  133.                 } else {
  134.                         res = 'A' + (lastThreeCharInfo % 26);
  135.                         lastThreeCharInfo /= 26;
  136.                 }
  137.                 key |= res << (8*(i+(4-length-1))); // 2nd, 3rd, 4th char are either upper-case or any printable char
  138.         }
  139.         if (length == 1) {
  140.                 key &= 0xFFFF0000;
  141.                 key |= ' ' << 8;
  142.                 key |= ' ';
  143.         }
  144.         if (length == 2) {
  145.                 key &= 0xFFFFFF00;
  146.                 key |= ' ';
  147.         }
  148.         return key;
  149.  
  150.         #endif
  151. }
  152.  
  153. size_t roundToNext4(size_t x) {
  154.         int pad = 4 - (x % 4);
  155.         if (pad == 0) pad = 4;
  156.         return x + pad;
  157. }
  158.  
  159. size_t fixpipl(PIPropertyList *pipl, size_t origsize, StringPtr title, long *event_id) {
  160.         PIProperty *prop;
  161.         char *p;
  162.         struct hstm_data {
  163.                 /* this structure must be 14+1 bytes long, to match PiPL structure */
  164.                 long version; /* = 0 */
  165.                 long class_id;
  166.                 long event_id;
  167.                 short aete_resid;
  168.                 char scope[1];
  169.         };
  170.         struct hstm_data *hstm;
  171.         int scopelen;
  172.         unsigned long hash;
  173.         size_t realLength;
  174.         size_t roundedLength;
  175.         char* scope;
  176.  
  177.         pipl->count += 3; // 3 more keys in PiPL: name, catg, hstm
  178.  
  179.         p = (char*)pipl + origsize;
  180.         prop = (PIProperty*)p;
  181.  
  182.         /* add Title/Name property key */
  183.  
  184.         prop->vendorID = kPhotoshopSignature;
  185.         prop->propertyKey = PINameProperty;
  186.         prop->propertyID = 0;
  187.         prop->propertyLength = (SPInt32)roundToNext4((size_t)title[0] + 1);
  188.         memset(prop->propertyData, 0x00, prop->propertyLength); // fill padding with 00h bytes (cosmetics)
  189.         PLstrcpy((StringPtr)prop->propertyData, title);
  190.  
  191.         // skip past new property record, and any padding
  192.         p += offsetof(PIProperty, propertyData) + prop->propertyLength;
  193.         prop = (PIProperty*)p;
  194.  
  195.         /* add Category property key */
  196.  
  197.         prop->vendorID = kPhotoshopSignature;
  198.         prop->propertyKey = PICategoryProperty;
  199.         prop->propertyID = 0;
  200.  
  201.         prop->propertyLength = (SPInt32)roundToNext4((size_t)gdata->parm.category[0] + 1);
  202.         memset(prop->propertyData, 0x00, prop->propertyLength); // fill padding with 00h bytes (cosmetics)
  203.         PLstrcpy((StringPtr)prop->propertyData, gdata->parm.category);
  204.  
  205.         p += offsetof(PIProperty, propertyData) + prop->propertyLength;
  206.         prop = (PIProperty*)p;
  207.  
  208.         /* add HasTerminology property key */
  209.  
  210.         hstm = (struct hstm_data*)prop->propertyData;
  211.  
  212.         scope = (char*)malloc(0x300);
  213.         if (!scope) return -1;
  214.         sprintf(scope, "%s %s",
  215.             INPLACEP2CSTR(gdata->parm.category),
  216.             INPLACEP2CSTR(title));
  217.  
  218.         #ifdef ENABLE_APPLESCRIPT
  219.         // If the uniqueString/scope is set, the plugin will only communicate with Photoshop.
  220.         // Otherwise it can be accessed with AppleScript, but the AETE keys need to be unique then.
  221.         // This is achieved with getAeteKey().
  222.         scopelen = 0;
  223.         hstm->scope[0] = '\0';
  224.         #else
  225.         // Construct scope string by concatenating Category and Title - hopefully unique!
  226.         // Note: In doresources() we malloc'ed 300h additional bytes,
  227.         // and in the build dialog, title and category are size-limited,
  228.         // so we can write here without malloc.
  229.         scopelen = strlen(scope);
  230.         memcpy(&hstm->scope, scope, scopelen);
  231.         #endif
  232.  
  233.         /* make up a new event ID for this aete, based on printable base-95 hash of scope */
  234.         hash = djb2(scope);
  235.         *event_id = printablehash(hash); /* this is used by aete_generate() later... */
  236.  
  237.         prop->vendorID = kPhotoshopSignature;
  238.         prop->propertyKey = PIHasTerminologyProperty;
  239.         prop->propertyID = 0;
  240.  
  241.         realLength = offsetof(struct hstm_data, scope) + scopelen + 1/*null-term*/;
  242.         roundedLength = roundToNext4(realLength);
  243.         prop->propertyLength = (SPInt32)roundedLength;
  244.         memset(prop->propertyData + realLength, 0x00, roundedLength - realLength); // fill padding with 00h bytes (cosmetics)
  245.  
  246.         hstm->version = 0;
  247.         hstm->class_id = plugInClassID;
  248.         hstm->event_id = *event_id;
  249.         hstm->aete_resid = AETE_ID;
  250.  
  251.         p += offsetof(PIProperty, propertyData) + prop->propertyLength;
  252.  
  253.         return p - (char*)pipl;  // figure how many bytes were added
  254. }
  255.  
  256. void _aete_write_byte(void** aeteptr, uint8_t val) {
  257.         uint8_t* tmp = *((uint8_t**)aeteptr);
  258.         *tmp = val;
  259.         *aeteptr = (void*)((unsigned char*)tmp + 1);
  260. }
  261. #define AETE_WRITE_BYTE(i) _aete_write_byte(&aeteptr, (i));
  262.  
  263. void _aete_write_word(void** aeteptr, uint16_t val) {
  264.         uint16_t* tmp = *((uint16_t**)aeteptr);
  265.         *tmp = val;
  266.         *aeteptr = (void*)((unsigned char*)tmp + 2);
  267. }
  268. #define AETE_WRITE_WORD(i) _aete_write_word(&aeteptr, (i));
  269.  
  270. void _aete_write_dword(void** aeteptr, uint32_t val) {
  271.         uint32_t* tmp = *((uint32_t**)aeteptr);
  272.         *tmp = val;
  273.         *aeteptr = (void*)((unsigned char*)tmp + 4);
  274. }
  275. #define AETE_WRITE_DWORD(i) _aete_write_dword(&aeteptr, (i));
  276.  
  277. void _aete_write_c2pstr(void** aeteptr, char* str) {
  278.         char* tmp;
  279.  
  280.         assert(strlen(str) <= 255);
  281.  
  282.         _aete_write_byte(aeteptr, (uint8_t)strlen(str));
  283.  
  284.         tmp = *((char**)aeteptr);
  285.         strcpy(tmp, str);
  286.         *aeteptr = (void*)((unsigned char*)tmp + strlen(str));
  287. }
  288. #define AETE_WRITE_C2PSTR(s) _aete_write_c2pstr(&aeteptr, (s));
  289.  
  290. void _aete_write_p2pstr(void** aeteptr, char* str) {
  291.     char* tmp;
  292.  
  293.     if (strlen(str) == 0) {
  294.         _aete_write_byte(aeteptr, 0);
  295.     } else {
  296.         tmp = *((char**)aeteptr);
  297.         strcpy(tmp, str);
  298.         *aeteptr = (void*)((unsigned char*)tmp + strlen(str));
  299.     }
  300. }
  301. #define AETE_WRITE_P2PSTR(s) _aete_write_p2pstr(&aeteptr, (s));
  302.  
  303. void _aete_align_word(void** aeteptr) {
  304.         #ifdef MAC_ENV
  305.         unsigned char* tmp = *((unsigned char**)aeteptr);
  306.         tmp += (intptr_t)tmp & 1;
  307.         *aeteptr = (void*)tmp;
  308.         #endif
  309. }
  310. #define AETE_ALIGN_WORD() _aete_align_word(&aeteptr);
  311.  
  312. void* _aete_property(void* aeteptr, PARM_T *pparm, int ctlidx, int mapidx, OSType key) {
  313.         char tmp[256];
  314.  
  315.         if (pparm->ctl_used[ctlidx] || pparm->map_used[mapidx]) {
  316.                 if (pparm->map_used[mapidx]) {
  317.                         if (ctlidx & 1) {
  318.                                 sprintf(tmp, "... %s", (char*)pparm->map[mapidx]);
  319.                         } else {
  320.                                 sprintf(tmp, "%s ...", (char*)pparm->map[mapidx]);
  321.                         }
  322.                         AETE_WRITE_C2PSTR(tmp);
  323.                 } else {
  324.                         AETE_WRITE_P2PSTR((char*)pparm->ctl[ctlidx]);
  325.                 }
  326.                 AETE_ALIGN_WORD();
  327.                 AETE_WRITE_DWORD(key);
  328.                 AETE_WRITE_DWORD(typeSInt32);
  329.                 AETE_WRITE_C2PSTR(_strdup(""));
  330.                 AETE_ALIGN_WORD();
  331.                 AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
  332.         }
  333.  
  334.         return aeteptr;
  335. }
  336.  
  337. size_t aete_generate(void* aeteptr, PARM_T *pparm, long event_id) {
  338.         int numprops;
  339.         void *beginptr = aeteptr;
  340.  
  341.         // Attention!
  342.         // - On some systems (e.g. ARM based CPUs) this will cause an unaligned memory access exception.
  343.         //   For X86, memory access just becomes slower.
  344.         // - If you change something here, please also change it in Scripting.rc (Windows) and scripting.r (Mac OS)
  345.  
  346.         // Note:
  347.         // - The 'aete' resource for Mac OS has word alignments after strings (but not if the next element is also a string)
  348.         //   see https://developer.apple.com/library/archive/documentation/mac/pdf/Interapplication_Communication/AE_Term_Resources.pdf page 8-9
  349.  
  350.         #ifdef WIN_ENV
  351.         AETE_WRITE_WORD(0x0001); /* Reserved (for Photoshop) */
  352.         #endif
  353.  
  354.         AETE_WRITE_BYTE(0x01); /* aete version */
  355.         AETE_WRITE_BYTE(0x00); /* aete version */
  356.         AETE_WRITE_WORD(english); /* language specifiers */
  357.         AETE_WRITE_WORD(roman);
  358.         AETE_WRITE_WORD(1); /* 1 suite */
  359.         {
  360.                 AETE_WRITE_P2PSTR((char*)pparm->author); /* vendor suite name */
  361.                 AETE_WRITE_C2PSTR(_strdup("")); /* optional description */
  362.                 AETE_ALIGN_WORD();
  363.                 AETE_WRITE_DWORD(plugInSuiteID); /* suite ID */
  364.                 AETE_WRITE_WORD(1); /* suite code, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */
  365.                 AETE_WRITE_WORD(1); /* suite level, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */
  366.                 AETE_WRITE_WORD(1); /* 1 event (structure for filters) */
  367.                 {
  368.                         AETE_WRITE_P2PSTR((char*)pparm->title); /* event name */
  369.                         AETE_WRITE_C2PSTR(_strdup("")); /* event description */
  370.                         AETE_ALIGN_WORD();
  371.                         AETE_WRITE_DWORD(plugInClassID); /* event class */
  372.                         AETE_WRITE_DWORD(/*plugInEventID*/event_id); /* event ID */
  373.                         /* NO_REPLY: */
  374.                         AETE_WRITE_DWORD(noReply); /* noReply='null' */
  375.                         AETE_WRITE_C2PSTR(_strdup("")); /* reply description */
  376.                         AETE_ALIGN_WORD();
  377.                         AETE_WRITE_WORD(0);
  378.                         /* IMAGE_DIRECT_PARAM: */
  379.                         AETE_WRITE_DWORD(typeImageReference); /* typeImageReference='#ImR' */
  380.                         AETE_WRITE_C2PSTR(_strdup("")); /* direct parm description */
  381.                         AETE_ALIGN_WORD();
  382.                         AETE_WRITE_WORD(0xB000);
  383.  
  384.                         numprops = 0;
  385.                         if (pparm->ctl_used[0] || pparm->map_used[0]) numprops++;
  386.                         if (pparm->ctl_used[1] || pparm->map_used[0]) numprops++;
  387.                         if (pparm->ctl_used[2] || pparm->map_used[1]) numprops++;
  388.                         if (pparm->ctl_used[3] || pparm->map_used[1]) numprops++;
  389.                         if (pparm->ctl_used[4] || pparm->map_used[2]) numprops++;
  390.                         if (pparm->ctl_used[5] || pparm->map_used[2]) numprops++;
  391.                         if (pparm->ctl_used[6] || pparm->map_used[3]) numprops++;
  392.                         if (pparm->ctl_used[7] || pparm->map_used[3]) numprops++;
  393.                         AETE_WRITE_WORD(numprops);
  394.                         {
  395.                                 // Standalone filters don't need RGBA expressions
  396.                                 /*
  397.                                 AETE_WRITE_C2PSTR(_strdup("R"));
  398.                                 AETE_ALIGN_WORD();
  399.                                 AETE_WRITE_DWORD(PARAM_R_KEY);
  400.                                 AETE_WRITE_DWORD(typeText);
  401.                                 AETE_WRITE_C2PSTR(_strdup("R channel expression"));
  402.                                 AETE_ALIGN_WORD();
  403.                                 AETE_WRITE_WORD(0x8000);
  404.  
  405.                                 AETE_WRITE_C2PSTR(_strdup("G"));
  406.                                 AETE_ALIGN_WORD();
  407.                                 AETE_WRITE_DWORD(PARAM_G_KEY);
  408.                                 AETE_WRITE_DWORD(typeText);
  409.                                 AETE_WRITE_C2PSTR(_strdup("G channel expression"));
  410.                                 AETE_ALIGN_WORD();
  411.                                 AETE_WRITE_WORD(0x8000);
  412.  
  413.                                 AETE_WRITE_C2PSTR(_strdup("B"));
  414.                                 AETE_ALIGN_WORD();
  415.                                 AETE_WRITE_DWORD(PARAM_B_KEY);
  416.                                 AETE_WRITE_DWORD(typeText);
  417.                                 AETE_WRITE_C2PSTR(_strdup("B channel expression"));
  418.                                 AETE_ALIGN_WORD();
  419.                                 AETE_WRITE_WORD(0x8000);
  420.  
  421.                                 AETE_WRITE_C2PSTR(_strdup("A"));
  422.                                 AETE_ALIGN_WORD();
  423.                                 AETE_WRITE_DWORD(PARAM_A_KEY);
  424.                                 AETE_WRITE_DWORD(typeText);
  425.                                 AETE_WRITE_C2PSTR(_strdup("A channel expression"));
  426.                                 AETE_ALIGN_WORD();
  427.                                 AETE_WRITE_WORD(0x8000);
  428.                                 */
  429.  
  430.                                 aeteptr = _aete_property(aeteptr, pparm, 0, 0, getAeteKey('0', pparm));
  431.                                 aeteptr = _aete_property(aeteptr, pparm, 1, 0, getAeteKey('1', pparm));
  432.                                 aeteptr = _aete_property(aeteptr, pparm, 2, 1, getAeteKey('2', pparm));
  433.                                 aeteptr = _aete_property(aeteptr, pparm, 3, 1, getAeteKey('3', pparm));
  434.                                 aeteptr = _aete_property(aeteptr, pparm, 4, 2, getAeteKey('4', pparm));
  435.                                 aeteptr = _aete_property(aeteptr, pparm, 5, 2, getAeteKey('5', pparm));
  436.                                 aeteptr = _aete_property(aeteptr, pparm, 6, 3, getAeteKey('6', pparm));
  437.                                 aeteptr = _aete_property(aeteptr, pparm, 7, 3, getAeteKey('7', pparm));
  438.                         }
  439.                 }
  440.  
  441.                 /* non-filter plug-in class here */
  442.                 AETE_WRITE_WORD(0); /* 0 classes */
  443.                 {}
  444.                 AETE_WRITE_WORD(0); /* 0 comparison ops (not supported) */
  445.                 {}
  446.                 AETE_WRITE_WORD(0); /* 0 enumerations */
  447.                 {}
  448.         }
  449.         AETE_WRITE_DWORD(0); /* padding (FIXME: do we need that? Adobe's Windows filters don't) */
  450.  
  451.         return (unsigned char*)aeteptr - (unsigned char*)beginptr; // length of stuff written
  452. }
  453.  
  454. int rand_msvcc(unsigned int* seed) {
  455.         *seed = *seed * 214013L + 2531011L;
  456.         return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */
  457. }
  458.  
  459. int rand_openwatcom(unsigned int* seed) {
  460.         // https://github.com/open-watcom/open-watcom-v2/blob/master/bld/clib/math/c/rand.c
  461.         *seed = *seed * 1103515245L + 12345L;
  462.         return (*seed >> 16) & 0x7fff; /* Scale between 0 and RAND_MAX */
  463. }
  464.  
  465. void _xorshift(unsigned char** p, uint32_t* x32, size_t num) {
  466.         size_t i;
  467.         unsigned char* x = *p;
  468.         for (i = 0; i < num; i++) {
  469.                 // https://de.wikipedia.org/wiki/Xorshift
  470.                 *x32 ^= *x32 << 13;
  471.                 *x32 ^= *x32 >> 17;
  472.                 *x32 ^= *x32 << 5;
  473.                 *x++ ^= *x32;
  474.         }
  475.         *p = x;
  476. }
  477.  
  478. void obfusc(PARM_T* pparm, unsigned int seed) {
  479.         unsigned char* p;
  480.         size_t size, seed_position;
  481.  
  482.         seed_position = offsetof(PARM_T, unknown2);
  483.         size = sizeof(PARM_T);
  484.  
  485.         // Version 4 obfuscation
  486.         // Filter Foundry >= 1.7.0.7
  487.  
  488.         p = (unsigned char*)pparm;
  489.         _xorshift(&p, &seed, seed_position);
  490.         *((unsigned int*)p) = 4; // Obfusc V4 info
  491.         p += 4;
  492.         _xorshift(&p, &seed, size - seed_position - 4);
  493. }
  494.  
  495. void deobfusc(PARM_T* pparm) {
  496.         unsigned char* p;
  497.         size_t i;
  498.         unsigned int seed;
  499.         size_t size, seed_position;
  500.  
  501.         seed_position = offsetof(PARM_T, unknown2); // = offsetof(PARM_T_PREMIERE, unknown1)
  502.         size = sizeof(PARM_T);
  503.  
  504.         seed = pparm->unknown2;
  505.  
  506.         if (seed == 0x90E364A3) { // A3 64 E3 90
  507.                 // Version 1 obfuscation, filter built with VC++ (official release by Toby Thain)
  508.                 // Filter Foundry FF >= 1.4b8,9,10
  509.                 seed = 0xdc43df3c;
  510.                 for (i = size, p = (unsigned char*)pparm; i--;) {
  511.                         *p++ ^= rand_msvcc(&seed);
  512.                 }
  513.         }
  514.         else if (seed == 0xE2CFCA34) { // 34 CA CF E2
  515.                 // Version 2 obfuscation, compiler independent
  516.                 // Filter Foundry >= 1.7b1
  517.                 unsigned int x32 = 0x95d4a68f;
  518.                 for (i = size, p = (unsigned char*)pparm; i--;) {
  519.                         x32 ^= x32 << 13;
  520.                         x32 ^= x32 >> 17;
  521.                         x32 ^= x32 << 5;
  522.                         *p++ ^= x32;
  523.                 }
  524.         }
  525.         else if (seed == 4) { // 04 00 00 00
  526.                 // Version 4 obfuscation
  527.                 // Filter Foundry >= 1.7.0.7
  528.                 // Not compiler dependent, but individual for each build
  529.                 // It is important that this code works for both x86 and x64 indepdently from the used compiler,
  530.                 // otherwise, the cross-make x86/x64 won't work!
  531.                 uint32_t v4seed = cObfuscV4Seed; // this value will be manipulated during the building of each individual filter (see make_win.c)
  532.                 p = (unsigned char*)pparm;
  533.                 _xorshift(&p, &v4seed, seed_position);
  534.                 p += 4; // obfusc info == 4
  535.                 _xorshift(&p, &v4seed, size - seed_position - 4);
  536.  
  537.                 // Filter Foundry >= 1.7.0.5 builds combines obfuscation and protection
  538.                 // when a standalone filter is built. Theoretically, you can un-protect a
  539.                 // plugin, even if it is obfuscated, just by bit-flipping the LSB of byte 0x164.
  540.                 // Therefore, we enforce that the plugin is protected!
  541.                 // Note: We don't need to check PARM_T_PREMIERE, because only PARM_T
  542.                 //       can be obfuscated by FilterFoundry.
  543.                 pparm->iProtected = 1;
  544.         }
  545.         else {
  546.                 // Version 3 obfuscation
  547.                 // Filter Foundry >= 1.7.0.5
  548.                 // NO loading of other implementation supported, but that doesn't matter since Obfuscation+Protection is combined in FF >= 1.7.0.5
  549.                 // Using rand() is more secure, because it differs from compiler to compiler, so
  550.                 // it is harder to read a protected 8BF plugin.
  551.                 // Note that rand() in combination with srand() is deterministic, so it is safe
  552.                 // to use it: https://stackoverflow.com/questions/55438293/does-rand-function-in-c-follows-non-determinstc-algorithm
  553.                 // Note: 32-Bit FF is built using OpenWatcom (to support Win95), while 64-Bit FF is built using Microsoft Visual C++
  554.                 srand(seed);
  555.                 p = (unsigned char*)pparm;
  556.                 for (i = 0; i < seed_position; i++) *p++ ^= rand();
  557.                 *((unsigned int*)p) = 0; // here was the seed. Fill it with 0x00000000
  558.                 p += 4;
  559.                 for (i = 0; i < size - seed_position - 4; i++) *p++ ^= rand();
  560.  
  561.                 // Filter Foundry >= 1.7.0.5 builds combines obfuscation and protection
  562.                 // when a standalone filter is built. Theoretically, you can un-protect a
  563.                 // plugin, even if it is obfuscated, just by bit-flipping the LSB of byte 0x164.
  564.                 // Therefore, we enforce that the plugin is protected!
  565.                 // Note: We don't need to check PARM_T_PREMIERE, because only PARM_T
  566.                 //       can be obfuscated by FilterFoundry.
  567.                 pparm->iProtected = 1;
  568.         }
  569. }
  570.