Subversion Repositories filter_foundry

Rev

Rev 444 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
113 dmarschall 1
/*
2
    This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
536 daniel-mar 3
    Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.net
206 daniel-mar 4
    Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
113 dmarschall 5
 
6
    This program is free software; you can redistribute it and/or modify
7
    it under the terms of the GNU General Public License as published by
8
    the Free Software Foundation; either version 2 of the License, or
9
    (at your option) any later version.
10
 
11
    This program is distributed in the hope that it will be useful,
12
    but WITHOUT ANY WARRANTY; without even the implied warranty of
13
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
    GNU General Public License for more details.
15
 
16
    You should have received a copy of the GNU General Public License
17
    along with this program; if not, write to the Free Software
18
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19
*/
20
 
21
#include "ff.h"
22
 
23
#include <windows.h>
24
#include <stdbool.h>
25
#include <stdio.h>
26
 
27
// This unit modifies the VersionInfo resource structure of a PE file.
28
// Entries can be modified or deleted (not added).
29
// Reference code by "RbMm" at StackOverflow:
30
// https://stackoverflow.com/questions/53916682/programmatically-change-versioninfo-of-a-foreign-dll
31
// Translated from C++ to C by Daniel Marschall and extended/modified to fit Filter Foundry's requirements.
32
 
33
typedef struct RsrcHeader {
34
        WORD  wLength;
35
        WORD  wValueLength;
36
        WORD  wType;
37
        WCHAR szKey[];
38
} RsrcHeader;
39
 
40
typedef struct RsrcNode {
41
        struct RsrcNode *first;
42
        struct RsrcNode *next;
43
        PCWSTR name;
44
        const void *pvValue;
45
        ULONG cbValue;
46
        WORD wValueLength;
47
        WORD wType;
48
} RsrcNode;
49
 
50
typedef struct EnumVerData {
51
        HANDLE hUpdate;
52
        BOOL fDiscard;
53
        PCWSTR changes;
54
} EnumVerData;
55
 
56
RsrcNode* NewNode() {
57
        RsrcNode* node = (RsrcNode*)calloc(1,sizeof(RsrcNode));
58
        return node;
59
}
60
 
61
bool NodeIsStringValue(RsrcNode* node) {
62
        return node->wType;
63
}
64
 
65
bool NodeParseResourse(RsrcNode* node, PVOID buf, ULONG size, ULONG* pLength) {
66
        WORD wType;
67
        ULONG wValueLength;
68
        ULONG wLength;
69
        ULONG cbValue;
70
 
71
        union {
72
                PVOID       pv;
73
                RsrcHeader* ph;
74
                ULONG_PTR   up;
75
                PCWSTR      sz;
76
        } x;
77
 
78
        x.pv = buf;
79
 
80
        if (size < sizeof(RsrcHeader) || (x.up & 3))
81
        {
82
                return false;
83
        }
84
 
85
        wType = x.ph->wType;
86
        wValueLength = x.ph->wValueLength, wLength = x.ph->wLength;
87
        cbValue = 0;
88
 
89
        switch (wType)
90
        {
91
                case 1:
92
                        cbValue = wValueLength * sizeof(WCHAR);
93
                        break;
94
                case 0:
95
                        cbValue = wValueLength;
96
                        break;
97
                default:
98
                        return false;
99
        }
100
 
101
        *pLength = wLength;
102
 
103
        if (wLength > size || wLength < sizeof(RsrcHeader) || cbValue >= (wLength -= sizeof(RsrcHeader)))
104
        {
105
                return false;
106
        }
107
 
108
        wLength -= cbValue;
109
 
110
        x.sz = x.ph->szKey, node->name = x.sz;
111
 
112
        do
113
        {
114
                if (wLength < sizeof(WCHAR))
115
                {
116
                        return false;
117
                }
118
 
119
                wLength -= sizeof(WCHAR);
120
        } while (*x.sz++);
121
 
122
        if (x.up & 3)
123
        {
124
                if (wLength < 2)
125
                {
126
                        return false;
127
                }
128
                x.up += 2, wLength -= 2;
129
        }
130
 
131
        node->wType = wType, node->wValueLength = (WORD)wValueLength, node->cbValue = cbValue, node->pvValue = x.pv;
132
 
133
        if (wValueLength && wType)
134
        {
135
                if (x.sz[wValueLength - 1])
136
                {
137
                        return false;
138
                }
139
        }
140
 
141
        if (wLength)
142
        {
143
                x.up += wValueLength;
144
 
145
                do
146
                {
147
                        RsrcNode* lnode;
148
 
149
                        if (x.up & 3)
150
                        {
151
                                if (wLength < 2)
152
                                {
153
                                        return false;
154
                                }
155
 
156
                                x.up += 2;
157
 
158
                                if (!(wLength -= 2))
159
                                {
160
                                        break;
161
                                }
162
                        }
163
 
164
                        if (lnode = NewNode())
165
                        {
166
                                lnode->next = node->first, node->first = lnode;
167
 
168
                                if (NodeParseResourse(lnode, x.ph, wLength, &size))
169
                                {
170
                                        continue;
171
                                }
172
                        }
173
 
174
                        return false;
175
 
176
                } while (x.up += size, wLength -= size);
177
        }
178
 
179
        return true;
180
}
181
 
