Subversion Repositories filter_foundry

Rev

Rev 178 | Rev 185 | 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-2019 Toby Thain, toby@telegraphics.com.au
  4.  
  5.         This program is free software; you can redistribute it and/or modify
  6.         it under the terms of the GNU General Public License as published by
  7.         the Free Software Foundation; either version 2 of the License, or
  8.         (at your option) any later version.
  9.  
  10.         This program is distributed in the hope that it will be useful,
  11.         but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.         MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.         GNU General Public License for more details.
  14.  
  15.         You should have received a copy of the GNU General Public License
  16.         along with this program; if not, write to the Free Software
  17.         Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  18. */
  19.  
  20. #include <stddef.h>
  21. #include <stdint.h>
  22.  
  23. #include "ff.h"
  24. #include "symtab.h"
  25.  
  26. #include "PIActions.h"
  27. #include "PITerminology.h"
  28.  
  29. #include "compat_string.h"
  30.  
  31. long event_id;
  32.  
  33. /*
  34. Find a printable 4-character key, remembering (see PS API guide):
  35. All IDs starting with an uppercase letter are reserved by Adobe.
  36. All IDs that are all uppercase are reserved by Apple.
  37. All IDs that are all lowercase are reserved by Apple.
  38. This leaves all IDs that begin with a lowercase letter and have at least
  39. one uppercase letter for you and other plug-in developers.
  40. */
  41. unsigned long printablehash(unsigned long hash) {
  42.         unsigned long key = 'a' + (hash % 26);  hash /= 26; // first lower case
  43.         key = (key << 8) | (' ' + (hash % 95)); hash /= 95; // any printable
  44.         key = (key << 8) | (' ' + (hash % 95)); hash /= 95; // any printable
  45.         return  (key << 8) | ('A' + (hash % 26));             // last upper case
  46. }
  47.  
  48. long roundToNext4(long x) {
  49.         int pad = 4 - (x % 4);
  50.         if (pad == 0) pad = 4;
  51.         return x + pad;
  52. }
  53.  
  54. long fixpipl(PIPropertyList *pipl, long origsize, StringPtr title) {
  55.         PIProperty *prop;
  56.         char *p;
  57.         struct hstm_data {
  58.                 /* this structure must be 14+1 bytes long, to match PiPL structure */
  59.                 long version; /* = 0 */
  60.                 long class_id;
  61.                 long event_id;
  62.                 short aete_resid;
  63.                 char scope[1];
  64.         };
  65.         struct hstm_data *hstm;
  66.         int scopelen;
  67.         unsigned long hash;
  68.  
  69.         pipl->count += 3; // 3 more keys in PiPL: name, catg, hstm
  70.  
  71.         p = (char*)pipl + origsize;
  72.         prop = (PIProperty*)p;
  73.  
  74.         /* add Title/Name property key */
  75.  
  76.         prop->vendorID = kPhotoshopSignature;
  77.         prop->propertyKey = PINameProperty;
  78.         prop->propertyID = 0;
  79.         prop->propertyLength = roundToNext4(title[0] + 1);
  80.         PLstrcpy((StringPtr)prop->propertyData, title);
  81.  
  82.         // skip past new property record, and any padding
  83.         p += offsetof(PIProperty, propertyData) + prop->propertyLength;
  84.         prop = (PIProperty*)p;
  85.  
  86.         /* add Category property key */
  87.  
  88.         prop->vendorID = kPhotoshopSignature;
  89.         prop->propertyKey = PICategoryProperty;
  90.         prop->propertyID = 0;
  91.         prop->propertyLength = roundToNext4(gdata->parm.category[0] + 1);
  92.         PLstrcpy((StringPtr)prop->propertyData, gdata->parm.category);
  93.  
  94.         p += offsetof(PIProperty, propertyData) + prop->propertyLength;
  95.         prop = (PIProperty*)p;
  96.  
  97.         /* add HasTerminology property key */
  98.  
  99.         /* construct scope string by concatenating Category and Title - hopefully unique! */
  100.         hstm = (struct hstm_data*)prop->propertyData;
  101.         scopelen = sprintf(hstm->scope, "%s %s",
  102.                 INPLACEP2CSTR(gdata->parm.category),
  103.                 INPLACEP2CSTR(title));
  104.  
  105.         /* make up a new event ID for this aete, based on printable base-95 hash of scope */
  106.         hash = djb2(hstm->scope);
  107.         event_id = printablehash(hash); /* this is used by fixaete() later... */
  108.  
  109.         prop->vendorID = kPhotoshopSignature;
  110.         prop->propertyKey = PIHasTerminologyProperty;
  111.         prop->propertyID = 0;
  112.         prop->propertyLength = roundToNext4(offsetof(struct hstm_data, scope) + scopelen);
  113.  
  114.         hstm->version = 0;
  115.         hstm->class_id = plugInClassID;
  116.         hstm->event_id = event_id;
  117.         hstm->aete_resid = AETE_ID;
  118.  
  119.         p += offsetof(PIProperty, propertyData) + prop->propertyLength;
  120.  
  121.         return p - (char*)pipl;  // figure how many bytes were added
  122. }
  123.  
  124. #define AETE_WRITE_BYTE(i) *((int8_t*)aeteptr) = (i); (byte*)aeteptr += 1
  125. #define AETE_WRITE_WORD(i) *((int16_t*)aeteptr) = (i); (byte*)aeteptr += 2
  126. #define AETE_WRITE_DWORD(i) *((int32_t*)aeteptr) = (i); (byte*)aeteptr += 4
  127. #define AETE_WRITE_STR(s) *((int8_t*)aeteptr) = strlen(s); (byte*)aeteptr += 1; strcpy((char*)aeteptr, s); (byte*)aeteptr += strlen(s)
  128. #ifdef MAC_ENV
  129. #define AETE_ALIGN_WORD() (byte*)aeteptr += (intptr_t)aeteptr & 1
  130. #else
  131. #define AETE_ALIGN_WORD() /*nothing*/
  132. #endif
  133.  
  134. long aete_generate(void* aeteptr, PARM_T *pparm) {
  135.         int numprops;
  136.         void *beginptr = aeteptr;
  137.  
  138.         // Attention!
  139.         // - On some systems (ARM) this will cause unaligned memory access exception.
  140.         //   For X86, memory access just becomes slower.
  141.         // - If you change something here, please also change it in PiPL.rc (Windows) and scripting.r (Mac OS)
  142.  
  143.         // Note:
  144.         // - The 'aete' resource for Mac OS has word alignments after strings (but not if the next element is also a string)
  145.         //   see https://developer.apple.com/library/archive/documentation/mac/pdf/Interapplication_Communication/AE_Term_Resources.pdf page 8-9
  146.  
  147. #ifdef WIN_ENV
  148.         AETE_WRITE_WORD(0x0001); /* Reserved (for Photoshop) */
  149. #endif
  150.         AETE_WRITE_BYTE(0x01); /* aete version */
  151.         AETE_WRITE_BYTE(0x00); /* aete version */
  152.         AETE_WRITE_WORD(english); /* language specifiers */
  153.         AETE_WRITE_WORD(roman);
  154.         AETE_WRITE_WORD(1); /* 1 suite */
  155.         {
  156.                 AETE_WRITE_STR(/*"Telegraphics"*/(char*)pparm->author); /* vendor suite name */
  157.                 AETE_WRITE_STR(/*""*/(char*)pparm->title); /* optional description */
  158.                 AETE_ALIGN_WORD();
  159.                 AETE_WRITE_DWORD(plugInSuiteID); /* suite ID */
  160.                 AETE_WRITE_WORD(1); /* suite code, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */
  161.                 AETE_WRITE_WORD(1); /* suite level, must be 1. Attention: Filters like 'Pointillize' have set this to 0! */
  162.                 AETE_WRITE_WORD(1); /* 1 event (structure for filters) */
  163.                 {
  164.                         AETE_WRITE_STR("FilterFoundry"); /* event name */
  165.                         AETE_WRITE_STR(""); /* event description */
  166.                         AETE_ALIGN_WORD();
  167.                         AETE_WRITE_DWORD(plugInClassID); /* event class */
  168.                         AETE_WRITE_DWORD(/*plugInEventID*/event_id); /* event ID */
  169.                         /* NO_REPLY: */
  170.                         AETE_WRITE_DWORD(noReply); /* noReply='null' */
  171.                         AETE_WRITE_STR(""); /* reply description */
  172.                         AETE_ALIGN_WORD();
  173.                         AETE_WRITE_WORD(0);
  174.                         /* IMAGE_DIRECT_PARAM: */
  175.                         AETE_WRITE_DWORD(typeImageReference); /* '#ImR' */
  176.                         AETE_WRITE_STR(""); /* direct parm description */
  177.                         AETE_ALIGN_WORD();
  178.                         AETE_WRITE_WORD(0xB000);
  179.  
  180.                         numprops = 0;
  181.                         if (pparm->ctl_used[0] || pparm->map_used[0]) numprops++;
  182.                         if (pparm->ctl_used[1] || pparm->map_used[0]) numprops++;
  183.                         if (pparm->ctl_used[2] || pparm->map_used[1]) numprops++;
  184.                         if (pparm->ctl_used[3] || pparm->map_used[1]) numprops++;
  185.                         if (pparm->ctl_used[4] || pparm->map_used[2]) numprops++;
  186.                         if (pparm->ctl_used[5] || pparm->map_used[2]) numprops++;
  187.                         if (pparm->ctl_used[6] || pparm->map_used[3]) numprops++;
  188.                         if (pparm->ctl_used[7] || pparm->map_used[3]) numprops++;
  189.                         AETE_WRITE_WORD(numprops);
  190.                         {
  191.                                 // Standalone filters don't need RGBA expressions
  192.                                 /*
  193.                                 AETE_WRITE_STR("R");
  194.                                 AETE_ALIGN_WORD();
  195.                                 AETE_WRITE_DWORD(PARAM_R_KEY);
  196.                                 AETE_WRITE_DWORD(typeText);
  197.                                 AETE_WRITE_STR("R channel expression");
  198.                                 AETE_ALIGN_WORD();
  199.                                 AETE_WRITE_WORD(0x8000);
  200.  
  201.                                 AETE_WRITE_STR("G");
  202.                                 AETE_ALIGN_WORD();
  203.                                 AETE_WRITE_DWORD(PARAM_G_KEY);
  204.                                 AETE_WRITE_DWORD(typeText);
  205.                                 AETE_WRITE_STR("G channel expression");
  206.                                 AETE_ALIGN_WORD();
  207.                                 AETE_WRITE_WORD(0x8000);
  208.  
  209.                                 AETE_WRITE_STR("B");
  210.                                 AETE_ALIGN_WORD();
  211.                                 AETE_WRITE_DWORD(PARAM_B_KEY);
  212.                                 AETE_WRITE_DWORD(typeText);
  213.                                 AETE_WRITE_STR("B channel expression");
  214.                                 AETE_ALIGN_WORD();
  215.                                 AETE_WRITE_WORD(0x8000);
  216.  
  217.                                 AETE_WRITE_STR("A");
  218.                                 AETE_ALIGN_WORD();
  219.                                 AETE_WRITE_DWORD(PARAM_A_KEY);
  220.                                 AETE_WRITE_DWORD(typeText);
  221.                                 AETE_WRITE_STR("A channel expression");
  222.                                 AETE_ALIGN_WORD();
  223.                                 AETE_WRITE_WORD(0x8000);
  224.                                 */
  225.  
  226.                                 if (pparm->ctl_used[0] || pparm->map_used[0]) {
  227.                                         AETE_WRITE_STR(/*"ctl0"*/pparm->map_used[0] ? (char*)pparm->map[0] : (char*)pparm->ctl[0]);
  228.                                         AETE_ALIGN_WORD();
  229.                                         AETE_WRITE_DWORD(PARAM_CTL0_KEY);
  230.                                         AETE_WRITE_DWORD(typeSInt32);
  231.                                         AETE_WRITE_STR("ctl(0) setting");
  232.                                         AETE_ALIGN_WORD();
  233.                                         AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
  234.                                 }
  235.  
  236.                                 if (pparm->ctl_used[1] || pparm->map_used[0]) {
  237.                                         AETE_WRITE_STR(/*"ctl1"*/pparm->map_used[0] ? (char*)pparm->map[0] : (char*)pparm->ctl[1]);
  238.                                         AETE_ALIGN_WORD();
  239.                                         AETE_WRITE_DWORD(PARAM_CTL1_KEY);
  240.                                         AETE_WRITE_DWORD(typeSInt32);
  241.                                         AETE_WRITE_STR("ctl(1) setting");
  242.                                         AETE_ALIGN_WORD();
  243.                                         AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
  244.                                 }
  245.  
  246.                                 if (pparm->ctl_used[2] || pparm->map_used[1]) {
  247.                                         AETE_WRITE_STR(/*"ctl2"*/pparm->map_used[1] ? (char*)pparm->map[1] : (char*)pparm->ctl[2]);
  248.                                         AETE_ALIGN_WORD();
  249.                                         AETE_WRITE_DWORD(PARAM_CTL2_KEY);
  250.                                         AETE_WRITE_DWORD(typeSInt32);
  251.                                         AETE_WRITE_STR("ctl(2) setting");
  252.                                         AETE_ALIGN_WORD();
  253.                                         AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
  254.                                 }
  255.  
  256.                                 if (pparm->ctl_used[3] || pparm->map_used[1]) {
  257.                                         AETE_WRITE_STR(/*"ctl3"*/pparm->map_used[1] ? (char*)pparm->map[1] : (char*)pparm->ctl[3]);
  258.                                         AETE_ALIGN_WORD();
  259.                                         AETE_WRITE_DWORD(PARAM_CTL3_KEY);
  260.                                         AETE_WRITE_DWORD(typeSInt32);
  261.                                         AETE_WRITE_STR("ctl(3) setting");
  262.                                         AETE_ALIGN_WORD();
  263.                                         AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
  264.                                 }
  265.  
  266.                                 if (pparm->ctl_used[4] || pparm->map_used[2]) {
  267.                                         AETE_WRITE_STR(/*"ctl4"*/pparm->map_used[2] ? (char*)pparm->map[2] : (char*)pparm->ctl[4]);
  268.                                         AETE_ALIGN_WORD();
  269.                                         AETE_WRITE_DWORD(PARAM_CTL4_KEY);
  270.                                         AETE_WRITE_DWORD(typeSInt32);
  271.                                         AETE_WRITE_STR("ctl(4) setting");
  272.                                         AETE_ALIGN_WORD();
  273.                                         AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
  274.                                 }
  275.  
  276.                                 if (pparm->ctl_used[5] || pparm->map_used[2]) {
  277.                                         AETE_WRITE_STR(/*"ctl5"*/pparm->map_used[2] ? (char*)pparm->map[2] : (char*)pparm->ctl[5]);
  278.                                         AETE_ALIGN_WORD();
  279.                                         AETE_WRITE_DWORD(PARAM_CTL5_KEY);
  280.                                         AETE_WRITE_DWORD(typeSInt32);
  281.                                         AETE_WRITE_STR("ctl(5) setting");
  282.                                         AETE_ALIGN_WORD();
  283.                                         AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
  284.                                 }
  285.  
  286.                                 if (pparm->ctl_used[6] || pparm->map_used[3]) {
  287.                                         AETE_WRITE_STR(/*"ctl6"*/pparm->map_used[3] ? (char*)pparm->map[3] : (char*)pparm->ctl[6]);
  288.                                         AETE_ALIGN_WORD();
  289.                                         AETE_WRITE_DWORD(PARAM_CTL6_KEY);
  290.                                         AETE_WRITE_DWORD(typeSInt32);
  291.                                         AETE_WRITE_STR("ctl(6) setting");
  292.                                         AETE_ALIGN_WORD();
  293.                                         AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
  294.                                 }
  295.  
  296.                                 if (pparm->ctl_used[7] || pparm->map_used[3]) {
  297.                                         AETE_WRITE_STR(/*"ctl7"*/pparm->map_used[3] ? (char*)pparm->map[3] : (char*)pparm->ctl[7]);
  298.                                         AETE_ALIGN_WORD();
  299.                                         AETE_WRITE_DWORD(PARAM_CTL7_KEY);
  300.                                         AETE_WRITE_DWORD(typeSInt32);
  301.                                         AETE_WRITE_STR("ctl(7) setting");
  302.                                         AETE_ALIGN_WORD();
  303.                                         AETE_WRITE_WORD(0x8000); /* FLAGS_1_OPT_PARAM / flagsOptionalSingleParameter */
  304.                                 }
  305.                         }
  306.                 }
  307.  
  308.                 /* non-filter plug-in class here */
  309.                 AETE_WRITE_WORD(0); /* 0 classes */
  310.                 {}
  311.                 AETE_WRITE_WORD(0); /* 0 comparison ops (not supported) */
  312.                 {}
  313.                 AETE_WRITE_WORD(0); /* 0 enumerations */
  314.                 {}
  315.         }
  316.         AETE_WRITE_DWORD(0); /* padding */
  317.  
  318.         return (byte*)aeteptr - (byte*)beginptr; // length of stuff written
  319. }
  320.  
  321. void obfusc(unsigned char *pparm, size_t size) {
  322.         int i;
  323.         unsigned char *p;
  324.         uint32_t x32;
  325.  
  326.         x32 = 0x95D4A68F; // Hardcoded seed
  327.         for (i = size, p = pparm; i--;) {
  328.                 // https://de.wikipedia.org/wiki/Xorshift
  329.                 *p++ ^= (x32 ^= (x32 ^= (x32 ^= x32 << 13) >> 17) << 5);
  330.         }
  331. }
  332.