Subversion Repositories filter_foundry

Rev

Rev 557 | Only display areas with differences | Regard whitespace | Details | Blame | Last modification | View Log | RSS feed

Rev 557 Rev 559
1
/*
1
/*
2
    This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
2
    This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.net
3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.net
4
    Copyright (C) 2018-2023 Daniel Marschall, ViaThinkSoft
4
    Copyright (C) 2018-2023 Daniel Marschall, ViaThinkSoft
5
 
5
 
6
    This program is free software; you can redistribute it and/or modify
6
    This program is free software; you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation; either version 2 of the License, or
8
    the Free Software Foundation; either version 2 of the License, or
9
    (at your option) any later version.
9
    (at your option) any later version.
10
 
10
 
11
    This program is distributed in the hope that it will be useful,
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
14
    GNU General Public License for more details.
15
 
15
 
16
    You should have received a copy of the GNU General Public License
16
    You should have received a copy of the GNU General Public License
17
    along with this program; if not, write to the Free Software
17
    along with this program; if not, write to the Free Software
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
*/
19
*/
20
 
20
 
21
//#include <stdio.h>
21
//#include <stdio.h>
22
//#include <sound.h>
22
//#include <sound.h>
23
 
23
 
24
#include "ff.h"
24
#include "ff.h"
25
 
25
 
26
#include "str.h"
26
#include "str.h"
27
#include "node.h"
27
#include "node.h"
28
#include "funcs.h"
28
#include "funcs.h"
29
#include "y.tab.h"
29
#include "y.tab.h"
30
#include "scripting.h"
30
#include "scripting.h"
31
#include <math.h>
31
#include <math.h>
32
#include "PIBufferSuite.h"
32
#include "PIBufferSuite.h"
33
 
33
 
34
// GIMP (PSPI) and IrfanView preserve neither *data(gdata), nor pb->parameters between invocations!
34
// GIMP (PSPI) and IrfanView preserve neither *data(gdata), nor pb->parameters between invocations!
35
// For debugging, we can simulate it here
35
// For debugging, we can simulate it here
36
//#define DEBUG_SIMULATE_GIMP
36
//#define DEBUG_SIMULATE_GIMP
37
 
37
 
38
// Used to find out which host signatures and memory settings a plugin host has
38
// Used to find out which host signatures and memory settings a plugin host has
39
//#define SHOW_HOST_DEBUG
39
//#define SHOW_HOST_DEBUG
40
 
40
 
41
// Here are working variables:
41
// Here are working variables:
42
struct node *tree[4];
42
struct node *tree[4];
43
TCHAR *err[4];
43
TCHAR *err[4];
44
int errpos[4],errstart[4],nplanes,cnvused,chunksize,toprow;
44
int errpos[4],errstart[4],nplanes,cnvused,chunksize,toprow;
45
value_type cell[NUM_CELLS];
45
value_type cell[NUM_CELLS];
46
 
46
 
47
// this is the only memory area that keeps preserved by Photoshop:
47
// this is the only memory area that keeps preserved by Photoshop:
48
globals_t *gdata;
48
globals_t *gdata;
49
FilterRecordPtr gpb;
49
FilterRecordPtr gpb;
50
 
50
 
51
#ifdef MAC_ENV
51
#ifdef MAC_ENV
52
#define HINSTANCE HANDLE
52
#define HINSTANCE HANDLE
53
#define hDllInstance NULL /* fake this Windows-only global */
53
#define hDllInstance NULL /* fake this Windows-only global */
54
#endif
54
#endif
55
 
55
 
56
#ifdef WIN_ENV
56
#ifdef WIN_ENV
57
#include "manifest.h"
57
#include "manifest.h"
58
#endif
58
#endif
59
 
59
 
60
extern struct sym_rec predefs[];
60
extern struct sym_rec predefs[];
61
extern int nplanes,varused[];
61
extern int nplanes,varused[];
62
 
62
 
63
int checkandinitparams(Handle params);
63
int checkandinitparams(Handle params);
64
 
64
 
65
// MPW MrC requires prototype
65
// MPW MrC requires prototype
66
DLLEXPORT MACPASCAL
66
DLLEXPORT MACPASCAL
67
void ENTRYPOINT(short selector,FilterRecordPtr pb,intptr_t *data,short *result);
67
void ENTRYPOINT(short selector,FilterRecordPtr pb,intptr_t *data,short *result);
68
 
68
 
69
unsigned long parm_hash(PARM_T *parm) {
69
unsigned long parm_hash(PARM_T *parm) {
70
        unsigned long hash;
70
        unsigned long hash;
71
        int i;
71
        int i;
72
 
72
 
73
        hash = djb2(parm->szCategory);
73
        hash = djb2(parm->szCategory);
74
        hash += djb2(parm->szTitle);
74
        hash += djb2(parm->szTitle);
75
        hash += djb2(parm->szCopyright);
75
        hash += djb2(parm->szCopyright);
76
        hash += djb2(parm->szAuthor);
76
        hash += djb2(parm->szAuthor);
77
        for (i = 0; i < 4; i++) hash += djb2(parm->szMap[i]);
77
        for (i = 0; i < 4; i++) hash += djb2(parm->szMap[i]);
78
        for (i = 0; i < 8; i++) hash += djb2(parm->szCtl[i]);
78
        for (i = 0; i < 8; i++) hash += djb2(parm->szCtl[i]);
79
        for (i = 0; i < 4; i++) hash += djb2(parm->szFormula[i]);
79
        for (i = 0; i < 4; i++) hash += djb2(parm->szFormula[i]);
80
 
80
 
81
        return hash;
81
        return hash;
82
}
82
}
83
 
83
 
84
size_t get_temp_afs(LPTSTR outfilename, Boolean isStandalone, PARM_T *parm) {
84
size_t get_temp_afs(TCHAR* outfilename, Boolean isStandalone, PARM_T *parm) {
85
        char* atempdir;
85
        char* atempdir;
86
        int hash;
86
        int hash;
87
        size_t i, j;
87
        size_t i, j;
88
        TCHAR out[MAX_PATH + 1];
88
        TCHAR out[MAX_PATH + 1];
89
        char ahash[20];
89
        char ahash[20];
90
 
90
 
91
        // out = getenv("TMP")
91
        // out = getenv("TMP")
92
        atempdir = getenv("TMP");
92
        atempdir = getenv("TMP");
93
        for (i = 0; i < strlen(atempdir); i++) {
93
        for (i = 0; i < strlen(atempdir); i++) {
94
                out[i] = (TCHAR)atempdir[i];
94
                out[i] = (TCHAR)atempdir[i];
95
                out[i + 1] = 0;
95
                out[i + 1] = 0;
96
        }
96
        }
97
 
97
 
98
        #ifdef WIN_ENV
98
        #ifdef WIN_ENV
99
        if (xstrlen(out) > 0) xstrcat(out, TEXT("\\"));
99
        if (xstrlen(out) > 0) xstrcat(out, TEXT("\\"));
100
        #else
100
        #else
101
        if (xstrlen(out) > 0) xstrcat(out, TEXT("/"));
101
        if (xstrlen(out) > 0) xstrcat(out, TEXT("/"));
102
        #endif
102
        #endif
103
 
103
 
104
        hash = (isStandalone) ? parm_hash(parm) : 0;
104
        hash = (isStandalone) ? parm_hash(parm) : 0;
105
 
105
 
106
        // sprintf(outfilename, "%sFilterFoundry%d.afs", atempdir, hash);
106
        // sprintf(outfilename, "%sFilterFoundry%d.afs", atempdir, hash);
107
        xstrcat(out, TEXT("FilterFoundry"));
107
        xstrcat(out, TEXT("FilterFoundry"));
108
        _itoa(hash, &ahash[0], 10);
108
        _itoa(hash, &ahash[0], 10);
109
        for (i = 0; i < strlen(ahash); i++) {
109
        for (i = 0; i < strlen(ahash); i++) {
110
                j = xstrlen(out);
110
                j = xstrlen(out);
111
                out[j] = (TCHAR)ahash[i];
111
                out[j] = (TCHAR)ahash[i];
112
                out[j + 1] = 0;
112
                out[j + 1] = 0;
113
        }
113
        }
114
        xstrcat(out, TEXT(".afs"));
114
        xstrcat(out, TEXT(".afs"));
115
        if (outfilename != NULL) {
115
        if (outfilename != NULL) {
116
                xstrcpy(outfilename, out);
116
                xstrcpy(outfilename, out);
117
        }
117
        }
118
        return xstrlen(out);
118
        return xstrlen(out);
119
}
119
}
120
 
120
 
121
char* stristr(const char* str, const char* strSearch) {
121
char* stristr(const char* str, const char* strSearch) {
122
        // Source: https://stackoverflow.com/questions/27303062/strstr-function-like-that-ignores-upper-or-lower-case
122
        // Source: https://stackoverflow.com/questions/27303062/strstr-function-like-that-ignores-upper-or-lower-case
123
        char *sors, *subs, *res = NULL;
123
        char *sors, *subs, *res = NULL;
124
        if ((sors = _strdup(str)) != NULL) {
124
        if ((sors = _strdup(str)) != NULL) {
125
                if ((subs = _strdup(strSearch)) != NULL) {
125
                if ((subs = _strdup(strSearch)) != NULL) {
126
                        res = strstr(_strlwr(sors), _strlwr(subs));
126
                        res = strstr(_strlwr(sors), _strlwr(subs));
127
                        if (res != NULL)
127
                        if (res != NULL)
128
                                res = (char*)str + (res - sors);
128
                                res = (char*)str + (res - sors);
129
                        free(subs);
129
                        free(subs);
130
                }
130
                }
131
                free(sors);
131
                free(sors);
132
        }
132
        }
133
        return res;
133
        return res;
134
}
134
}
135
 
135
 
-
 
136
#ifdef WIN_ENV
136
BOOL CalledFromRunDLL32(HINSTANCE hinst) {
137
BOOL CalledFromRunDLL32(HINSTANCE hinst) {
137
        char exename[MAX_PATH];
138
        char exename[MAX_PATH];
138
        if (GetModuleFileNameA(hinst, exename, MAX_PATH) == 0) return false;
139
        if (GetModuleFileNameA(hinst, exename, MAX_PATH) == 0) return false;
139
        return stristr(exename, "rundll32") != NULL;
140
        return stristr(exename, "rundll32") != NULL;
140
}
141
}
-
 
142
#endif
141
 
143
 
-
 