182
const void* NodeGetValue(RsrcNode* node, ULONG* cb) {
183
        *cb = node->cbValue;
184
        return node->pvValue;
185
}
186
 
187
bool NodeToBeDeleted(RsrcNode* node) {
188
        return ((NodeIsStringValue(node)) && (!wcscmp((PCWSTR)node->pvValue, L"\b")));
189
}
190
 
191
void NodeSetValue(RsrcNode* node, const void* pv, ULONG cb) {
192
        node->pvValue = pv, node->cbValue = cb;
193
        node->wValueLength = (WORD)(node->wType ? cb / sizeof(WCHAR) : cb);
194
}
195
 
196
void FreeNode(RsrcNode* node) {
197
        RsrcNode* next;
198
 
199
        if (next = node->first)
200
        {
201
                do
202
                {
203
                        RsrcNode* cur = next;
204
                        next = next->next;
205
                        FreeNode(cur);
206
                } while (next);
207
        }
208
 
209
        free(node);
210
}
211
 
212
RsrcNode* NodeFind(RsrcNode* node, const PCWSTR strings[], ULONG n) {
213
        PCWSTR str;
214
        RsrcNode* next;
215
 
216
        str = *strings++;
217
 
218
        if (!str || !wcscmp(str, node->name))
219
        {
220
                if (!--n)
221
                {
222
                        return node;
223
                }
224
 
225
                if (next = node->first)
226
                {
227
                        do
228
                        {
229
                                RsrcNode* p;
230
                                if (p = NodeFind(next, strings, n))
231
                                {
232
                                        return p;
233
                                }
234
                        } while (next = next->next);
235
                }
236
        }
237
 
238
        return NULL;
239
}
240
 
241
ULONG NodeGetSize(RsrcNode* node) {
242
        ULONG size;
243
        RsrcNode* next;
244
 
245
        size = sizeof(RsrcHeader) + (1 + (ULONG)wcslen(node->name)) * sizeof(WCHAR);
246
 
247
        if (node->cbValue)
248
        {
249
                size = ((size + 3) & ~3) + node->cbValue;
250
        }
251
 
252
        if (next = node->first)
253
        {
254
                do
255
                {
256
                        size = ((size + 3) & ~3) + NodeGetSize(next);
257
                } while (next = next->next);
258
        }
259
 
260
        return size;
261
}
262
 
263
PVOID NodeStore(RsrcNode* node, PVOID buf, ULONG* pcb) {
264
        ULONG size;
265
        ULONG cb;
266
        RsrcNode* next;
267
 
268
        union {
269
                RsrcHeader* ph;
270
                ULONG_PTR   up;
271
                PVOID       pv;
272
        } x;
273
 
274
        x.pv = buf;
275
 
276
        x.ph->wType = node->wType;
277
        x.ph->wValueLength = node->wValueLength;
278
 
279
        size = (1 + (ULONG)wcslen(node->name)) * sizeof(WCHAR);
280
 
281
        memcpy(x.ph->szKey, node->name, size);
282
 
283
        x.up += (size += sizeof(RsrcHeader));
284
 
285
        if (node->cbValue)
286
        {
287
                x.up = (x.up + 3) & ~3;
288
                memcpy(x.pv, node->pvValue, node->cbValue);
289
                x.up += node->cbValue;
290
                size = ((size + 3) & ~3) + node->cbValue;
291
        }
292
 
293
        if (next = node->first)
294
        {
295
                do
296
                {
297
                        if (!NodeToBeDeleted(next)) {
298
                                x.up = (x.up + 3) & ~3;
299
                                x.pv = NodeStore(next, x.pv, &cb);
300
                                size = ((size + 3) & ~3) + cb;
301
                        }
302
                } while (next = next->next);
303
        }
304
 
305
        ((RsrcHeader*)buf)->wLength = (WORD)size;
306
 
307
        *pcb = size;
308
 
309
        return x.pv;
310
}
311
 
