Subversion Repositories filter_foundry

Rev

Rev 311 | Rev 455 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | RSS feed

  1. /*
  2.         This file is part of "Filter Foundry", a filter plugin for Adobe Photoshop
  3.         Copyright (C) 2003-2009 Toby Thain, toby@telegraphics.com.au
  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. #ifndef _CRT_SECURE_NO_WARNINGS
  22. #define _CRT_SECURE_NO_WARNINGS
  23. #endif
  24.  
  25. #include <iostream>
  26. #include <windows.h>
  27.  
  28. bool update_pe_timestamp(LPCTSTR filename, time_t timestamp) {
  29.         size_t peoffset;
  30.         FILE* fptr;
  31.  
  32.         fptr = _wfopen(filename, L"rb+");
  33.         if (fptr == NULL) return false;
  34.  
  35.         fseek(fptr, 0x3C, SEEK_SET);
  36.         fread(&peoffset, sizeof(peoffset), 1, fptr);
  37.  
  38.         fseek(fptr, (long)peoffset + 8, SEEK_SET);
  39.         fwrite(&timestamp, sizeof(time_t), 1, fptr);
  40.  
  41.         fclose(fptr);
  42.  
  43.         return true;
  44. }
  45.  
  46. //DOS .EXE header
  47. struct image_dos_header
  48. {
  49.         uint16_t e_magic;                     // Magic number
  50.         uint16_t e_cblp;                      // Bytes on last page of file
  51.         uint16_t e_cp;                        // Pages in file
  52.         uint16_t e_crlc;                      // Relocations
  53.         uint16_t e_cparhdr;                   // Size of header in paragraphs
  54.         uint16_t e_minalloc;                  // Minimum extra paragraphs needed
  55.         uint16_t e_maxalloc;                  // Maximum extra paragraphs needed
  56.         uint16_t e_ss;                        // Initial (relative) SS value
  57.         uint16_t e_sp;                        // Initial SP value
  58.         uint16_t e_csum;                      // Checksum
  59.         uint16_t e_ip;                        // Initial IP value
  60.         uint16_t e_cs;                        // Initial (relative) CS value
  61.         uint16_t e_lfarlc;                    // File address of relocation table
  62.         uint16_t e_ovno;                      // Overlay number
  63.         uint16_t e_res[4];                    // Reserved words
  64.         uint16_t e_oemid;                     // OEM identifier (for e_oeminfo)
  65.         uint16_t e_oeminfo;                   // OEM information; e_oemid specific
  66.         uint16_t e_res2[10];                  // Reserved words
  67.         int32_t  e_lfanew;                    // File address of new exe header
  68. };
  69.  
  70. struct image_file_header
  71. {
  72.         uint16_t Machine;
  73.         uint16_t NumberOfSections;
  74.         uint32_t TimeDateStamp;
  75.         uint32_t PointerToSymbolTable;
  76.         uint32_t NumberOfSymbols;
  77.         uint16_t SizeOfOptionalHeader;
  78.         uint16_t Characteristics;
  79. };
  80.  
  81. uint32_t calculate_checksum(LPCTSTR filename) {
  82.         //Calculate checksum of image
  83.         // Taken from "PE Bliss" Cross-Platform Portable Executable C++ Library
  84.         // https://github.com/mrexodia/portable-executable-library/blob/master/pe_lib/pe_checksum.cpp
  85.         // Converted from C++ to C by Daniel Marschall
  86.  
  87.         FILE* fptr;
  88.         unsigned long long checksum = 0;
  89.         struct image_dos_header header;
  90.         size_t filesize;
  91.         unsigned long long top;
  92.         unsigned long pe_checksum_pos;
  93.         static const unsigned long checksum_pos_in_optional_headers = 64;
  94.         size_t i;
  95.  
  96.         fptr = _wfopen(filename, L"rb");
  97.         if (fptr == NULL) return 0x00000000;
  98.  
  99.         //Read DOS header
  100.         fseek(fptr, 0, SEEK_SET);
  101.         fread(&header, sizeof(struct image_dos_header), 1, fptr);
  102.  
  103.         //Calculate PE checksum
  104.         fseek(fptr, 0, SEEK_SET);
  105.         top = 0xFFFFFFFF;
  106.         top++;
  107.  
  108.         //"CheckSum" field position in optional PE headers - it's always 64 for PE and PE+
  109.         //Calculate real PE headers "CheckSum" field position
  110.         //Sum is safe here
  111.         pe_checksum_pos = header.e_lfanew + sizeof(struct image_file_header) + sizeof(uint32_t) + checksum_pos_in_optional_headers;
  112.  
  113.         //Calculate checksum for each byte of file
  114.         fseek(fptr, 0L, SEEK_END);
  115.         filesize = ftell(fptr);
  116.         fseek(fptr, 0L, SEEK_SET);
  117.         for (i = 0; i < filesize; i += 4)
  118.         {
  119.                 unsigned long dw = 0;
  120.  
  121.                 //Read DWORD from file
  122.                 fread(&dw, sizeof(dw), 1, fptr);
  123.                 //Skip "CheckSum" DWORD
  124.                 if (i == pe_checksum_pos)
  125.                         continue;
  126.  
  127.                 //Calculate checksum
  128.                 checksum = (checksum & 0xffffffff) + dw + (checksum >> 32);
  129.                 if (checksum > top)
  130.                         checksum = (checksum & 0xffffffff) + (checksum >> 32);
  131.         }
  132.  
  133.         //Finish checksum
  134.         checksum = (checksum & 0xffff) + (checksum >> 16);
  135.         checksum = (checksum)+(checksum >> 16);
  136.         checksum = checksum & 0xffff;
  137.  
  138.         checksum += (unsigned long)(filesize);
  139.  
  140.         fclose(fptr);
  141.  
  142.         //Return checksum
  143.         return (uint32_t)checksum;
  144. }
  145.  
  146. bool repair_pe_checksum(LPCTSTR filename) {
  147.         size_t peoffset;
  148.         FILE* fptr;
  149.  
  150.         uint32_t checksum = calculate_checksum(filename);
  151.         //if (checksum == 0x00000000) return false;
  152.  
  153.         fptr = _wfopen(filename, L"rb+");
  154.         if (fptr == NULL) return false;
  155.  
  156.         fseek(fptr, 0x3C, SEEK_SET);
  157.         fread(&peoffset, sizeof(peoffset), 1, fptr);
  158.  
  159.         fseek(fptr, (long)peoffset + 88, SEEK_SET);
  160.         fwrite(&checksum, sizeof(uint32_t), 1, fptr);
  161.  
  162.         fclose(fptr);
  163.  
  164.         return true;
  165. }
  166.  
  167. bool removeFromFile(LPCTSTR pluginfile, LPCTSTR lpType, LPCTSTR lpName, WORD wLanguage) {
  168.         bool bSuccessful = false;
  169.  
  170.         HANDLE hRes = BeginUpdateResource(pluginfile, false);
  171.         if (hRes != NULL) {
  172.                 if (UpdateResource(hRes, lpType, lpName, wLanguage, NULL, 0)) {
  173.                         if (EndUpdateResource(hRes, false)) {
  174.                                 bSuccessful = true;
  175.                         }
  176.                 }
  177.                 else {
  178.                         EndUpdateResource(hRes, true);
  179.                 }
  180.         }
  181.  
  182.         return bSuccessful;
  183. }
  184.  
  185. bool addToFile(LPCTSTR pluginfile, LPCTSTR otherfile, LPCTSTR lpType, LPCTSTR lpName, WORD wLanguage) {
  186.         HANDLE hFile;
  187.         DWORD dwFileSize, dwBytesRead;
  188.         LPBYTE lpBuffer;
  189.         bool bSuccessful = false;
  190.  
  191.         hFile = CreateFile(otherfile, GENERIC_READ,
  192.                 0,
  193.                 NULL,
  194.                 OPEN_EXISTING,
  195.                 FILE_ATTRIBUTE_NORMAL,
  196.                 NULL);
  197.  
  198.         if (INVALID_HANDLE_VALUE != hFile)
  199.         {
  200.                 dwFileSize = GetFileSize(hFile, NULL);
  201.  
  202.                 //lpBuffer = new BYTE[dwFileSize];
  203.                 lpBuffer = (LPBYTE)malloc(dwFileSize);
  204.  
  205.                 if (ReadFile(hFile, lpBuffer, dwFileSize, &dwBytesRead, NULL) != FALSE)
  206.                 {
  207.                         HANDLE hRes = BeginUpdateResource(pluginfile, false);
  208.                         if (hRes != NULL) {
  209.                                 if (UpdateResource(hRes, lpType, lpName, wLanguage, lpBuffer, dwFileSize)) {
  210.                                         if (EndUpdateResource(hRes, false)) {
  211.                                                 bSuccessful = true;
  212.                                         }
  213.                                 }
  214.                                 else {
  215.                                         EndUpdateResource(hRes, true);
  216.                                 }
  217.                         }
  218.                 }
  219.  
  220.                 //delete[] lpBuffer;
  221.                 free(lpBuffer);
  222.  
  223.                 CloseHandle(hFile);
  224.         }
  225.  
  226.         return bSuccessful;
  227. }
  228.  
  229. int main()
  230. {
  231.         LPCTSTR lpTemplateType = L"TPLT";
  232.         LPCTSTR lpName32Plugin = (LPCTSTR)1032;
  233.         LPCTSTR lpName64Plugin = (LPCTSTR)1064;
  234.         LPCTSTR lpName32Version = (LPCTSTR)3032;
  235.         LPCTSTR lpName64Version = (LPCTSTR)3064;
  236.         LPCTSTR lpName32Pipl = (LPCTSTR)16032;
  237.         LPCTSTR lpName64Pipl = (LPCTSTR)16064;
  238.         WORD wLanguageEnUs = MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US); // 1033 en-US
  239.         WORD wLanguageNeutral = MAKELANGID(LANG_NEUTRAL, SUBLANG_NEUTRAL); // 0 Neutral
  240.  
  241.         LPCTSTR file32in = L"in\\FilterFoundry.8bf";
  242.         LPCTSTR file64in = L"in\\FilterFoundry64.8bf";
  243.         LPCTSTR file32out = L"out\\FilterFoundry.8bf";
  244.         LPCTSTR file64out = L"out\\FilterFoundry64.8bf";
  245.         LPCTSTR file32tmp = L"FilterFoundry.tmp";
  246.         LPCTSTR file64tmp = L"FilterFoundry64.tmp";
  247.  
  248.         // 1a. Copy 32 "IN" to 32 "TMP", and 64 "IN" to 64 "TMP"
  249.         {
  250.                 if (!CopyFile(file32in, file32tmp, false)) {
  251.                         DeleteFile(file32out);
  252.                         DeleteFile(file64out);
  253.                         printf("Error: Copyfile 32in > 32tmp\n");
  254.                         return 1;
  255.                 }
  256.  
  257.                 if (!CopyFile(file64in, file64tmp, false)) {
  258.                         DeleteFile(file32out);
  259.                         DeleteFile(file64out);
  260.                         printf("Error: Copyfile 64in > 64tmp\n");
  261.                         return 1;
  262.                 }
  263.         }
  264.  
  265.         // 1b. Copy 32 "IN" to 32 "OUT", and 64 "IN" to 64 "OUT" (will be edited later)
  266.         {
  267.                 if (!CopyFile(file32in, file32out, false)) {
  268.                         DeleteFile(file32out);
  269.                         DeleteFile(file64out);
  270.                         printf("Error: Copyfile 32in > 32out\n");
  271.                         return 1;
  272.                 }
  273.  
  274.                 if (!CopyFile(file64in, file64out, false)) {
  275.                         DeleteFile(file32out);
  276.                         DeleteFile(file64out);
  277.                         printf("Error: Copyfile 64in > 64out\n");
  278.                         return 1;
  279.                 }
  280.         }
  281.  
  282.         // 2. Remove any template residues at 32/64 "TMP", since they are only used for building
  283.         //    "TMP" is our "standalone plugin skelleton"
  284.         // TODO: Also remove build dialogs, cursors and icons (like done in make_win.c)?
  285.         {
  286.                 // Remove TPLT 1 (Manifest template)
  287.                 removeFromFile(file32tmp, lpTemplateType, MAKEINTRESOURCE(1), wLanguageNeutral);
  288.                 removeFromFile(file64tmp, lpTemplateType, MAKEINTRESOURCE(1), wLanguageNeutral);
  289.  
  290.                 // Remove TPLT 1032/1064 (8BF included)
  291.                 removeFromFile(file32tmp, lpTemplateType, lpName32Plugin, wLanguageEnUs);
  292.                 removeFromFile(file32tmp, lpTemplateType, lpName64Plugin, wLanguageEnUs);
  293.                 removeFromFile(file64tmp, lpTemplateType, lpName32Plugin, wLanguageEnUs);
  294.                 removeFromFile(file64tmp, lpTemplateType, lpName64Plugin, wLanguageEnUs);
  295.  
  296.                 // Remove TPLT 3032/3064 (Versioninfo included)
  297.                 removeFromFile(file32tmp, lpTemplateType, lpName32Version, wLanguageEnUs);
  298.                 removeFromFile(file32tmp, lpTemplateType, lpName64Version, wLanguageEnUs);
  299.                 removeFromFile(file64tmp, lpTemplateType, lpName32Version, wLanguageEnUs);
  300.                 removeFromFile(file64tmp, lpTemplateType, lpName64Version, wLanguageEnUs);
  301.  
  302.                 // Remove TPLT 16032/16064 (PIPL template)
  303.                 removeFromFile(file32tmp, lpTemplateType, lpName32Pipl, wLanguageNeutral);
  304.                 removeFromFile(file32tmp, lpTemplateType, lpName64Pipl, wLanguageNeutral);
  305.                 removeFromFile(file64tmp, lpTemplateType, lpName32Pipl, wLanguageNeutral);
  306.                 removeFromFile(file64tmp, lpTemplateType, lpName64Pipl, wLanguageNeutral);
  307.         }
  308.  
  309.         // 3. Update timestamp of 32/64 "TMP"
  310.         {
  311.                 if (!update_pe_timestamp(file32tmp, time(0))) {
  312.                         DeleteFile(file32out);
  313.                         DeleteFile(file64out);
  314.                         printf("Error: Update TMP timestamp 32\n");
  315.                         return 1;
  316.                 }
  317.  
  318.                 if (!update_pe_timestamp(file64tmp, time(0))) {
  319.                         DeleteFile(file32out);
  320.                         DeleteFile(file64out);
  321.                         printf("Error: Update TMP timestamp 64\n");
  322.                         return 1;
  323.                 }
  324.         }
  325.  
  326.         // 4. Repair checksums of 32/64 "TMP"
  327.         {
  328.                 if (!repair_pe_checksum(file32tmp)) {
  329.                         DeleteFile(file32out);
  330.                         DeleteFile(file64out);
  331.                         printf("Error: Repair TMP checksum 32\n");
  332.                         return 1;
  333.                 }
  334.                 if (!repair_pe_checksum(file64tmp)) {
  335.                         DeleteFile(file32out);
  336.                         DeleteFile(file64out);
  337.                         printf("Error: Repair TMP checksum 64\n");
  338.                         return 1;
  339.                 }
  340.         }
  341.  
  342.         // 6. Add 32/64 "TMP" to 64/32 "OUT" ("criss-cross")
  343.         {
  344.                 if (!addToFile(file32out, file32tmp, lpTemplateType, lpName32Plugin, wLanguageEnUs)) {
  345.                         DeleteFile(file32out);
  346.                         DeleteFile(file64out);
  347.                         printf("Error: Add 32 to 32\n");
  348.                         return 1;
  349.                 }
  350.                 if (!addToFile(file32out, file64tmp, lpTemplateType, lpName64Plugin, wLanguageEnUs)) {
  351.                         DeleteFile(file32out);
  352.                         DeleteFile(file64out);
  353.                         printf("Error: Add 64 to 32\n");
  354.                         return 1;
  355.                 }
  356.  
  357.                 if (!addToFile(file64out, file32tmp, lpTemplateType, lpName32Plugin, wLanguageEnUs)) {
  358.                         DeleteFile(file32out);
  359.                         DeleteFile(file64out);
  360.                         printf("Error: Add 32 to 64\n");
  361.                         return 1;
  362.                 }
  363.  
  364.                 if (!addToFile(file64out, file64tmp, lpTemplateType, lpName64Plugin, wLanguageEnUs)) {
  365.                         DeleteFile(file32out);
  366.                         DeleteFile(file64out);
  367.                         printf("Error: Add 64 to 64\n");
  368.                         return 1;
  369.                 }
  370.         }
  371.  
  372.         // 7a. Read Version Info from 32 bit "TMP", and copy it to 32/64 "OUT" template
  373.         {
  374.                 HMODULE lib = LoadLibraryEx(file32tmp, NULL, LOAD_LIBRARY_AS_DATAFILE);
  375.                 if (!lib) {
  376.                         printf("Loadlib failed at versioninfo TPLT 32");
  377.                         return 1;
  378.                 }
  379.                 HRSRC resinfo = FindResource(lib, MAKEINTRESOURCE(1), RT_VERSION);
  380.                 if (!resinfo) {
  381.                         printf("FindResource failed at versioninfo TPLT 32");
  382.                         return 1;
  383.                 }
  384.                 size_t cbVersionInfo = SizeofResource(lib, resinfo);
  385.                 HGLOBAL hvinfo = LoadResource(lib, resinfo);
  386.                 if (!hvinfo) {
  387.                         printf("LoadResource failed at versioninfo TPLT 32");
  388.                         return 1;
  389.                 }
  390.                 char* vinfo = (char*)LockResource(hvinfo);
  391.                 char* vinfocpy = (char*)malloc(cbVersionInfo);
  392.                 if (vinfocpy == NULL) return 1;
  393.                 memcpy(vinfocpy, vinfo, cbVersionInfo);
  394.                 UnlockResource(hvinfo);
  395.                 FreeLibrary(lib);
  396.  
  397.                 // Write Version info to TPLT Resource of 32 bit "OUT"
  398.  
  399.                 HANDLE hupd = BeginUpdateResource(file32out, false);
  400.                 UpdateResource(hupd, TEXT("TPLT"), lpName32Version, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), vinfocpy, cbVersionInfo);
  401.                 EndUpdateResource(hupd, false);
  402.  
  403.                 // Write Version info to TPLT Resource of 64 bit "OUT"
  404.  
  405.                 hupd = BeginUpdateResource(file64out, false);
  406.                 UpdateResource(hupd, TEXT("TPLT"), lpName32Version, MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), vinfocpy, cbVersionInfo);
  407.                 EndUpdateResource(hupd, false);
  408.  
  409.                 // Free memory
  410.  
  411.                 free(vinfocpy);
  412.         }
  413.  
  414.         // 7b. Read Version Info from 64 bit "TMP", and copy it to 32/64 "OUT" template
  415.         {
  416.                 HMODULE lib = LoadLibraryEx(file64tmp, NULL, LOAD_LIBRARY_AS_DATAFILE);
  417.                 if (!lib) {
  418.                         printf("Loadlib failed at versioninfo TPLT 64");
  419.                         return 1;
  420.                 }
  421.                 HRSRC resinfo = FindResource(lib, MAKEINTRESOURCE(1), RT_VERSION);
  422.                 if (!resinfo) {
  423.                         printf("FindResource failed at versioninfo TPLT 64");
  424.                         return 1;
  425.                 }
  426.                 size_t cbVersionInfo = SizeofResource(lib, resinfo);
  427.                 HGLOBAL hvinfo = LoadResource(lib, resinfo);
  428.                 if (!hvinfo) {
  429.                         printf("LoadResource failed at versioninfo TPLT 64");
  430.                         return 1;
  431.                 }
  432.                 char* vinfo = (char*)LockResource(hvinfo);
  433.                 char* vinfocpy = (char*)malloc(cbVersionInfo);
  434.                 if (vinfocpy == NULL) return 1;
  435.                 memcpy(vinfocpy, vinfo, cbVersionInfo);
  436.                 UnlockResource(hvinfo);
  437.                 FreeLibrary(lib);
  438.  
  439.                 // Write Version info to TPLT Resource of 32 bit "OUT"
  440.  
  441.                 HANDLE hupd = BeginUpdateResource(file32out, false);
  442.                 UpdateResource(hupd, TEXT("TPLT"), lpName64Version, 1033, vinfocpy, cbVersionInfo);
  443.                 EndUpdateResource(hupd, false);
  444.  
  445.                 // Write Version info to TPLT Resource of 64 bit "OUT"
  446.  
  447.                 hupd = BeginUpdateResource(file64out, false);
  448.                 UpdateResource(hupd, TEXT("TPLT"), lpName64Version, 1033, vinfocpy, cbVersionInfo);
  449.                 EndUpdateResource(hupd, false);
  450.  
  451.                 // Free memory
  452.  
  453.                 free(vinfocpy);
  454.         }
  455.  
  456.         // 8. Delete 32/64 "TMP"
  457.         {
  458.                 DeleteFile(file32tmp);
  459.                 DeleteFile(file64tmp);
  460.         }
  461.  
  462.         // 9. Update timestamp of 32/64 "OUT"
  463.         {
  464.                 if (!update_pe_timestamp(file32out, time(0))) {
  465.                         DeleteFile(file32out);
  466.                         DeleteFile(file64out);
  467.                         printf("Error: Update OUT timestamp 32\n");
  468.                         return 1;
  469.                 }
  470.  
  471.                 if (!update_pe_timestamp(file64out, time(0))) {
  472.                         DeleteFile(file32out);
  473.                         DeleteFile(file64out);
  474.                         printf("Error: Update OUT timestamp 64\n");
  475.                         return 1;
  476.                 }
  477.         }
  478.  
  479.         // 10. Repair checksums of 32/64 "OUT"
  480.         {
  481.                 if (!repair_pe_checksum(file32out)) {
  482.                         DeleteFile(file32out);
  483.                         DeleteFile(file64out);
  484.                         printf("Error: Repair OUT checksum 32\n");
  485.                         return 1;
  486.                 }
  487.                 if (!repair_pe_checksum(file64out)) {
  488.                         DeleteFile(file32out);
  489.                         DeleteFile(file64out);
  490.                         printf("Error: Repair OUT checksum 64\n");
  491.                         return 1;
  492.                 }
  493.         }
  494.  
  495.         // 11. All done!
  496.  
  497.         printf("All OK!\n");
  498.         return 0;
  499. }
  500.