144
#ifdef WIN_ENV
142
void CALLBACK FakeRundll32(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) {
145
void CALLBACK FakeRundll32(HWND hwnd, HINSTANCE hinst, LPSTR lpszCmdLine, int nCmdShow) {
143
        UNREFERENCED_PARAMETER(hwnd);
146
        UNREFERENCED_PARAMETER(hwnd);
144
        UNREFERENCED_PARAMETER(hinst);
147
        UNREFERENCED_PARAMETER(hinst);
145
        UNREFERENCED_PARAMETER(lpszCmdLine);
148
        UNREFERENCED_PARAMETER(lpszCmdLine);
146
        UNREFERENCED_PARAMETER(nCmdShow);
149
        UNREFERENCED_PARAMETER(nCmdShow);
147
 
150
 
148
        /*
151
        /*
149
        char* tmp = (char*)malloc(512);
152
        char* tmp = (char*)malloc(512);
150
        if (tmp != 0) {
153
        if (tmp != 0) {
151
                sprintf(tmp, "hwnd: %p\nhinst: %p\nlpszCmdLine: %s\nCmdShow: %d", (void*)(hwnd), (void*)(hinst), lpszCmdLine, nCmdShow);
154
                sprintf(tmp, "hwnd: %p\nhinst: %p\nlpszCmdLine: %s\nCmdShow: %d", (void*)(hwnd), (void*)(hinst), lpszCmdLine, nCmdShow);
152
                MessageBoxA(0, tmp, 0, 0);
155
                MessageBoxA(0, tmp, 0, 0);
153
                free(tmp);
156
                free(tmp);
154
        }
157
        }
155
        */
158
        */
156
 
159
 
157
        simplealert_id(MSG_RUNDLL_ERR_ID);
160
        simplealert_id(MSG_RUNDLL_ERR_ID);
158
 
161
 
159
        return;
162
        return;
160
}
163
}
-
 
164
#endif
161
 
165
 
162
void CreateDataPointer(intptr_t* data) {
166
void CreateDataPointer(intptr_t* data) {
163
        // Register "gdata" that contains the PARM information and other things which need to be persistant
167
        // Register "gdata" that contains the PARM information and other things which need to be persistant
164
        // and preserve them in *data
168
        // and preserve them in *data
165
        // This memory allocation is never freed, because the filter can always be invoked again.
169
        // This memory allocation is never freed, because the filter can always be invoked again.
166
        // The memory allocation will be kept for the lifetime of the Photoshop process and
170
        // The memory allocation will be kept for the lifetime of the Photoshop process and
167
        // freed together with the application termination.
171
        // freed together with the application termination.
168
 
172
 
169
        // We have at least 5 options to allocate memory:
173
        // We have at least 5 options to allocate memory:
170
 
174
 
171
        // (Method 1)
175
        // (Method 1)
172
        // 1. The deprecated Standard Buffer Suite (pb->bufferProcs) - works fine!
176
        // 1. The deprecated Standard Buffer Suite (pb->bufferProcs) - works fine!
173
        /*
177
        /*
174
        BufferID tempId;
178
        BufferID tempId;
175
        if (gpb->bufferProcs->allocateProc(sizeof(globals_t), &tempId) != noErr) {
179
        if (gpb->bufferProcs->allocateProc(sizeof(globals_t), &tempId) != noErr) {
176
                *data = NULL;
180
                *data = NULL;
177
        }
181
        }
178
        else {
182
        else {
179
                *data = (void*)gpb->bufferProcs->lockProc(tempId, true);
183
                *data = (void*)gpb->bufferProcs->lockProc(tempId, true);
180
                if (*data) memset((void*)*data, 0, sizeof(globals_t));
184
                if (*data) memset((void*)*data, 0, sizeof(globals_t));
181
        }
185
        }
182
        */
186
        */
183
 
187
 
184
        // (Method 2) *DOES NOT WORK*
188
        // (Method 2) *DOES NOT WORK*
185
        // 2. The recommended buffer suite (kPSBufferSuite),
189
        // 2. The recommended buffer suite (kPSBufferSuite),
186
        //    It does not work, since it causes memory corruption when the filter is invoked a second time.
190
        //    It does not work, since it causes memory corruption when the filter is invoked a second time.
187
        //    Probably the BufferSuite cannot be used to share data between filter invocations?
191
        //    Probably the BufferSuite cannot be used to share data between filter invocations?
188
        //    Also, the buffer suite is only available on the Adobe Photoshop host application.
192
        //    Also, the buffer suite is only available on the Adobe Photoshop host application.
189
        /*
193
        /*
190
        FFBuffer buf;
194
        FFBuffer buf;
191
        newBuffer(&buf, sizeof(globals_t));
195
        newBuffer(&buf, sizeof(globals_t));
192
        *data = (intptr_t)lockBuffer(&buf);
196
        *data = (intptr_t)lockBuffer(&buf);
193
        if (*data) memset((void*)*data, 0, sizeof(globals_t));
197
        if (*data) memset((void*)*data, 0, sizeof(globals_t));
194
        */
198
        */
195
 
199
 
196
        // (Method 3)
200
        // (Method 3)
197
        // 3. Using malloc(), which works also fine and is more independent from the host. It is also easier.
201
        // 3. Using malloc(), which works also fine and is more independent from the host. It is also easier.
198
        //    However, we do not know how malloc() is implemented, and it might cause problems if the
202
        //    However, we do not know how malloc() is implemented, and it might cause problems if the
199
        //    DLL is unloaded between invocations.
203
        //    DLL is unloaded between invocations.
200
        /*
204
        /*
201
        *data = (intptr_t)malloc(sizeof(globals_t));
205
        *data = (intptr_t)malloc(sizeof(globals_t));
202
        if (*data) memset((void*)*data, 0, sizeof(globals_t));
206
        if (*data) memset((void*)*data, 0, sizeof(globals_t));
203
        */
207
        */
204
 
208
 
205
        // (Method 4)
209
        // (Method 4)
206
        // 4. Using PLUGIN.DLL:NewPtr(). This does FilterFactory 3.0.4, but requires an Adobe host.
210
        // 4. Using PLUGIN.DLL:NewPtr(). This does FilterFactory 3.0.4, but requires an Adobe host.
207
        //    In Plugin.dll, the function NewPtr() and NewPtrClear() are implemented as GlobalAlloc/GlobalLock.
211
        //    In Plugin.dll, the function NewPtr() and NewPtrClear() are implemented as GlobalAlloc/GlobalLock.
208
        //    Nothing special.
212
        //    Nothing special.
209
 
213
 
210
        // (Method 5)
214
        // (Method 5)
211
        // 5. Using GlobalAlloc/GlobalLock. This does FilterFactory 3.00 (Flags GHND = GMEM_MOVEABLE and GMEM_ZEROINIT).
215
        // 5. Using GlobalAlloc/GlobalLock. This does FilterFactory 3.00 (Flags GHND = GMEM_MOVEABLE and GMEM_ZEROINIT).
212
        //    This is Windows dependant. (However, on Mac we will just call NewPtr.)
216
        //    This is Windows dependant. (However, on Mac we will just call NewPtr.)
213
        //    GlobalAlloc and LocalAlloc are equal in 32-bit windows. The memory allocation is NOT global anymore,
217
        //    GlobalAlloc and LocalAlloc are equal in 32-bit windows. The memory allocation is NOT global anymore,
214
        //    instead it is on the private heap of the application. (Therefore we do not cause a leak when
218
        //    instead it is on the private heap of the application. (Therefore we do not cause a leak when
215
        //    Photoshop is closed).
219
        //    Photoshop is closed).
216
        // In Filter Foundry 1.7.0.17 we define a function called NewPtrClear, which is natively supported by Mac,
220
        // In Filter Foundry 1.7.0.17 we define a function called NewPtrClear, which is natively supported by Mac,
217
        // and in Windows it will be implemented using GlobalAlloc/GlobalLock.
221
        // and in Windows it will be implemented using GlobalAlloc/GlobalLock.
218
        *data = (intptr_t)NewPtrClear(sizeof(globals_t));
222
        *data = (intptr_t)NewPtrClear(sizeof(globals_t));
219
}
223
}
220
 
224
 
