home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 March / CMCD0304.ISO / Software / Freeware / Programare / nullsoft / nsis20.exe / Source / util.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-01-30  |  12.0 KB  |  393 lines

  1. #include "Platform.h"
  2. #include <stdio.h>
  3. #include <stdarg.h>
  4. #include <conio.h>
  5. #include "exedata.h"
  6. #include "exehead/fileform.h"
  7. #include "util.h"
  8. #include "strlist.h"
  9.  
  10. int g_dopause=0;
  11. extern int g_display_errors;
  12. extern FILE *g_output;
  13.  
  14. void dopause(void)
  15. {
  16.   if (g_dopause)
  17.   {
  18.     if (g_display_errors) fprintf(g_output,"MakeNSIS done - hit enter to close...");
  19.     fflush(stdout);
  20.     int a;
  21.     while ((a=_getch()) != '\r' && a != 27/*esc*/);
  22.   }
  23. }
  24.  
  25. // Returns 0 if everything is OK
  26. // Returns -1 if can't find the file
  27. // Returns -2 if the file is an invalid bitmap
  28. // Returns -3 if the size doesn't match
  29. // Returns -4 if the bpp doesn't match
  30. int update_bitmap(CResourceEditor* re, WORD id, char* filename, int width/*=0*/, int height/*=0*/, int maxbpp/*=0*/) {
  31.   FILE *f = fopen(filename, "rb");
  32.   if (!f) return -1;
  33.  
  34.   if (fgetc(f) != 'B' || fgetc(f) != 'M') {
  35.     fclose(f);
  36.     return -2;
  37.   }
  38.  
  39.   if (width != 0) {
  40.     LONG biWidth;
  41.     fseek(f, 18, SEEK_SET); // Seek to the width member of the header
  42.     fread(&biWidth, sizeof(LONG), 1, f);
  43.     if (width != biWidth) {
  44.       fclose(f);
  45.       return -3;
  46.     }
  47.   }
  48.  
  49.   if (height != 0) {
  50.     LONG biHeight;
  51.     fseek(f, 22, SEEK_SET); // Seek to the height member of the header
  52.     fread(&biHeight, sizeof(LONG), 1, f);
  53.     // Bitmap height can be negative too...
  54.     if (height != abs(biHeight)) {
  55.       fclose(f);
  56.       return -3;
  57.     }
  58.   }
  59.  
  60.   if (maxbpp != 0) {
  61.     WORD biBitCount;
  62.     fseek(f, 28, SEEK_SET); // Seek to the height member of the header
  63.     fread(&biBitCount, sizeof(WORD), 1, f);
  64.     if (biBitCount > maxbpp) {
  65.       fclose(f);
  66.       return -4;
  67.     }
  68.   }
  69.  
  70.   DWORD dwSize;
  71.   fseek(f, 2, SEEK_SET);
  72.   fread(&dwSize, sizeof(DWORD), 1, f);
  73.   dwSize -= 14;
  74.  
  75.   unsigned char* bitmap = (unsigned char*)malloc(dwSize);
  76.   if (!bitmap) throw bad_alloc();
  77.  
  78.   fseek(f, 14, SEEK_SET);
  79.   if (fread(bitmap, 1, dwSize, f) != dwSize) {
  80.     fclose(f);
  81.     return -2;
  82.   }
  83.   fclose(f);
  84.  
  85.   re->UpdateResource(RT_BITMAP, MAKEINTRESOURCE(id), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), bitmap, dwSize);
  86.  
  87.   free(bitmap);
  88.  
  89.   return 0;
  90. }
  91.  
  92. // Added by Amir Szekely 8th July 2002
  93. // Icon editing structures
  94. typedef struct {
  95.   WORD wReserved;
  96.   WORD wIsIcon;
  97.   WORD wCount;
  98. } IconGroupHeader;
  99.  
  100. typedef struct {
  101.   BYTE bWidth;
  102.   BYTE bHeight;
  103.   BYTE bPaletteEntries;
  104.   BYTE bReserved;
  105.   WORD wPlanes;
  106.   WORD wBitsPerPixel;
  107.   DWORD dwRawSize;
  108.   DWORD dwImageOffset;
  109. } FileIconGroupEntry;
  110.  
  111. typedef struct {
  112.   BYTE bWidth;
  113.   BYTE bHeight;
  114.   BYTE bPaletteEntries;
  115.   BYTE bReserved;
  116.   WORD wPlanes;
  117.   WORD wBitsPerPixel;
  118.   DWORD dwRawSize;
  119.   WORD wRsrcId;
  120. } RsrcIconGroupEntry;
  121.  
  122. #define SIZEOF_RSRC_ICON_GROUP_ENTRY 14
  123.  
  124. // Added by Amir Szekely 8th July 2002
  125. // replace_icon, must get an initialized resource editor
  126. // return values:
  127. //   0  - All OK
  128. //   -1 - Bad icon file
  129. int replace_icon(CResourceEditor* re, WORD wIconId, char* filename)
  130. {
  131.   FILE* f = fopen(filename, "rb");
  132.   if (!f) return -1;
  133.  
  134.   IconGroupHeader igh;
  135.   fread(&igh, sizeof(IconGroupHeader), 1, f);
  136.  
  137.   if (igh.wIsIcon != 1 && igh.wReserved != 0) return -1;
  138.  
  139.   BYTE* rsrcIconGroup = (BYTE*)malloc(sizeof(IconGroupHeader) + igh.wCount*SIZEOF_RSRC_ICON_GROUP_ENTRY);
  140.   if (!rsrcIconGroup) throw bad_alloc();
  141.  
  142.   CopyMemory(rsrcIconGroup, &igh, sizeof(IconGroupHeader));
  143.  
  144.   RsrcIconGroupEntry* ige = (RsrcIconGroupEntry*)(rsrcIconGroup + sizeof(IconGroupHeader));
  145.  
  146.   int i = 1;
  147.  
  148.   // Delete old icons
  149.   while (re->UpdateResource(RT_ICON, MAKEINTRESOURCE(i++), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), 0, 0));
  150.  
  151.   int iNewIconSize = 0;
  152.  
  153.   for (i = 0; i < igh.wCount; i++) {
  154.     fread(ige, sizeof(FileIconGroupEntry)-sizeof(DWORD), 1, f);
  155.     ige->wRsrcId = i+1;
  156.  
  157.     DWORD dwOffset;
  158.     fread(&dwOffset, sizeof(DWORD), 1, f);
  159.  
  160.     fpos_t pos;
  161.     fgetpos(f, &pos);
  162.  
  163.     if (fseek(f, dwOffset, SEEK_SET)) {
  164.       free(rsrcIconGroup);
  165.       return -1;
  166.     }
  167.     BYTE* iconData = (BYTE*)malloc(ige->dwRawSize);
  168.     if (!iconData) {
  169.       free(rsrcIconGroup);
  170.       throw bad_alloc();
  171.     }
  172.     fread(iconData, sizeof(BYTE), ige->dwRawSize, f);
  173.     re->UpdateResource(RT_ICON, MAKEINTRESOURCE(i+1), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), iconData, ige->dwRawSize);
  174.     free(iconData);
  175.  
  176.     fsetpos(f, &pos);
  177.  
  178.     // Every icon entry should be 8 aligned
  179.     iNewIconSize += ((ige->dwRawSize%8 == 0) ? ige->dwRawSize : ige->dwRawSize - (ige->dwRawSize%8) + 8);
  180.  
  181.     // Seems like the compiler refuses to increase the pointer by just 14.
  182.     // If you'll replace this line by ige++ you will get unwanted results.
  183.     ige = (RsrcIconGroupEntry*)((BYTE*)ige + SIZEOF_RSRC_ICON_GROUP_ENTRY);
  184.   }
  185.  
  186.   fclose(f);
  187.  
  188.   re->UpdateResource(RT_GROUP_ICON, MAKEINTRESOURCE(wIconId), MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), rsrcIconGroup, sizeof(IconGroupHeader) + igh.wCount*SIZEOF_RSRC_ICON_GROUP_ENTRY);
  189.  
  190.   free(rsrcIconGroup);
  191.  
  192.   icondata_size = iNewIconSize;
  193.  
  194.   return 0;
  195. }
  196.  
  197. // Added by Amir Szekely 8th July 2002
  198. #ifdef NSIS_CONFIG_UNINSTALL_SUPPORT
  199. // returns the data of the uninstaller icon that should replace the installer icon data
  200. // return values:
  201. //   0  - Bad icon file
  202. //   Anything else - Pointer to the uninstaller icon data
  203. unsigned char* generate_uninstall_icon_data(char* filename)
  204. {
  205.   int i;
  206.  
  207.   FILE* f = fopen(filename, "rb");
  208.   if (!f) return 0;
  209.  
  210.   IconGroupHeader igh;
  211.   if (!fread(&igh, sizeof(IconGroupHeader), 1, f)) return 0;
  212.  
  213.   if (igh.wIsIcon != 1 && igh.wReserved != 0) return 0;
  214.  
  215.   int iNewIconSize = 0;
  216.   FileIconGroupEntry ige;
  217.  
  218.   DWORD* offsets = (DWORD*)malloc(sizeof(DWORD)*igh.wCount);
  219.   DWORD* rawSizes = (DWORD*)malloc(sizeof(DWORD)*igh.wCount);
  220.   if (!offsets || !rawSizes) throw bad_alloc();
  221.  
  222.   for (i = 0; i < igh.wCount; i++) {
  223.     if (!fread(&ige, sizeof(FileIconGroupEntry), 1, f)) return 0;
  224.     offsets[i] = ige.dwImageOffset;
  225.     rawSizes[i] = ige.dwRawSize;
  226.     iNewIconSize += ige.dwRawSize;
  227.   }
  228.  
  229.   // Before each icon come two DWORDs, one for size and the other for offset (set later)
  230.   // The last size is 0, no offset
  231.   iNewIconSize += sizeof(DWORD)*(1 + igh.wCount*2);
  232.  
  233.   BYTE* pbUninstIcon = (BYTE*)malloc(iNewIconSize);
  234.   if (!pbUninstIcon) throw bad_alloc();
  235.  
  236.   BYTE* seeker = pbUninstIcon;
  237.  
  238.   for (i = 0; i < igh.wCount; i++) {
  239.     *(DWORD*)seeker = rawSizes[i];
  240.     seeker += sizeof(DWORD);
  241.     *(DWORD*)seeker = 0;
  242.     seeker += sizeof(DWORD);
  243.     fseek(f, offsets[i], SEEK_SET);
  244.     fread(seeker, 1, rawSizes[i], f);
  245.     seeker += rawSizes[i];
  246.   }
  247.  
  248.   // This is how we know there are no more icons (size = 0)
  249.   *(DWORD*)seeker = 0;
  250.  
  251.   free(offsets);
  252.   free(rawSizes);
  253.  
  254.   unicondata_size = iNewIconSize;
  255.  
  256.   return pbUninstIcon;
  257. }
  258.  
  259. // Added by Amir Szekely 11th July 2002
  260. #define MY_ASSERT(x, y) if (x) {if (g_display_errors) fprintf(g_output,"\nError finding icon resources: %s -- failing!\n", y);return 0;}
  261.  
  262. int find_in_dir(PRESOURCE_DIRECTORY rd, WORD id) {
  263.   for (int i = rd->Header.NumberOfNamedEntries; i < rd->Header.NumberOfNamedEntries + rd->Header.NumberOfIdEntries; i++) {
  264.     if (rd->Entries[i].Id == id) {
  265.       return i;
  266.     }
  267.   }
  268.   return -1;
  269. }
  270.  
  271. // Fill the array of icons for uninstall with their offsets
  272. // Returns 0 if failed, anything else is icon_offset.
  273. int generate_unicons_offsets(unsigned char* exeHeader, unsigned char* uninstIconData) {
  274.   int i;
  275.  
  276.   MY_ASSERT(PIMAGE_DOS_HEADER(exeHeader)->e_magic != IMAGE_DOS_SIGNATURE, "invalid dos header");
  277.  
  278.   PIMAGE_NT_HEADERS ntHeaders = PIMAGE_NT_HEADERS(exeHeader + PIMAGE_DOS_HEADER(exeHeader)->e_lfanew);
  279.  
  280.   MY_ASSERT(ntHeaders->Signature != IMAGE_NT_SIGNATURE, "invalid nt headers");
  281.  
  282.   DWORD dwResourceSectionVA = ntHeaders->OptionalHeader.DataDirectory[IMAGE_DIRECTORY_ENTRY_RESOURCE].VirtualAddress;
  283.   PIMAGE_SECTION_HEADER sectionHeadersArray = IMAGE_FIRST_SECTION(ntHeaders);
  284.  
  285.   for (i = 0; i < ntHeaders->FileHeader.NumberOfSections; i++)
  286.     if (dwResourceSectionVA == sectionHeadersArray[i].VirtualAddress)
  287.       break;
  288.  
  289.   MY_ASSERT(i == ntHeaders->FileHeader.NumberOfSections, "can't find resource section");
  290.  
  291.   PRESOURCE_DIRECTORY rdRoot = PRESOURCE_DIRECTORY(exeHeader + sectionHeadersArray[i].PointerToRawData);
  292.  
  293.   int iNextSection;
  294.   if (i == ntHeaders->FileHeader.NumberOfSections - 1)
  295.     iNextSection = (int)ntHeaders->OptionalHeader.SizeOfImage;
  296.   else
  297.     iNextSection = (int)sectionHeadersArray[i+1].PointerToRawData;
  298.  
  299.   MY_ASSERT((int)rdRoot - (int)exeHeader > iNextSection, "corrupted EXE - invalid pointer");
  300.  
  301.   int idx = find_in_dir(rdRoot, WORD(RT_ICON));
  302.   MY_ASSERT(idx == -1, "no icons?!");
  303.   MY_ASSERT(!rdRoot->Entries[idx].DataIsDirectory, "bad resource directory");
  304.  
  305.   PRESOURCE_DIRECTORY rdIcons = PRESOURCE_DIRECTORY(rdRoot->Entries[idx].OffsetToDirectory + DWORD(rdRoot));
  306.  
  307.   MY_ASSERT((int)rdIcons - (int)exeHeader > iNextSection, "corrupted EXE - invalid pointer");
  308.  
  309.   MY_ASSERT(rdIcons->Header.NumberOfIdEntries == 0, "no icons found");
  310.  
  311.   for (i = 0; i < rdIcons->Header.NumberOfIdEntries; i++) { // Icons dir can't have named entries
  312.     MY_ASSERT(!rdIcons->Entries[i].DataIsDirectory, "bad resource directory");
  313.     PRESOURCE_DIRECTORY rd = PRESOURCE_DIRECTORY(rdIcons->Entries[i].OffsetToDirectory + DWORD(rdRoot));
  314.     
  315.     MY_ASSERT((int)rd - (int)exeHeader > iNextSection, "corrupted EXE - invalid pointer");
  316.     MY_ASSERT(rd->Entries[0].DataIsDirectory, "bad resource directory");
  317.     
  318.     PIMAGE_RESOURCE_DATA_ENTRY rde = PIMAGE_RESOURCE_DATA_ENTRY(rd->Entries[0].OffsetToData + DWORD(rdRoot));
  319.  
  320.     MY_ASSERT((int)rde - (int)exeHeader > iNextSection, "corrupted EXE - invalid pointer");
  321.  
  322.     // find icon to replace
  323.     LPBYTE seeker = uninstIconData;
  324.     while (*seeker) {
  325.       DWORD dwSize = *(DWORD*)seeker;
  326.       seeker += sizeof(DWORD);
  327.       DWORD dwOffset = *(DWORD*)seeker;
  328.       // if we haven't set the offset yet and the size is the same, it's a match
  329.       if (!dwOffset && dwSize == rde->Size)
  330.         break;
  331.  
  332.       seeker += dwSize + sizeof(DWORD);
  333.  
  334.       // reached the end of the list and no match
  335.       MY_ASSERT(!*seeker, "installer, uninstaller icon size mismatch - see the Icon instruction's documentation for more information");
  336.     }
  337.  
  338.     // Set offset
  339.     *(LPDWORD) seeker = rde->OffsetToData + DWORD(rdRoot) - dwResourceSectionVA - DWORD(exeHeader);
  340.  
  341.     MY_ASSERT(*(int*)seeker > iNextSection || *(int*)seeker < (int)rdRoot - (int)exeHeader, "invalid data offset - icon resource probably compressed");
  342.   }
  343.  
  344.   LPBYTE seeker = uninstIconData;
  345.   while (*seeker) {
  346.     DWORD dwSize = *(DWORD*)seeker;
  347.     seeker += sizeof(DWORD);
  348.     DWORD dwOffset = *(DWORD*)seeker;
  349.     seeker += sizeof(DWORD);
  350.     // offset isn't set which means we found no match for this one
  351.     MY_ASSERT(!dwOffset, "number of icons doesn't match");
  352.     seeker += dwSize;
  353.   }
  354.  
  355.   return PIMAGE_RESOURCE_DATA_ENTRY(PRESOURCE_DIRECTORY(rdIcons->Entries[0].OffsetToDirectory + DWORD(rdRoot))->Entries[0].OffsetToData + DWORD(rdRoot))->OffsetToData + DWORD(rdRoot) - dwResourceSectionVA - DWORD(exeHeader);
  356. }
  357. #endif // NSIS_CONFIG_UNINSTALL_SUPPORT
  358.  
  359. #ifdef NSIS_CONFIG_VISIBLE_SUPPORT
  360. BYTE* get_dlg(HINSTANCE hUIFile, WORD dlgId, char* filename) {
  361.   HRSRC hUIRes = FindResource(hUIFile, MAKEINTRESOURCE(dlgId), RT_DIALOG);
  362.   if (!hUIRes) {
  363.     if (g_display_errors) fprintf(g_output, "Error: \"%s\" doesn't contain a dialog with the ID %u!\n", filename, dlgId);
  364.     return 0;
  365.   }
  366.   HGLOBAL hUIMem = LoadResource(hUIFile, hUIRes);
  367.   if (!hUIMem) {
  368.     if (g_display_errors) fprintf(g_output, "Error: Can't load a dialog from \"%s\"!\n", filename);
  369.     return 0;
  370.   }
  371.   BYTE* pbUIData = (BYTE*)LockResource(hUIMem);
  372.   if (!pbUIData) {
  373.     if (g_display_errors) fprintf(g_output, "Error: Can't lock resource from \"%s\"!\n", filename);
  374.     return 0;
  375.   }
  376.   return pbUIData;
  377. }
  378. #endif //NSIS_CONFIG_VISIBLE_SUPPORT
  379.  
  380. void *operator new(size_t size) {
  381.   void *p = malloc(size);
  382.   if (!p)
  383.     throw bad_alloc();
  384.   return p;
  385. }
  386.  
  387. void operator delete(void *p) {
  388.   if (p) free(p);
  389. }
  390.  
  391. void operator delete [](void *p) {
  392.   if (p) free(p);
  393. }