Subversion Repositories filter_foundry

Rev

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