221
DLLEXPORT MACPASCAL
225
DLLEXPORT MACPASCAL
222
void ENTRYPOINT(short selector, FilterRecordPtr pb, intptr_t *data, short *result){
226
void ENTRYPOINT(short selector, FilterRecordPtr pb, intptr_t *data, short *result){
223
        static Boolean wantdialog = false;
227
        static Boolean wantdialog = false;
224
        static Boolean premiereWarnedOnce = false;
228
        static Boolean premiereWarnedOnce = false;
225
 
229
 
226
        #ifdef SHOW_HOST_DEBUG
230
        #ifdef SHOW_HOST_DEBUG
227
        char* tmp;
231
        char* tmp;
228
        #endif
232
        #endif
229
 
233
 
230
        #ifdef WIN_ENV
234
        #ifdef WIN_ENV
231
        // For Windows, we use an activation context to enforce that our Manifest resource will
235
        // For Windows, we use an activation context to enforce that our Manifest resource will
232
        // be used. This allows us to use Visual Styles, even if the host application does not
236
        // be used. This allows us to use Visual Styles, even if the host application does not
233
        // support it.
237
        // support it.
234
        ManifestActivationCtx manifestVars;
238
        ManifestActivationCtx manifestVars;
235
        BOOL activationContextUsed;
239
        BOOL activationContextUsed;
236
        #endif
240
        #endif
237
 
241
 
238
        // ---------------------------------------------------------------------
242
        // ---------------------------------------------------------------------
239
 
243
 
240
        EnterCodeResource();
244
        EnterCodeResource();
241
 
245
 
242
        #ifdef WIN_ENV
246
        #ifdef WIN_ENV
243
        activationContextUsed = ActivateManifest((HMODULE)hDllInstance, 1, &manifestVars);
247
        activationContextUsed = ActivateManifest((HMODULE)hDllInstance, 1, &manifestVars);
244
        #endif
248
        #endif
245
 
249
 
246
        #ifdef WIN_ENV
250
        #ifdef WIN_ENV
247
        if ((intptr_t)result == SW_SHOWDEFAULT && CalledFromRunDLL32((HINSTANCE)pb)) {
251
        if ((intptr_t)result == SW_SHOWDEFAULT && CalledFromRunDLL32((HINSTANCE)pb)) {
248
                // When the 8BF file is analyzed with VirusTotal.com, it will invoke each
252
                // When the 8BF file is analyzed with VirusTotal.com, it will invoke each
249
                // exported function by calling
253
                // exported function by calling
250
                // loaddll64.exe 'C:\Users\user\Desktop\attachment.dll'
254
                // loaddll64.exe 'C:\Users\user\Desktop\attachment.dll'
251
                //        ==>  rundll32.exe C:\Users\user\Desktop\attachment.dll,PluginMain
255
                //        ==>  rundll32.exe C:\Users\user\Desktop\attachment.dll,PluginMain
252
                //           ==> C:\Windows\system32\WerFault.exe -u -p 6612 -s 480
256
                //           ==> C:\Windows\system32\WerFault.exe -u -p 6612 -s 480
253
                //
257
                //
254
                // But RunDLL32 requires the following signature:
258
                // But RunDLL32 requires the following signature:
255
                //    void __stdcall EntryPoint(HWND hwnd,      HINSTANCE hinst,    LPSTR lpszCmdLine, int nCmdShow);
259
                //    void __stdcall EntryPoint(HWND hwnd,      HINSTANCE hinst,    LPSTR lpszCmdLine, int nCmdShow);
256
                // Our signature is:
260
                // Our signature is:
257
                //    void           PluginMain(short selector, FilterRecordPtr pb, intptr_t *data,    short *result);
261
                //    void           PluginMain(short selector, FilterRecordPtr pb, intptr_t *data,    short *result);
258
                //
262
                //
259
                // Obviously, this will cause an Exception. (It crashes at *result=e because result is 0xA, which is SW_SHOWDEFAULT)
263
                // Obviously, this will cause an Exception. (It crashes at *result=e because result is 0xA, which is SW_SHOWDEFAULT)
260
                // Here is the problem: The crash will be handled by WerFault.exe inside the
264
                // Here is the problem: The crash will be handled by WerFault.exe inside the
261
                // VirusTotal virtual machine. WerFault connects to various servers (9 DNS resolutions!) and does
265
                // VirusTotal virtual machine. WerFault connects to various servers (9 DNS resolutions!) and does
262
                // a lot of weird things, but VirusTotal thinks that our plugin does all that stuff,
266
                // a lot of weird things, but VirusTotal thinks that our plugin does all that stuff,
263
                // and so they mark our plugin as "malware"!
267
                // and so they mark our plugin as "malware"!
264
                // This is a problem with VirusTotal! It shall not assume that WerFault.exe actions are our actions!
268
                // This is a problem with VirusTotal! It shall not assume that WerFault.exe actions are our actions!
265
                // Even actions from processes like "MicrosoftEdgeUpdate.exe" and "SpeechRuntime.exe" are reported to be our
269
                // Even actions from processes like "MicrosoftEdgeUpdate.exe" and "SpeechRuntime.exe" are reported to be our
266
                // actions, although they have nothing to do with us!
270
                // actions, although they have nothing to do with us!
267
                // See https://www.virustotal.com/gui/file/1f1012c567208186be455b81afc1ee407ae6476c197d633c70cc70929113223a/behavior
271
                // See https://www.virustotal.com/gui/file/1f1012c567208186be455b81afc1ee407ae6476c197d633c70cc70929113223a/behavior
268
                //
272
                //
269
                // Note in re "*result": Usually, The first 64KB of address space are always invalid. However, in Win32s (Windows 3.11), the
273
                // Note in re "*result": Usually, The first 64KB of address space are always invalid. However, in Win32s (Windows 3.11), the
270
                // variable "result" is <=0xFFFF. So we cannot assume that result<=0xFFFF means that the call came from RunDLL32.
274
                // variable "result" is <=0xFFFF. So we cannot assume that result<=0xFFFF means that the call came from RunDLL32.
271
 
275
 
272
                FakeRundll32((HWND)(intptr_t)selector, (HINSTANCE)pb, (LPSTR)data, (int)(intptr_t)result);
276
                FakeRundll32((HWND)(intptr_t)selector, (HINSTANCE)pb, (LPSTR)data, (int)(intptr_t)result);
273
                // (I don't understand why this works! Aren't we __cdecl and rundll expected __stdcall? But why is the parameter order correct and not reversed?)
277
                // (I don't understand why this works! Aren't we __cdecl and rundll expected __stdcall? But why is the parameter order correct and not reversed?)
274
 
278
 
275
                goto endmain;
279
                goto endmain;
276
        }
280
        }
277
        else {
281
        #endif
-
 
282
 
278
                // will be changed if an error happens
283
        // will be changed if an error happens
279
                *result = noErr;
284
        *result = noErr;
280
        }
-
 
281
        #endif
-
 
282
 
285
 
283
        #ifdef SHOW_HOST_DEBUG
286
        #ifdef SHOW_HOST_DEBUG
284
        tmp = (char*)malloc(512);
287
        tmp = (char*)malloc(512);
285
        sprintf(tmp, "Host signature: '%c%c%c%c' (%d)\nMaxSpace32 = %d\nMaxSpace64 = %lld\nNum buffer procs: %d", (pb->hostSig >> 24) & 0xFF, (pb->hostSig >> 16) & 0xFF, (pb->hostSig >> 8) & 0xFF, pb->hostSig & 0xFF, pb->hostSig, pb->maxSpace, pb->maxSpace64, pb->bufferProcs == 0 ? -999/*About has no BufferProcs*/ : pb->bufferProcs->numBufferProcs);
288
        sprintf(tmp, "Host signature: '%c%c%c%c' (%d)\nMaxSpace32 = %d\nMaxSpace64 = %lld\nNum buffer procs: %d", (pb->hostSig >> 24) & 0xFF, (pb->hostSig >> 16) & 0xFF, (pb->hostSig >> 8) & 0xFF, pb->hostSig & 0xFF, pb->hostSig, pb->maxSpace, pb->maxSpace64, pb->bufferProcs == 0 ? -999/*About has no BufferProcs*/ : pb->bufferProcs->numBufferProcs);
286
        simplealert(tmp);
289
        simplealert(tmp);
287
        free(tmp);
290
        free(tmp);
288
        #endif
291
        #endif
289
 
292
 
290
        if (pb->hostSig == HOSTSIG_ADOBE_PREMIERE) {
293
        if (pb->hostSig == HOSTSIG_ADOBE_PREMIERE) {
291
                // DM 19.07.2021 : Tried running the 8BF file in Adobe Premiere 5 + Win98
294
                // DM 19.07.2021 : Tried running the 8BF file in Adobe Premiere 5 + Win98
292
                // (yes, that's possible, and there is even a FilterFactory for Premiere!),
295
                // (yes, that's possible, and there is even a FilterFactory for Premiere!),
293
                // but it crashes in evalpixel() where there is write-access to the "outp".
296
                // but it crashes in evalpixel() where there is write-access to the "outp".
294
                // DM 24.04.2022 : On Adobe Premiere 6 + Win10, the filter opens sometimes (and sometimes crashes inside DialogBoxParam),
297
                // DM 24.04.2022 : On Adobe Premiere 6 + Win10, the filter opens sometimes (and sometimes crashes inside DialogBoxParam),
295
                // but the filter is not applied when you click "OK" (because it crashes internally; only the debugger sees it)...
298
                // but the filter is not applied when you click "OK" (because it crashes internally; only the debugger sees it)...
296
                // Maybe the canvas structure is different (maybe it contains frames to achieve transitions?)
299
                // Maybe the canvas structure is different (maybe it contains frames to achieve transitions?)
297
                // TODO: make Filter Foundry compatible with Premiere!
300
                // TODO: make Filter Foundry compatible with Premiere!
298
                if (!premiereWarnedOnce) {
301
                if (!premiereWarnedOnce) {
299
                        simplealert_id(MSG_PREMIERE_COMPAT_ID);
302
                        simplealert_id(MSG_PREMIERE_COMPAT_ID);
300
                }
303
                }
301
                premiereWarnedOnce = true;
304
                premiereWarnedOnce = true;
302
                *result = errPlugInHostInsufficient;
305
                *result = errPlugInHostInsufficient;
303
                goto endmain;
306
                goto endmain;
304
        }
307
        }
305
 
308
 
306
        #ifdef DEBUG_SIMULATE_GIMP
309
        #ifdef DEBUG_SIMULATE_GIMP
307
        *data = 0;
310
        *data = 0;
308
        pb->parameters = pb->handleProcs->newProc(1);
311
        pb->parameters = pb->handleProcs->newProc(1);
309
        #endif
312
        #endif
310
 
313
 
311
        gpb = pb; // required for CreateDataPointer()
314
        gpb = pb; // required for CreateDataPointer()
312
 
315
 
313
        if (selector != filterSelectorAbout && !*data) {
316
        if (selector != filterSelectorAbout && !*data) {
314
                // The filter was never called before. We allocate (zeroed) memory now.
317
                // The filter was never called before. We allocate (zeroed) memory now.
315
                CreateDataPointer(data);
318
                CreateDataPointer(data);
316
                if (!*data) {
319
                if (!*data) {
317
                        *result = memFullErr;
320
                        *result = memFullErr;
318
                        goto endmain;
321
                        goto endmain;
319
                }
322
                }
320
        }
323
        }
321
 
324
 
322
        gdata = (globals_t*)*data;
325
        gdata = (globals_t*)*data;
323
 
326
 
324
        nplanes = MIN(pb->planes,4);
327
        nplanes = MIN(pb->planes,4);
325
 
328
 
326
        switch (selector){
329
        switch (selector){
327
        case filterSelectorAbout:
330
        case filterSelectorAbout:
328
                if (!gdata) {
331
                if (!gdata) {
329
                        Boolean parmReadOk;
332
                        Boolean parmReadOk;
330
                        // This is a temporary gdata structure just for the About dialog!
333
                        // This is a temporary gdata structure just for the About dialog!
331
                        // Not to be confused with the "real" gdata during the filter invocation (containing more data).
334
                        // Not to be confused with the "real" gdata during the filter invocation (containing more data).
332
                        gdata = (globals_t*)malloc(sizeof(globals_t));
335
                        gdata = (globals_t*)malloc(sizeof(globals_t));
333
                        if (!gdata) break;
336
                        if (!gdata) break;
334
                        gdata->hWndMainDlg = (HWND)((PlatformData*)((AboutRecordPtr)pb)->platformData)->hwnd; // so that simplealert() works
337
                        gdata->hWndMainDlg = (HWND)((PlatformData*)((AboutRecordPtr)pb)->platformData)->hwnd; // so that simplealert() works
335
                        parmReadOk = (LOADING_OK == readPARMresource((HMODULE)hDllInstance));
338
                        parmReadOk = (LOADING_OK == readPARMresource((HMODULE)hDllInstance));
336
                        if (!parmReadOk) gdata->parm.standalone = false;
339
                        if (!parmReadOk) gdata->parm.standalone = false;
337
                        if (parmReadOk && (gdata->parm.cbSize != PARM_SIZE) && (gdata->parm.cbSize != PARM_SIZE_PREMIERE) && (gdata->parm.cbSize != PARM_SIG_MAC)) {
340
                        if (parmReadOk && (gdata->parm.cbSize != PARM_SIZE) && (gdata->parm.cbSize != PARM_SIZE_PREMIERE) && (gdata->parm.cbSize != PARM_SIG_MAC)) {
338
                                parm_reset(true, true, true, true);
341
                                parm_reset(true, true, true, true);
339
                                if (gdata->obfusc) {
342
                                if (gdata->obfusc) {
340
                                        simplealert_id(MSG_INCOMPATIBLE_OBFUSCATION_ID);
343
                                        simplealert_id(MSG_INCOMPATIBLE_OBFUSCATION_ID);
341
                                }
344
                                }
342
                                else {
345
                                else {
343
                                        simplealert_id(MSG_INVALID_PARAMETER_DATA_ID);
346
                                        simplealert_id(MSG_INVALID_PARAMETER_DATA_ID);
344
                                }
347
                                }
345
                        }
348
                        }
346
                        else {
349
                        else {
347
                                DoAbout((AboutRecordPtr)pb);
350
                                DoAbout((AboutRecordPtr)pb);
348
                        }
351
                        }
349
                        free(gdata);
352
                        free(gdata);
350
                        gdata = NULL;
353
                        gdata = NULL;
351
                } else {
354
                } else {
352
                        DoAbout((AboutRecordPtr)pb);
355
                        DoAbout((AboutRecordPtr)pb);
353
                }
356
                }
354
                break;
357
                break;
355
        case filterSelectorParameters:
358
        case filterSelectorParameters:
356
                wantdialog = true;
359
                wantdialog = true;
357
                break;
360
                break;
358
        case filterSelectorPrepare:
361
        case filterSelectorPrepare:
359
                gdata->hWndMainDlg = 0;
362
                gdata->hWndMainDlg = 0;
360
                DoPrepare(pb);
363
                DoPrepare(pb);
361
                init_symtab(predefs); // ready for parser calls
364
                init_symtab(predefs); // ready for parser calls
362
                init_trigtab();
365
                init_trigtab();
363
                break;
366
                break;
364
        case filterSelectorStart:
367
        case filterSelectorStart:
365
                if (HAS_BIG_DOC(pb)) {
368
                if (HAS_BIG_DOC(pb)) {
366
                        // The BigDocument structure is required if the document is larger than 30,000 pixels
369
                        // The BigDocument structure is required if the document is larger than 30,000 pixels
367
                        // It deprecates imageSize, filterRect, inRect, outRect, maskRect, floatCoord, and wholeSize.
370
                        // It deprecates imageSize, filterRect, inRect, outRect, maskRect, floatCoord, and wholeSize.
368
                        // By setting it to nonzero, we communicate to Photoshop that we support the BigDocument structure.
371
                        // By setting it to nonzero, we communicate to Photoshop that we support the BigDocument structure.
369
                        pb->bigDocumentData->PluginUsing32BitCoordinates = true;
372
                        pb->bigDocumentData->PluginUsing32BitCoordinates = true;
370
                }
373
                }
371
 
374
 
372
                /* initialise the parameter handle that Photoshop keeps for us */
375
                /* initialise the parameter handle that Photoshop keeps for us */
373
                if(!pb->parameters)
376
                if(!pb->parameters)
374
                        pb->parameters = PINEWHANDLE(1); // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that.
377
                        pb->parameters = PINEWHANDLE(1); // don't set initial size to 0, since some hosts (e.g. GIMP/PSPI) are incompatible with that.
375
 
378
 
376
                if (!pb->parameters) {
379
                if (!pb->parameters) {
377
                        *result = memFullErr;
380
                        *result = memFullErr;
378
                }
381
                }
379
                else
382
                else
380
                {
383
                {
381
                        wantdialog |= checkandinitparams(pb->parameters);
384
                        wantdialog |= checkandinitparams(pb->parameters);
382
 
385
 
383
                        /* wantdialog = false means that we never got a Parameters call, so we're not supposed to ask user */
386
                        /* wantdialog = false means that we never got a Parameters call, so we're not supposed to ask user */
384
                        if (wantdialog && (!gdata->parm.standalone || gdata->parm.popDialog)) {
387
                        if (wantdialog && (!gdata->parm.standalone || gdata->parm.popDialog)) {
385
                                if (maindialog(pb)) {
388
                                if (maindialog(pb)) {
386
                                        if (!host_preserves_parameters()) {
389
                                        if (!host_preserves_parameters()) {
387
                                                /* Workaround for GIMP/PSPI, to avoid that formulas vanish when you re-open the main window.
390
                                                /* Workaround for GIMP/PSPI, to avoid that formulas vanish when you re-open the main window.
388
                                                   The reason is a bug in PSPI: The host should preserve the value of pb->parameters, which PSPI does not do.
391
                                                   The reason is a bug in PSPI: The host should preserve the value of pb->parameters, which PSPI does not do.
389
                                                   Also, all global variables are unloaded, so the plugin cannot preserve any data.
392
                                                   Also, all global variables are unloaded, so the plugin cannot preserve any data.
390
                                                   Workaround in FF 1.7: If the host GIMP is detected, then a special mode will be activated.
393
                                                   Workaround in FF 1.7: If the host GIMP is detected, then a special mode will be activated.
391
                                                   This mode saves the filter data into a temporary file "FilterFoundryXX.afs" and loads it
394
                                                   This mode saves the filter data into a temporary file "FilterFoundryXX.afs" and loads it
392
                                                   when the window is opened again. */
395
                                                   when the window is opened again. */
393
                                                   // Workaround: Save settings in "FilterFoundryXX.afs" if the host does not preserve pb->parameters
396
                                                   // Workaround: Save settings in "FilterFoundryXX.afs" if the host does not preserve pb->parameters
394
                                                TCHAR outfilename[MAX_PATH + 1];
397
                                                TCHAR outfilename[MAX_PATH + 1];
395
                                                StandardFileReply sfr;
398
                                                StandardFileReply sfr;
396
                                                InternalState tmpState;
399
                                                InternalState tmpState;
397
                                                FFSavingResult saveres;
400
                                                FFSavingResult saveres;
398
 
401
 
399
                                                sfr.sfGood = true;
402
                                                sfr.sfGood = true;
400
                                                sfr.sfReplacing = true;
403
                                                sfr.sfReplacing = true;
401
                                                sfr.sfType = PS_FILTER_FILETYPE;
404
                                                sfr.sfType = PS_FILTER_FILETYPE;
402
 
405
 
403
                                                get_temp_afs(&outfilename[0], gdata->parm.standalone, &gdata->parm);
406
                                                get_temp_afs(&outfilename[0], gdata->parm.standalone, &gdata->parm);
404
 
407
 
405
                                                xstrcpy(sfr.sfFile.szName, outfilename);
408
                                                xstrcpy(sfr.sfFile.szName, outfilename);
406
                                                #ifdef WIN_ENV
409
                                                #ifdef WIN_ENV
407
                                                sfr.nFileExtension = (WORD)(xstrlen(outfilename) - strlen(".afs") + 1);
410
                                                sfr.nFileExtension = (WORD)(xstrlen(outfilename) - strlen(".afs") + 1);
408
                                                #endif
411
                                                #endif
409
                                                sfr.sfScript = smSystemScript;
412
                                                sfr.sfScript = smSystemScript;
410
 
413
 
411
                                                // We only want the parameters (ctl,map) in the temporary .afs file
414
                                                // We only want the parameters (ctl,map) in the temporary .afs file
412
                                                // It is important to remove the expressions, otherwise they would be
415
                                                // It is important to remove the expressions, otherwise they would be
413
                                                // revealed in the temporary files (That might be bad for obfuscated filters).
416
                                                // revealed in the temporary files (That might be bad for obfuscated filters).
414
                                                if (gdata->parm.standalone) {
417
                                                if (gdata->parm.standalone) {
415
                                                        tmpState = saveInternalState();
418
                                                        tmpState = saveInternalState();
416
                                                        parm_reset(false, false, false, true);
419
                                                        parm_reset(false, false, false, true);
417
                                                }
420
                                                }
418
 
421
 
419
                                                saveres = savefile_afs_pff_picotxt_guf(&sfr);
422
                                                saveres = savefile_afs_pff_picotxt_guf(&sfr);
420
 
423
 
421
                                                if (gdata->parm.standalone) {
424
                                                if (gdata->parm.standalone) {
422
                                                        restoreInternalState(tmpState);
425
                                                        restoreInternalState(tmpState);
423
                                                }
426
                                                }
424
 
427
 
425
                                                if (saveres != SAVING_OK) {
428
                                                if (saveres != SAVING_OK) {
426
                                                        TCHAR* reason = FF_GetMsg_Cpy(saveres);
429
                                                        TCHAR* reason = FF_GetMsg_Cpy(saveres);
427
                                                        alertuser_id(MSG_CANNOT_SAVE_SETTINGS_ID, reason);
430
                                                        alertuser_id(MSG_CANNOT_SAVE_SETTINGS_ID, reason);
428
                                                        FF_GetMsg_Free(reason);
431
                                                        FF_GetMsg_Free(reason);
429
                                                        *result = filterBadParameters;
432
                                                        *result = filterBadParameters;
430
                                                }
433
                                                }
431
                                        }
434
                                        }
432
                                        else {
435
                                        else {
433
                                                /* update stored parameters from new user settings */
436
                                                /* update stored parameters from new user settings */
434
                                                if (pb->parameters)
437
                                                if (pb->parameters)
435
                                                        saveparams_afs_pff(pb->parameters, false);
438
                                                        saveparams_afs_pff(pb->parameters, false);
436
                                        }
439
                                        }
437
                                }
440
                                }
438
                                else
441
                                else
439
                                        *result = userCanceledErr;
442
                                        *result = userCanceledErr;
440
                        }
443
                        }
441
                        wantdialog = false;
444
                        wantdialog = false;
442
                }
445
                }
443
 
446
 
444
                if(*result == noErr){
447
                if(*result == noErr){
445
                        if(setup(pb)){
448
                        if(setup(pb)){
446
                                DoStart(pb);
449
                                DoStart(pb);
447
                        }else{
450
                        }else{
448
                                simplealert_id(MSG_SAVED_EXPR_ERR_ID);
451
                                simplealert_id(MSG_SAVED_EXPR_ERR_ID);
449
                                *result = filterBadParameters;
452
                                *result = filterBadParameters;
450
                        }
453
                        }
451
                }
454
                }
452
                break;
455
                break;
453
        case filterSelectorContinue:
456
        case filterSelectorContinue:
454
                *result = DoContinue(pb);
457
                *result = DoContinue(pb);
455
                break;
458
                break;
456
        case filterSelectorFinish:
459
        case filterSelectorFinish:
457
                DoFinish(pb);
460
                DoFinish(pb);
458
                break;
461
                break;
459
        default:
462
        default:
460
                *result = filterBadParameters;
463
                *result = filterBadParameters;
461
        }
464
        }
462
 
465
 
463
endmain:
466
endmain:
464
 
467
 
465
        // TODO: Question: Is that OK to call this every invocation, or should it be only around UI stuff?
468
        // TODO: Question: Is that OK to call this every invocation, or should it be only around UI stuff?
466
        #ifdef WIN_ENV
469
        #ifdef WIN_ENV
467
        if (activationContextUsed) DeactivateManifest(&manifestVars);
470
        if (activationContextUsed) DeactivateManifest(&manifestVars);
468
        #endif
471
        #endif
469
 
472
 
470
        ExitCodeResource();
473
        ExitCodeResource();
471
}
474
}
472
 
