Subversion Repositories filter_foundry

Rev

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

  1. /*
  2.     This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
  3.     Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.net
  4.     Copyright (C) 2018-2021 Daniel Marschall, ViaThinkSoft
  5.  
  6.     This program is free software; you can redistribute it and/or modify
  7.     it under the terms of the GNU General Public License as published by
  8.     the Free Software Foundation; either version 2 of the License, or
  9.     (at your option) any later version.
  10.  
  11.     This program is distributed in the hope that it will be useful,
  12.     but WITHOUT ANY WARRANTY; without even the implied warranty of
  13.     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14.     GNU General Public License for more details.
  15.  
  16.     You should have received a copy of the GNU General Public License
  17.     along with this program; if not, write to the Free Software
  18.     Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19. */
  20.  
  21. #include "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.  
  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.
  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.                                                 {
  357.                                                         NodeSetValue(p, newValue, (ULONG)((wcslen(newValue)+1)*sizeof(wchar_t)));
  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.  
  382. /*
  383. BOOL CALLBACK EnumResLangProc(HMODULE hModule, LPCTSTR lpszType, LPCTSTR lpszName, WORD wIDLanguage, EnumVerData* Ctx) {
  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.                                         {
  399.                                                 if (_UpdateResource(Ctx->hUpdate, lpszType, lpszName, wIDLanguage, pv, size))
  400.                                                 {
  401.                                                         Ctx->fDiscard = FALSE;
  402.                                                 }
  403.  
  404.                                                 LocalFree(pv);
  405.                                         }
  406.                                 }
  407.                         }
  408.                 }
  409.         }
  410.  
  411.         return TRUE;
  412. }
  413. */
  414.  
  415. /*
  416. Usage example:
  417.  
  418. int main(int argc, char** argv) {
  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";
  423.  
  424.         UpdateVersionInfoByFilename("C:\\Test.dll", changes);
  425.         return 0;
  426. }
  427. */
  428.