416 daniel-mar 312
// Format of argument "PCWSTR changes" is "<name>\0<value>\0<name>\0<value>\0....."
313
// You can CHANGE values for any given name
314
// You can DELETE entries by setting the value to "\b" (0x08 backspace character)
315
// You cannot (yet) ADD entries.
113 dmarschall 316
BOOL UpdateVersionRaw(PVOID pvVersion, ULONG cbVersion, PVOID* pvNewVersion, ULONG* cbNewVersion, PCWSTR changes) {
317
        BOOL fOk = FALSE;
318
        BOOL changesMade = FALSE;
319
        RsrcNode* node;
320
 
321
        if (node = NewNode())
322
        {
323
                // Parse VersionInfo (pvVersion) into a hierarchical structure with head "RsrcNode node"
324
                if (NodeParseResourse(node, pvVersion, cbVersion, &cbVersion))
325
                {
326
                        // Loop through all elements of "PCWSTR changes" and apply the changes to the hierarchical structure
327
                        while (1)
328
                        {
329
                                PCWSTR change;
330
                                PCWSTR newValue;
331
                                PCWSTR str[4];
332
                                RsrcNode *p;
333
 
334
                                change = changes;
335
                                if (wcslen(changes) == 0) break;
336
                                changes += (wcslen(changes)+1);
337
 
338
                                newValue = changes;
339
                                changes += (wcslen(changes)+1);
340
 
341
                                str[0] = L"VS_VERSION_INFO";
342
                                str[1] = L"StringFileInfo";
343
                                str[2] = NULL;
344
                                str[3] = change;
345
 
346
                                if (p = NodeFind(node, str, 4))
347
                                {
348
                                        if (NodeIsStringValue(p))
349
                                        {
350
                                                ULONG cb;
351
                                                PCWSTR prevValue = (PCWSTR)NodeGetValue(p, &cb);
352
 
353
                                                //printf("Change %S: %S -> %S\n", change, prevValue, newValue);
354
 
355
                                                if (cb != (wcslen(newValue)+1)*sizeof(wchar_t) || (wcscmp(prevValue, newValue)))
356
                                                {
185 dmarschall 357
                                                        NodeSetValue(p, newValue, (ULONG)((wcslen(newValue)+1)*sizeof(wchar_t)));
113 dmarschall 358
                                                        changesMade = TRUE;
359
                                                }
360
                                        }
361
                                }
362
                        }
363
 
364
                        // Write back the hierarchical structure into the raw data pvVersion
365
                        if (changesMade) {
366
                                cbVersion = NodeGetSize(node);
367
 
368
                                if (pvVersion = LocalAlloc(0, cbVersion))
369
                                {
370
                                        NodeStore(node, pvVersion, cbNewVersion);
371
                                        *pvNewVersion = pvVersion;
372
                                        fOk = TRUE;
373
                                }
374
                        }
375
                }
376
                FreeNode(node);
377
        }
378
 
379
        return fOk;
380
}
381
 
444 daniel-mar 382
/*
383
BOOL CALLBACK EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, EnumVerData* Ctx) {
113 dmarschall 384
        HRSRC hResInfo;
385
        HGLOBAL hg;
386
        ULONG size;
387
        PVOID pv;
388
 
389
        if (hResInfo = FindResourceEx(hModule, lpszType, lpszName, wIDLanguage))
390
        {
391
                if (hg = LoadResource(hModule, hResInfo))
392
                {
393
                        if (size = SizeofResource(hModule, hResInfo))
394
                        {
395
                                if (pv = LockResource(hg))
396
                                {
397
                                        if (UpdateVersionRaw(pv, size, &pv, &size, Ctx->changes))
398
                                        {
162 dmarschall 399
                                                if (_UpdateResource(Ctx->hUpdate, lpszType, lpszName, wIDLanguage, pv, size))
113 dmarschall 400
                                                {
401
                                                        Ctx->fDiscard = FALSE;
402
                                                }
403
 
404
                                                LocalFree(pv);
405
                                        }
406
                                }
407
                        }
408
                }
409
        }
410
 
411
        return TRUE;
412
}
444 daniel-mar 413
*/
113 dmarschall 414
 
415
/*
416
Usage example:
417
 
418
int main(int argc, char** argv) {
192 daniel-mar 419
        // Set CompanyName to "Contoso Ltd."
420
        // Delete LegalCopyright
421
        // Set OriginalFilename to "Test.dll"
422
        static const PCWSTR changes = L"Foo\0Bar\0CompanyName\0Contoso Ltd.\0LegalCopyright\0\b\0OriginalFilename\0Test.dll\0";
113 dmarschall 423
 
192 daniel-mar 424
        UpdateVersionInfoByFilename("C:\\Test.dll", changes);
113 dmarschall 425
        return 0;
426
}
427
*/