475
 
473
void parm_reset(Boolean resetMetadata, Boolean resetSliderValues, Boolean resetSliderNames, Boolean resetFormulas) {
476
void parm_reset(Boolean resetMetadata, Boolean resetSliderValues, Boolean resetSliderNames, Boolean resetFormulas) {
474
        gdata->parm.cbSize = PARM_SIZE;
477
        gdata->parm.cbSize = PARM_SIZE;
475
        if (resetMetadata) {
478
        if (resetMetadata) {
476
                strcpy(gdata->parm.szCategory, "Filter Foundry");
479
                strcpy(gdata->parm.szCategory, "Filter Foundry");
477
                strcpy(gdata->parm.szTitle, "Untitled");
480
                strcpy(gdata->parm.szTitle, "Untitled");
478
                strcpy(gdata->parm.szCopyright, ""); //"Filter Foundry Copyright (C) 2003-2009 Toby Thain, 2018-" RELEASE_YEAR " Daniel Marschall"
481
                strcpy(gdata->parm.szCopyright, ""); //"Filter Foundry Copyright (C) 2003-2009 Toby Thain, 2018-" RELEASE_YEAR " Daniel Marschall"
479
                strcpy(gdata->parm.szAuthor, "Anonymous");
482
                strcpy(gdata->parm.szAuthor, "Anonymous");
480
        }
483
        }
481
        if (resetSliderValues) {
484
        if (resetSliderValues) {
482
                int i;
485
                int i;
483
                for (i = 0; i < 8; ++i) {
486
                for (i = 0; i < 8; ++i) {
484
                        gdata->parm.val[i] = (uint8_t)(i * 10 + 100);
487
                        gdata->parm.val[i] = (uint8_t)(i * 10 + 100);
485
                }
488
                }
486
        }
489
        }
487
        if (resetSliderNames) {
490
        if (resetSliderNames) {
488
                int i;
491
                int i;
489
                for (i = 0; i < 8; ++i) {
492
                for (i = 0; i < 8; ++i) {
490
                        strcpy(gdata->parm.szCtl[i], "ctl(X)");
493
                        strcpy(gdata->parm.szCtl[i], "ctl(X)");
491
                        gdata->parm.szCtl[i][4] = '0' + i;
494
                        gdata->parm.szCtl[i][4] = '0' + i;
492
                }
495
                }
493
                for (i = 0; i < 4; ++i) {
496
                for (i = 0; i < 4; ++i) {
494
                        strcpy(gdata->parm.szMap[i], "Map X");
497
                        strcpy(gdata->parm.szMap[i], "Map X");
495
                        gdata->parm.szMap[i][4] = '0' + i;
498
                        gdata->parm.szMap[i][4] = '0' + i;
496
                }
499
                }
497
        }
500
        }
498
        if (resetFormulas) {
501
        if (resetFormulas) {
499
                if (gpb->imageMode == plugInModeRGBColor) {
502
                if (gpb->imageMode == plugInModeRGBColor) {
500
                        strcpy(gdata->parm.szFormula[0], "r");
503
                        strcpy(gdata->parm.szFormula[0], "r");
501
                        strcpy(gdata->parm.szFormula[1], "g");
504
                        strcpy(gdata->parm.szFormula[1], "g");
502
                        strcpy(gdata->parm.szFormula[2], "b");
505
                        strcpy(gdata->parm.szFormula[2], "b");
503
                        strcpy(gdata->parm.szFormula[3], "a");
506
                        strcpy(gdata->parm.szFormula[3], "a");
504
                }
507
                }
505
                else {
508
                else {
506
                        strcpy(gdata->parm.szFormula[0], "c");
509
                        strcpy(gdata->parm.szFormula[0], "c");
507
                        strcpy(gdata->parm.szFormula[1], "c");
510
                        strcpy(gdata->parm.szFormula[1], "c");
508
                        strcpy(gdata->parm.szFormula[2], "c");
511
                        strcpy(gdata->parm.szFormula[2], "c");
509
                        strcpy(gdata->parm.szFormula[3], "c");
512
                        strcpy(gdata->parm.szFormula[3], "c");
510
                }
513
                }
511
        }
514
        }
512
}
515
}
513
 
