Subversion Repositories filter_foundry

Rev

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