516
 
514
void parm_cleanup() {
517
void parm_cleanup() {
515
        // Cleanup "PARM" resource by removing stuff after the null terminators, to avoid that parts of confidential formulas are leaked
518
        // Cleanup "PARM" resource by removing stuff after the null terminators, to avoid that parts of confidential formulas are leaked
516
        int i;
519
        int i;
517
 
520
 
518
        {
521
        {
519
                char tmp[256];
522
                char tmp[256];
520
 
523
 
521
                strcpy(tmp, gdata->parm.szCategory);
524
                strcpy(tmp, gdata->parm.szCategory);
522
                memset(gdata->parm.szCategory, 0, sizeof(gdata->parm.szCategory));
525
                memset(gdata->parm.szCategory, 0, sizeof(gdata->parm.szCategory));
523
                strcpy(gdata->parm.szCategory, tmp);
526
                strcpy(gdata->parm.szCategory, tmp);
524
 
527
 
525
                strcpy(tmp, gdata->parm.szTitle);
528
                strcpy(tmp, gdata->parm.szTitle);
526
                memset(gdata->parm.szTitle, 0, sizeof(gdata->parm.szTitle));
529
                memset(gdata->parm.szTitle, 0, sizeof(gdata->parm.szTitle));
527
                strcpy(gdata->parm.szTitle, tmp);
530
                strcpy(gdata->parm.szTitle, tmp);
528
 
531
 
529
                strcpy(tmp, gdata->parm.szCopyright);
532
                strcpy(tmp, gdata->parm.szCopyright);
530
                memset(gdata->parm.szCopyright, 0, sizeof(gdata->parm.szCopyright));
533
                memset(gdata->parm.szCopyright, 0, sizeof(gdata->parm.szCopyright));
531
                strcpy(gdata->parm.szCopyright, tmp);
534
                strcpy(gdata->parm.szCopyright, tmp);
532
 
535
 
533
                strcpy(tmp, gdata->parm.szAuthor);
536
                strcpy(tmp, gdata->parm.szAuthor);
534
                memset(gdata->parm.szAuthor, 0, sizeof(gdata->parm.szAuthor));
537
                memset(gdata->parm.szAuthor, 0, sizeof(gdata->parm.szAuthor));
535
                strcpy(gdata->parm.szAuthor, tmp);
538
                strcpy(gdata->parm.szAuthor, tmp);
536
        }
539
        }
537
 
540
 
538
        for (i = 0; i < 4; i++) {
541
        for (i = 0; i < 4; i++) {
539
                char tmp[256];
542
                char tmp[256];
540
                strcpy(tmp, gdata->parm.szMap[i]);
543
                strcpy(tmp, gdata->parm.szMap[i]);
541
                memset(gdata->parm.szMap[i], 0, sizeof(gdata->parm.szMap[i]));
544
                memset(gdata->parm.szMap[i], 0, sizeof(gdata->parm.szMap[i]));
542
                strcpy(gdata->parm.szMap[i], tmp);
545
                strcpy(gdata->parm.szMap[i], tmp);
543
        }
546
        }
544
 
547
 
545
        for (i = 0; i < 8; i++) {
548
        for (i = 0; i < 8; i++) {
546
                char tmp[256];
549
                char tmp[256];
547
                strcpy(tmp, gdata->parm.szCtl[i]);
550
                strcpy(tmp, gdata->parm.szCtl[i]);
548
                memset(gdata->parm.szCtl[i], 0, sizeof(gdata->parm.szCtl[i]));
551
                memset(gdata->parm.szCtl[i], 0, sizeof(gdata->parm.szCtl[i]));
549
                strcpy(gdata->parm.szCtl[i], tmp);
552
                strcpy(gdata->parm.szCtl[i], tmp);
550
        }
553
        }
551
 
554
 
552
        for (i = 0; i < 4; i++) {
555
        for (i = 0; i < 4; i++) {
553
                char tmp[1024];
556
                char tmp[1024];
554
                strcpy(tmp, gdata->parm.szFormula[i]);
557
                strcpy(tmp, gdata->parm.szFormula[i]);
555
                memset(gdata->parm.szFormula[i], 0, sizeof(gdata->parm.szFormula[i]));
558
                memset(gdata->parm.szFormula[i], 0, sizeof(gdata->parm.szFormula[i]));
556
                strcpy(gdata->parm.szFormula[i], tmp);
559
                strcpy(gdata->parm.szFormula[i], tmp);
557
        }
560
        }
558
}
561
}
559
 
562
 
560
int checkandinitparams(Handle params){
563
int checkandinitparams(Handle params){
561
        int i;
564
        int i;
562
        Boolean bUninitializedParams;
565
        Boolean bUninitializedParams;
563
        Boolean showdialog;
566
        Boolean showdialog;
564
        InternalState tmpState;
567
        InternalState tmpState;
565
 
568
 
566
        if (!host_preserves_parameters()) {
569
        if (!host_preserves_parameters()) {
567
                // Workaround: Load settings in "FilterFoundryXX.afs" if host does not preserve pb->parameters
570
                // Workaround: Load settings in "FilterFoundryXX.afs" if host does not preserve pb->parameters
568
                TCHAR outfilename[MAX_PATH + 1];
571
                TCHAR outfilename[MAX_PATH + 1];
569
                Boolean parmReadOk;
572
                Boolean parmReadOk;
570
                StandardFileReply sfr;
573
                StandardFileReply sfr;
571
                char bakexpr[4][MAXEXPR];
574
                char bakexpr[4][MAXEXPR];
572
 
575
 
573
                sfr.sfGood = true;
576
                sfr.sfGood = true;
574
                sfr.sfReplacing = true;
577
                sfr.sfReplacing = true;
575
                sfr.sfType = PS_FILTER_FILETYPE;
578
                sfr.sfType = PS_FILTER_FILETYPE;
576
 
579
 
577
                parmReadOk = (LOADING_OK == readPARMresource((HMODULE)hDllInstance));
580
                parmReadOk = (LOADING_OK == readPARMresource((HMODULE)hDllInstance));
578
                if (!parmReadOk) gdata->parm.standalone = false;
581
                if (!parmReadOk) gdata->parm.standalone = false;
579
                if (parmReadOk && (gdata->parm.cbSize != PARM_SIZE) && (gdata->parm.cbSize != PARM_SIZE_PREMIERE) && (gdata->parm.cbSize != PARM_SIG_MAC)) {
582
                if (parmReadOk && (gdata->parm.cbSize != PARM_SIZE) && (gdata->parm.cbSize != PARM_SIZE_PREMIERE) && (gdata->parm.cbSize != PARM_SIG_MAC)) {
580
                        parm_reset(true, true, true, true);
583
                        parm_reset(true, true, true, true);
581
                        if (gdata->obfusc) {
584
                        if (gdata->obfusc) {
582
                                simplealert_id(MSG_INCOMPATIBLE_OBFUSCATION_ID);
585
                                simplealert_id(MSG_INCOMPATIBLE_OBFUSCATION_ID);
583
                        }
586
                        }
584
                        else {
587
                        else {
585
                                simplealert_id(MSG_INVALID_PARAMETER_DATA_ID);
588
                                simplealert_id(MSG_INVALID_PARAMETER_DATA_ID);
586
                        }
589
                        }
587
                        return false;
590
                        return false;
588
                }
591
                }
589
 
592
 
590
                get_temp_afs(&outfilename[0], parmReadOk, &gdata->parm);
593
                get_temp_afs(&outfilename[0], parmReadOk, &gdata->parm);
591
 
594
 
592
                xstrcpy(sfr.sfFile.szName, outfilename);
595
                xstrcpy(sfr.sfFile.szName, outfilename);
593
                #ifdef WIN_ENV
596
                #ifdef WIN_ENV
594
                sfr.nFileExtension = (WORD)(xstrlen(outfilename) - strlen(".afs") + 1);
597
                sfr.nFileExtension = (WORD)(xstrlen(outfilename) - strlen(".afs") + 1);
595
                #endif
598
                #endif
596
                sfr.sfScript = smSystemScript;
599
                sfr.sfScript = smSystemScript;
597
 
600
 
598
                if (parmReadOk) {
601
                if (parmReadOk) {
599
                        tmpState = saveInternalState();
602
                        tmpState = saveInternalState();
600
                }
603
                }
601
 
604
 
602
                if (LOADING_OK == loadfile(&sfr)) {
605
                if (LOADING_OK == loadfile(&sfr)) {
603
                        if (parmReadOk) {
606
                        if (parmReadOk) {
604
                                // In the standalone filter, we only want the parameters (ctl,map) in the temporary .afs file, not the formulas
607
                                // In the standalone filter, we only want the parameters (ctl,map) in the temporary .afs file, not the formulas
605
                                // We do not need to care about the metadata, because the AFS does not touch the metadata anyway
608
                                // We do not need to care about the metadata, because the AFS does not touch the metadata anyway
606
                                for (i = 0; i < 4; i++) {
609
                                for (i = 0; i < 4; i++) {
607
                                        strcpy(bakexpr[i], gdata->parm.szFormula[i]);
610
                                        strcpy(bakexpr[i], gdata->parm.szFormula[i]);
608
                                }
611
                                }
609
                                restoreInternalState(tmpState);
612
                                restoreInternalState(tmpState);
610
                                for (i = 0; i < 4; i++) {
613
                                for (i = 0; i < 4; i++) {
611
                                        strcpy(gdata->parm.szFormula[i],bakexpr[i]);
614
                                        strcpy(gdata->parm.szFormula[i],bakexpr[i]);
612
                                }
615
                                }
613
                        }
616
                        }
614
 
617
 
615
                        return true;
618
                        return true;
616
                }
619
                }
617
        }
620
        }
618
 
621
 
619
        if( (bUninitializedParams = !(params && (LOADING_OK == readparams_afs_pff(params, false)))) ){
622
        if( (bUninitializedParams = !(params && (LOADING_OK == readparams_afs_pff(params, false)))) ){
620
                /* either the parameter handle was uninitialised,
623
                /* either the parameter handle was uninitialised,
621
                   or the parameter data couldn't be read; set default values */
624
                   or the parameter data couldn't be read; set default values */
622
 
625
 
623
                Boolean parmReadOk;
626
                Boolean parmReadOk;
624
 
627
 
625
                // see if saved parameters exist
628
                // see if saved parameters exist
626
                parmReadOk = (LOADING_OK == readPARMresource((HMODULE)hDllInstance));
629
                parmReadOk = (LOADING_OK == readPARMresource((HMODULE)hDllInstance));
627
                if (!parmReadOk) gdata->parm.standalone = false;
630
                if (!parmReadOk) gdata->parm.standalone = false;
628
                if (parmReadOk && (gdata->parm.cbSize != PARM_SIZE) && (gdata->parm.cbSize != PARM_SIZE_PREMIERE) && (gdata->parm.cbSize != PARM_SIG_MAC)) {
631
                if (parmReadOk && (gdata->parm.cbSize != PARM_SIZE) && (gdata->parm.cbSize != PARM_SIZE_PREMIERE) && (gdata->parm.cbSize != PARM_SIG_MAC)) {
629
                        parm_reset(true, true, true, true);
632
                        parm_reset(true, true, true, true);
630
                        if (gdata->obfusc) {
633
                        if (gdata->obfusc) {
631
                                simplealert_id(MSG_INCOMPATIBLE_OBFUSCATION_ID);
634
                                simplealert_id(MSG_INCOMPATIBLE_OBFUSCATION_ID);
632
                        }
635
                        }
633
                        else {
636
                        else {
634
                                simplealert_id(MSG_INVALID_PARAMETER_DATA_ID);
637
                                simplealert_id(MSG_INVALID_PARAMETER_DATA_ID);
635
                        }
638
                        }
636
                        return false;
639
                        return false;
637
                }
640
                }
638
 
641
 
639
                if(!gdata->parm.standalone){
642
                if(!gdata->parm.standalone){
640
                        // no saved settings (not standalone)
643
                        // no saved settings (not standalone)
641
                        parm_reset(true, true, true, true);
644
                        parm_reset(true, true, true, true);
642
                }
645
                }
643
        }
646
        }
644
 
647
 
645
        // let scripting system change parameters, if we're scripted;
648
        // let scripting system change parameters, if we're scripted;
646
        // user may want to force display of dialog during scripting playback
649
        // user may want to force display of dialog during scripting playback
647
        switch (ReadScriptParamsOnRead()) {
650
        switch (ReadScriptParamsOnRead()) {
648
        case SCR_SHOW_DIALOG:
651
        case SCR_SHOW_DIALOG:
649
                showdialog = true;
652
                showdialog = true;
650
                break;
653
                break;
651
        case SCR_HIDE_DIALOG:
654
        case SCR_HIDE_DIALOG:
652
                showdialog = false;
655
                showdialog = false;
653
                break;
656
                break;
654
        default:
657
        default:
655
        case SCR_NO_SCRIPT:
658
        case SCR_NO_SCRIPT:
656
                showdialog = bUninitializedParams;
659
                showdialog = bUninitializedParams;
657
                break;
660
                break;
658
        }
661
        }
659
 
662
 
660
        if (params) saveparams_afs_pff(params, false);
663
        if (params) saveparams_afs_pff(params, false);
661
 
664
 
662
        return showdialog;
665
        return showdialog;
663
}
666
}
664
 
667
 
665
Boolean host_preserves_parameters(void) {
668
Boolean host_preserves_parameters(void) {
666
        #ifdef DEBUG_SIMULATE_GIMP
669
        #ifdef DEBUG_SIMULATE_GIMP
667
        return false;
670
        return false;
668
        #endif
671
        #endif
669
 
672
 
670
        if (gpb->hostSig == HOSTSIG_GIMP) return false;
673
        if (gpb->hostSig == HOSTSIG_GIMP) return false;
671
        if (gpb->hostSig == HOSTSIG_IRFANVIEW) return false;
674
        if (gpb->hostSig == HOSTSIG_IRFANVIEW) return false;
672
 
675
 
673
        // We just assume the other hosts preserve the parameters
676
        // We just assume the other hosts preserve the parameters
674
        return true;
677
        return true;
675
}
678
}
676
 
679
 
677
int64_t maxspace(void){
680
int64_t maxspace(void){
678
        // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
681
        // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
679
 
682
 
680
        // Plugins that don't support MaxSpace64 shall set the field to zero; then we will use MaxSpace instead.
683
        // Plugins that don't support MaxSpace64 shall set the field to zero; then we will use MaxSpace instead.
681
        // Also check "gpb->bufferProcs->numBufferProcs" to see if 64 bit API is available
684
        // Also check "gpb->bufferProcs->numBufferProcs" to see if 64 bit API is available
682
        if ((gpb->bufferProcs->numBufferProcs >= 8) && (gpb->maxSpace64 > 0)) {
685
        if ((gpb->bufferProcs->numBufferProcs >= 8) && (gpb->maxSpace64 > 0)) {
683
                uint64_t maxSpace64 = gpb->maxSpace64;
686
                uint64_t maxSpace64 = gpb->maxSpace64;
684
 
687
 
685
                return maxSpace64;
688
                return maxSpace64;
686
        } else {
689
        } else {
687
                // Note: If maxSpace gets converted from Int32 to unsigned int, we can reach up to 4 GB RAM. However, after this, there will be a wrap to 0 GB again.
690
                // Note: If maxSpace gets converted from Int32 to unsigned int, we can reach up to 4 GB RAM. However, after this, there will be a wrap to 0 GB again.
688
                unsigned int maxSpace32 = (unsigned int) gpb->maxSpace;
691
                unsigned int maxSpace32 = (unsigned int) gpb->maxSpace;
689
                uint64_t maxSpace64 = maxSpace32;
692
                uint64_t maxSpace64 = maxSpace32;
690
 
693
 
691
                if (gpb->hostSig == HOSTSIG_IRFANVIEW) maxSpace64 *= 1024; // IrfanView is giving Kilobytes instead of Bytes
694
                if (gpb->hostSig == HOSTSIG_IRFANVIEW) maxSpace64 *= 1024; // IrfanView is giving Kilobytes instead of Bytes
692
                //if (gpb->hostSig == HOSTSIG_SERIF_PHOTOPLUS) maxSpace64 *= 1024; // TODO: Serif PhotoPlus also gives Kilobytes instead of bytes. But since it uses not a unique host signature, there is nothing we can do???
695
                //if (gpb->hostSig == HOSTSIG_SERIF_PHOTOPLUS) maxSpace64 *= 1024; // TODO: Serif PhotoPlus also gives Kilobytes instead of bytes. But since it uses not a unique host signature, there is nothing we can do???
693
 
696
 
694
                return maxSpace64;
697
                return maxSpace64;
695
        }
698
        }
696
}
699
}
697
 
700
 
698
Boolean maxspace_available(void) {
701
Boolean maxspace_available(void) {
699
        // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
702
        // Please see "Hosts.md" for details about the MaxSpace implementations of tested plugins
700
 
703
 
701
        // GIMP PSPI sets MaxSpace to hardcoded 100 MB
704
        // GIMP PSPI sets MaxSpace to hardcoded 100 MB
702
        if (gpb->hostSig == HOSTSIG_GIMP) return false;
705
        if (gpb->hostSig == HOSTSIG_GIMP) return false;
703
 
706
 
704
        // HOSTSIG_PAINT_NET sets MaxSpace to hardcoded 1 GB, see https://github.com/0xC0000054/PSFilterPdn/issues/5
707
        // HOSTSIG_PAINT_NET sets MaxSpace to hardcoded 1 GB, see https://github.com/0xC0000054/PSFilterPdn/issues/5
705
        // Comment by the host author "This was done to avoid any compatibility issues with plugins handling 2 GB - 1"
708
        // Comment by the host author "This was done to avoid any compatibility issues with plugins handling 2 GB - 1"
706
        if (gpb->hostSig == HOSTSIG_PAINT_NET) return false;
709
        if (gpb->hostSig == HOSTSIG_PAINT_NET) return false;
707
 
710
 
708
        return true;
711
        return true;
709
}
712
}
710
 
713
 
711
void DoPrepare(FilterRecordPtr pb){
714
void DoPrepare(FilterRecordPtr pb){
712
        int i;
715
        int i;
713
 
716
 
714
        for(i = 4; i--;){
717
        for(i = 4; i--;){
715
                tree[i] = NULL;
718
                tree[i] = NULL;
716
                err[i] = NULL;
719
                err[i] = NULL;
717
        }
720
        }
718
 
721
 
719
        // Commented out by DM, 18 Dec 2018:
722
        // Commented out by DM, 18 Dec 2018:
720
        // This code did not work on systems with 8 GB RAM:
723
        // This code did not work on systems with 8 GB RAM:
721
        /*
724
        /*
722
        long space = (pb->maxSpace*9)/10; // don't ask for more than 90% of available memory
725
        long space = (pb->maxSpace*9)/10; // don't ask for more than 90% of available memory
723
 
726
 
724
        maxSpace = 512L<<10; // this is a wild guess, actually
727
        maxSpace = 512L<<10; // this is a wild guess, actually
725
        if(maxSpace > space)
728
        if(maxSpace > space)
726
                        maxSpace = space;
729
                        maxSpace = space;
727
        pb->maxSpace = maxSpace;
730
        pb->maxSpace = maxSpace;
728
        */
731
        */
729
 
732
 
730
        // New variant:
733
        // New variant:
731
        if (maxspace_available()) {
734
        if (maxspace_available()) {
732
                // don't ask for more than 90% of available memory
735
                // don't ask for more than 90% of available memory
733
                int64 ninetyPercent = (int64)ceil((maxspace() / 10.) * 9);
736
                int64 ninetyPercent = (int64)ceil((maxspace() / 10.) * 9);
734
                if ((gpb->bufferProcs->numBufferProcs >= 8) && (gpb->maxSpace64 > 0)) {
737
                if ((gpb->bufferProcs->numBufferProcs >= 8) && (gpb->maxSpace64 > 0)) {
735
                        pb->maxSpace64 = ninetyPercent;
738
                        pb->maxSpace64 = ninetyPercent;
736
                }
739
                }
737
                if (ninetyPercent <= 0x7FFFFFFF) {
740
                if (ninetyPercent <= 0x7FFFFFFF) {
738
                        pb->maxSpace = (int32)ninetyPercent;
741
                        pb->maxSpace = (int32)ninetyPercent;
739
                }
742
                }
740
        }
743
        }
741
}
744
}
742
 
745
 
743
void RequestNext(FilterRecordPtr pb){
746
void RequestNext(FilterRecordPtr pb){
744
        /* Request next block of the image */
747
        /* Request next block of the image */
745
 
748
 
746
        pb->inLoPlane = pb->outLoPlane = 0;
749
        pb->inLoPlane = pb->outLoPlane = 0;
747
        pb->inHiPlane = pb->outHiPlane = nplanes-1;
750
        pb->inHiPlane = pb->outHiPlane = nplanes-1;
748
 
751
 
749
        if (HAS_BIG_DOC(pb)) {
752
        if (HAS_BIG_DOC(pb)) {
750
                // if any of the formulae involve random access to image pixels,
753
                // if any of the formulae involve random access to image pixels,
751
                // ask for the entire image
754
                // ask for the entire image
752
                if (needall) {
755
                if (needall) {
753
                        SETRECT(BIGDOC_IN_RECT(pb), 0, 0, BIGDOC_IMAGE_SIZE(pb).h, BIGDOC_IMAGE_SIZE(pb).v);
756
                        SETRECT(BIGDOC_IN_RECT(pb), 0, 0, BIGDOC_IMAGE_SIZE(pb).h, BIGDOC_IMAGE_SIZE(pb).v);
754
                } else {
757
                } else {
755
                        // TODO: This does not work with GIMP. So, if we are using GIMP, we should
758
                        // TODO: This does not work with GIMP. So, if we are using GIMP, we should
756
                        //       somehow always use "needall=true", and/or find out why this doesn't work
759
                        //       somehow always use "needall=true", and/or find out why this doesn't work
757
                        //       with GIMP.
760
                        //       with GIMP.
758
 
761
 
759
                        // otherwise, process the filtered area, by chunksize parts
762
                        // otherwise, process the filtered area, by chunksize parts
760
                        BIGDOC_IN_RECT(pb).left = BIGDOC_FILTER_RECT(pb).left;
763
                        BIGDOC_IN_RECT(pb).left = BIGDOC_FILTER_RECT(pb).left;
761
                        BIGDOC_IN_RECT(pb).right = BIGDOC_FILTER_RECT(pb).right;
764
                        BIGDOC_IN_RECT(pb).right = BIGDOC_FILTER_RECT(pb).right;
762
                        BIGDOC_IN_RECT(pb).top = (int32)toprow;
765
                        BIGDOC_IN_RECT(pb).top = (int32)toprow;
763
                        BIGDOC_IN_RECT(pb).bottom = (int32)MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
766
                        BIGDOC_IN_RECT(pb).bottom = (int32)MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
764
 
767
 
765
                        if (cnvused) {
768
                        if (cnvused) {
766
                                // cnv() needs one extra pixel in each direction
769
                                // cnv() needs one extra pixel in each direction
767
                                if (BIGDOC_IN_RECT(pb).left > 0)
770
                                if (BIGDOC_IN_RECT(pb).left > 0)
768
                                        --BIGDOC_IN_RECT(pb).left;
771
                                        --BIGDOC_IN_RECT(pb).left;
769
                                if (BIGDOC_IN_RECT(pb).right < BIGDOC_IMAGE_SIZE(pb).h)
772
                                if (BIGDOC_IN_RECT(pb).right < BIGDOC_IMAGE_SIZE(pb).h)
770
                                        ++BIGDOC_IN_RECT(pb).right;
773
                                        ++BIGDOC_IN_RECT(pb).right;
771
                                if (BIGDOC_IN_RECT(pb).top > 0)
774
                                if (BIGDOC_IN_RECT(pb).top > 0)
772
                                        --BIGDOC_IN_RECT(pb).top;
775
                                        --BIGDOC_IN_RECT(pb).top;
773
                                if (BIGDOC_IN_RECT(pb).bottom < BIGDOC_IMAGE_SIZE(pb).v)
776
                                if (BIGDOC_IN_RECT(pb).bottom < BIGDOC_IMAGE_SIZE(pb).v)
774
                                        ++BIGDOC_IN_RECT(pb).bottom;
777
                                        ++BIGDOC_IN_RECT(pb).bottom;
775
                        }
778
                        }
776
                }
779
                }
777
                BIGDOC_OUT_RECT(pb) = BIGDOC_FILTER_RECT(pb);
780
                BIGDOC_OUT_RECT(pb) = BIGDOC_FILTER_RECT(pb);
778
                /*
781
                /*
779
                {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
782
                {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
780
                                needall,
783
                                needall,
781
                                BIGDOC_IN_RECT(pb).left,BIGDOC_IN_RECT(pb).top,BIGDOC_IN_RECT(pb).right,BIGDOC_IN_RECT(pb).bottom,
784
                                BIGDOC_IN_RECT(pb).left,BIGDOC_IN_RECT(pb).top,BIGDOC_IN_RECT(pb).right,BIGDOC_IN_RECT(pb).bottom,
782
                                BIGDOC_FILTER_RECT(pb).left,BIGDOC_FILTER_RECT(pb).top,BIGDOC_FILTER_RECT(pb).right,BIGDOC_FILTER_RECT(pb).bottom);dbg(s);}
785
                                BIGDOC_FILTER_RECT(pb).left,BIGDOC_FILTER_RECT(pb).top,BIGDOC_FILTER_RECT(pb).right,BIGDOC_FILTER_RECT(pb).bottom);dbg(s);}
783
                */
786
                */
784
        } else {
787
        } else {
785
                // if any of the formulae involve random access to image pixels,
788
                // if any of the formulae involve random access to image pixels,
786
                // ask for the entire image
789
                // ask for the entire image
787
                if (needall) {
790
                if (needall) {
788
                        SETRECT(IN_RECT(pb), 0, 0, IMAGE_SIZE(pb).h, IMAGE_SIZE(pb).v);
791
                        SETRECT(IN_RECT(pb), 0, 0, IMAGE_SIZE(pb).h, IMAGE_SIZE(pb).v);
789
                }
792
                }
790
                else {
793
                else {
791
                        // TODO: This does not work with GIMP. So, if we are using GIMP, we should
794
                        // TODO: This does not work with GIMP. So, if we are using GIMP, we should
792
                        //       somehow always use "needall=true", and/or find out why this doesn't work
795
                        //       somehow always use "needall=true", and/or find out why this doesn't work
793
                        //       with GIMP.
796
                        //       with GIMP.
794
 
797
 
795
                        // otherwise, process the filtered area, by chunksize parts
798
                        // otherwise, process the filtered area, by chunksize parts
796
                        IN_RECT(pb).left = FILTER_RECT(pb).left;
799
                        IN_RECT(pb).left = FILTER_RECT(pb).left;
797
                        IN_RECT(pb).right = FILTER_RECT(pb).right;
800
                        IN_RECT(pb).right = FILTER_RECT(pb).right;
798
                        IN_RECT(pb).top = (int16)toprow;
801
                        IN_RECT(pb).top = (int16)toprow;
799
                        IN_RECT(pb).bottom = (int16)MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
802
                        IN_RECT(pb).bottom = (int16)MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
800
 
803
 
801
                        if (cnvused) {
804
                        if (cnvused) {
802
                                // cnv() needs one extra pixel in each direction
805
                                // cnv() needs one extra pixel in each direction
803
                                if (IN_RECT(pb).left > 0)
806
                                if (IN_RECT(pb).left > 0)
804
                                        --IN_RECT(pb).left;
807
                                        --IN_RECT(pb).left;
805
                                if (IN_RECT(pb).right < IMAGE_SIZE(pb).h)
808
                                if (IN_RECT(pb).right < IMAGE_SIZE(pb).h)
806
                                        ++IN_RECT(pb).right;
809
                                        ++IN_RECT(pb).right;
807
                                if (IN_RECT(pb).top > 0)
810
                                if (IN_RECT(pb).top > 0)
808
                                        --IN_RECT(pb).top;
811
                                        --IN_RECT(pb).top;
809
                                if (IN_RECT(pb).bottom < IMAGE_SIZE(pb).v)
812
                                if (IN_RECT(pb).bottom < IMAGE_SIZE(pb).v)
810
                                        ++IN_RECT(pb).bottom;
813
                                        ++IN_RECT(pb).bottom;
811
                        }
814
                        }
812
                }
815
                }
813
                OUT_RECT(pb) = FILTER_RECT(pb);
816
                OUT_RECT(pb) = FILTER_RECT(pb);
814
                /*
817
                /*
815
                {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
818
                {char s[0x100];sprintf(s,"RequestNext needall=%d inRect=(%d,%d,%d,%d) filterRect=(%d,%d,%d,%d)",
816
                                needall,
819
                                needall,
817
                                IN_RECT(pb).left,IN_RECT(pb).top,IN_RECT(pb).right,IN_RECT(pb).bottom,
820
                                IN_RECT(pb).left,IN_RECT(pb).top,IN_RECT(pb).right,IN_RECT(pb).bottom,
818
                                FILTER_RECT(pb).left,FILTER_RECT(pb).top,FILTER_RECT(pb).right,FILTER_RECT(pb).bottom);dbg(s);}
821
                                FILTER_RECT(pb).left,FILTER_RECT(pb).top,FILTER_RECT(pb).right,FILTER_RECT(pb).bottom);dbg(s);}
819
                */
822
                */
820
        }
823
        }
821
}
824
}
822
 
825
 
823
void DoStart(FilterRecordPtr pb){
826
void DoStart(FilterRecordPtr pb){
824
        /* Global variable "needall": if src() or rad() functions are used, random access to the image data is required,
827
        /* Global variable "needall": if src() or rad() functions are used, random access to the image data is required,
825
           so we must request the entire image in a single chunk, otherwise we will use chunksize "CHUNK_ROWS". */
828
           so we must request the entire image in a single chunk, otherwise we will use chunksize "CHUNK_ROWS". */
826
        if (HAS_BIG_DOC(pb)) {
829
        if (HAS_BIG_DOC(pb)) {
827
                chunksize = needall ? (BIGDOC_FILTER_RECT(pb).bottom - BIGDOC_FILTER_RECT(pb).top) : CHUNK_ROWS;
830
                chunksize = needall ? (BIGDOC_FILTER_RECT(pb).bottom - BIGDOC_FILTER_RECT(pb).top) : CHUNK_ROWS;
828
                toprow = BIGDOC_FILTER_RECT(pb).top;
831
                toprow = BIGDOC_FILTER_RECT(pb).top;
829
        } else {
832
        } else {
830
                chunksize = needall ? (FILTER_RECT(pb).bottom - FILTER_RECT(pb).top) : CHUNK_ROWS;
833
                chunksize = needall ? (FILTER_RECT(pb).bottom - FILTER_RECT(pb).top) : CHUNK_ROWS;
831
                toprow = FILTER_RECT(pb).top;
834
                toprow = FILTER_RECT(pb).top;
832
        }
835
        }
833
        RequestNext(pb);
836
        RequestNext(pb);
834
}
837
}
835
 
838
 
836
OSErr DoContinue(FilterRecordPtr pb){
839
OSErr DoContinue(FilterRecordPtr pb){
837
        OSErr e = noErr;
840
        OSErr e = noErr;
838
        long outoffset;
841
        long outoffset;
839
 
842
 
840
        if (HAS_BIG_DOC(pb)) {
843
        if (HAS_BIG_DOC(pb)) {
841
                VRect fr;
844
                VRect fr;
842
                if (needall) {
845
                if (needall) {
843
                        fr = BIGDOC_FILTER_RECT(pb);  // filter whole selection at once
846
                        fr = BIGDOC_FILTER_RECT(pb);  // filter whole selection at once
844
                } else if (cnvused) {
847
                } else if (cnvused) {
845
                        // we've requested one pixel extra all around
848
                        // we've requested one pixel extra all around
846
                        // (see RequestNext()), just for access purposes. But filter
849
                        // (see RequestNext()), just for access purposes. But filter
847
                        // original selection only.
850
                        // original selection only.
848
                        fr.left = BIGDOC_FILTER_RECT(pb).left;
851
                        fr.left = BIGDOC_FILTER_RECT(pb).left;
849
                        fr.right = BIGDOC_FILTER_RECT(pb).right;
852
                        fr.right = BIGDOC_FILTER_RECT(pb).right;
850
                        fr.top = toprow;
853
                        fr.top = toprow;
851
                        fr.bottom = MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
854
                        fr.bottom = MIN(toprow + chunksize, BIGDOC_FILTER_RECT(pb).bottom);
852
                } else {  // filter whatever portion we've been given
855
                } else {  // filter whatever portion we've been given
853
                        fr = BIGDOC_IN_RECT(pb);
856
                        fr = BIGDOC_IN_RECT(pb);
854
                }
857
                }
855
 
858
 
856
                outoffset = (long)pb->outRowBytes * (fr.top - BIGDOC_OUT_RECT(pb).top)
859
                outoffset = (long)pb->outRowBytes * (fr.top - BIGDOC_OUT_RECT(pb).top)
857
                        + (long)nplanes * (fr.left - BIGDOC_OUT_RECT(pb).left);
860
                        + (long)nplanes * (fr.left - BIGDOC_OUT_RECT(pb).left);
858
 
861
 
859
                if (!(e = process_scaled_bigdoc(pb, true, fr, fr,
862
                if (!(e = process_scaled_bigdoc(pb, true, fr, fr,
860
                        (Ptr)pb->outData + outoffset, pb->outRowBytes, 1.)))
863
                        (Ptr)pb->outData + outoffset, pb->outRowBytes, 1.)))
861
                {
864
                {
862
                        toprow += chunksize;
865
                        toprow += chunksize;
863
                        if (toprow < BIGDOC_FILTER_RECT(pb).bottom)
866
                        if (toprow < BIGDOC_FILTER_RECT(pb).bottom)
864
                                RequestNext(pb);
867
                                RequestNext(pb);
865
                        else {
868
                        else {
866
                                SETRECT(BIGDOC_IN_RECT(pb), 0, 0, 0, 0);
869
                                SETRECT(BIGDOC_IN_RECT(pb), 0, 0, 0, 0);
867
                                BIGDOC_OUT_RECT(pb) = BIGDOC_MASK_RECT(pb) = BIGDOC_IN_RECT(pb);
870
                                BIGDOC_OUT_RECT(pb) = BIGDOC_MASK_RECT(pb) = BIGDOC_IN_RECT(pb);
868
                        }
871
                        }
869
                }
872
                }
870
        } else {
873
        } else {
871
                Rect fr;
874
                Rect fr;
872
                if (needall) {
875
                if (needall) {
873
                        fr = FILTER_RECT(pb);  // filter whole selection at once
876
                        fr = FILTER_RECT(pb);  // filter whole selection at once
874
                } else if (cnvused) {
877
                } else if (cnvused) {
875
                        // we've requested one pixel extra all around
878
                        // we've requested one pixel extra all around
876
                        // (see RequestNext()), just for access purposes. But filter
879
                        // (see RequestNext()), just for access purposes. But filter
877
                        // original selection only.
880
                        // original selection only.
878
                        fr.left = FILTER_RECT(pb).left;
881
                        fr.left = FILTER_RECT(pb).left;
879
                        fr.right = FILTER_RECT(pb).right;
882
                        fr.right = FILTER_RECT(pb).right;
880
                        fr.top = toprow;
883
                        fr.top = toprow;
881
                        fr.bottom = MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
884
                        fr.bottom = MIN(toprow + chunksize, FILTER_RECT(pb).bottom);
882
                } else {  // filter whatever portion we've been given
885
                } else {  // filter whatever portion we've been given
883
                        fr = IN_RECT(pb);
886
                        fr = IN_RECT(pb);
884
                }
887
                }
885
 
888
 
886
                outoffset = (long)pb->outRowBytes*(fr.top - OUT_RECT(pb).top)
889
                outoffset = (long)pb->outRowBytes*(fr.top - OUT_RECT(pb).top)
887
                        + (long)nplanes*(fr.left - OUT_RECT(pb).left);
890
                        + (long)nplanes*(fr.left - OUT_RECT(pb).left);
888
 
891
 
889
                if(!(e = process_scaled_olddoc(pb, true, fr, fr,
892
                if(!(e = process_scaled_olddoc(pb, true, fr, fr,
890
                        (Ptr)pb->outData+outoffset, pb->outRowBytes, 1.)))
893
                        (Ptr)pb->outData+outoffset, pb->outRowBytes, 1.)))
891
                {
894
                {
892
                        toprow += chunksize;
895
                        toprow += chunksize;
893
                        if(toprow < FILTER_RECT(pb).bottom)
896
                        if(toprow < FILTER_RECT(pb).bottom)
894
                                RequestNext(pb);
897
                                RequestNext(pb);
895
                        else{
898
                        else{
896
                                SETRECT(IN_RECT(pb),0,0,0,0);
899
                                SETRECT(IN_RECT(pb),0,0,0,0);
897
                                OUT_RECT(pb) = MASK_RECT(pb) = IN_RECT(pb);
900
                                OUT_RECT(pb) = MASK_RECT(pb) = IN_RECT(pb);
898
                        }
901
                        }
899
                }
902
                }
900
        }
903
        }
901
        return e;
904
        return e;
902
}
905
}
903
 
906
 
904
void DoFinish(FilterRecordPtr pb){
907
void DoFinish(FilterRecordPtr pb){
905
        int i;
908
        int i;
906
 
909
 
907
        UNREFERENCED_PARAMETER(pb);
910
        UNREFERENCED_PARAMETER(pb);
908
 
911
 
909
        WriteScriptParamsOnRead();
912
        WriteScriptParamsOnRead();
910
 
913
 
911
        for(i = 4; i--;){
914
        for(i = 4; i--;){
912
                freetree(tree[i]);
915
                freetree(tree[i]);
913
        }
916
        }
914
}
917
}
915
 
918
 
916
InternalState saveInternalState(void) {
919
InternalState saveInternalState(void) {
917
        InternalState ret;
920
        InternalState ret;
918
        ret.bak_obfusc = gdata->obfusc;
921
        ret.bak_obfusc = gdata->obfusc;
919
        memcpy(&ret.bak_parm, &gdata->parm, sizeof(PARM_T));
922
        memcpy(&ret.bak_parm, &gdata->parm, sizeof(PARM_T));
920
 
923
 
921
        return ret;
924
        return ret;
922
}
925
}
923
 
926
 
924
void restoreInternalState(InternalState state) {
927
void restoreInternalState(InternalState state) {
925
        gdata->obfusc = state.bak_obfusc;
928
        gdata->obfusc = state.bak_obfusc;
926
        memcpy(&gdata->parm, &state.bak_parm, sizeof(PARM_T));
929
        memcpy(&gdata->parm, &state.bak_parm, sizeof(PARM_T));
927
}
930
}
928
 
931